%% fileadv.tex
%%
-%% Copyright (C) 2000-2012 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2014 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
\label{sec:file_noblocking}
Abbiamo visto in sez.~\ref{sec:sig_gen_beha}, affrontando la suddivisione fra
-\textit{fast} e \textit{slow} system call,\index{system~call~lente} che in
-certi casi le funzioni di I/O possono bloccarsi indefinitamente.\footnote{si
- ricordi però che questo può accadere solo per le pipe, i socket ed alcuni
- file di dispositivo\index{file!di~dispositivo}; sui file normali le funzioni
- di lettura e scrittura ritornano sempre subito.} Ad esempio le operazioni
-di lettura possono bloccarsi quando non ci sono dati disponibili sul
-descrittore su cui si sta operando.
+\textit{fast} e \textit{slow} \textit{system call},\index{system~call~lente}
+che in certi casi le funzioni di I/O possono bloccarsi
+indefinitamente.\footnote{si ricordi però che questo può accadere solo per le
+ pipe, i socket ed alcuni file di dispositivo\index{file!di~dispositivo}; sui
+ file normali le funzioni di lettura e scrittura ritornano sempre subito.}
+Ad esempio le operazioni di lettura possono bloccarsi quando non ci sono dati
+disponibili sul descrittore su cui si sta operando.
Questo comportamento causa uno dei problemi più comuni che ci si trova ad
affrontare nelle operazioni di I/O, che si verifica quando si deve operare con
file descriptor, in un ciclo in cui si ripete l'accesso fintanto che esso non
viene garantito. Ovviamente questa tecnica, detta \itindex{polling}
\textit{polling}, è estremamente inefficiente: si tiene costantemente
-impiegata la CPU solo per eseguire in continuazione delle system call che
-nella gran parte dei casi falliranno.
+impiegata la CPU solo per eseguire in continuazione delle \textit{system call}
+che nella gran parte dei casi falliranno.
Per superare questo problema è stato introdotto il concetto di \textit{I/O
multiplexing}, una nuova modalità di operazioni che consente di tenere sotto
La funzione è sostanzialmente identica a \func{select}, solo che usa una
struttura \struct{timespec} (vedi fig.~\ref{fig:sys_timespec_struct}) per
indicare con maggiore precisione il timeout e non ne aggiorna il valore in
-caso di interruzione.\footnote{in realtà la system call di Linux aggiorna il
- valore al tempo rimanente, ma la funzione fornita dalle \acr{glibc} modifica
- questo comportamento passando alla system call una variabile locale, in modo
- da mantenere l'aderenza allo standard POSIX che richiede che il valore di
- \param{timeout} non sia modificato.} Inoltre prende un argomento aggiuntivo
-\param{sigmask} che è il puntatore ad una \index{maschera~dei~segnali}
-maschera di segnali (si veda sez.~\ref{sec:sig_sigmask}). La maschera
-corrente viene sostituita da questa immediatamente prima di eseguire l'attesa,
-e ripristinata al ritorno della funzione.
+caso di interruzione.\footnote{in realtà la \textit{system call} di Linux
+ aggiorna il valore al tempo rimanente, ma la funzione fornita dalle
+ \acr{glibc} modifica questo comportamento passando alla \textit{system call}
+ una variabile locale, in modo da mantenere l'aderenza allo standard POSIX
+ che richiede che il valore di \param{timeout} non sia modificato.} Inoltre
+prende un argomento aggiuntivo \param{sigmask} che è il puntatore ad una
+\index{maschera~dei~segnali} maschera di segnali (si veda
+sez.~\ref{sec:sig_sigmask}). La maschera corrente viene sostituita da questa
+immediatamente prima di eseguire l'attesa, e ripristinata al ritorno della
+funzione.
L'uso di \param{sigmask} è stato introdotto allo scopo di prevenire possibili
\textit{race condition} \itindex{race~condition} quando ci si deve porre in
Per questo è stata introdotta \func{pselect} che attraverso l'argomento
\param{sigmask} permette di riabilitare la ricezione il segnale
contestualmente all'esecuzione della funzione,\footnote{in Linux però, fino al
- kernel 2.6.16, non era presente la relativa system call, e la funzione era
- implementata nelle \acr{glibc} attraverso \func{select} (vedi \texttt{man
- select\_tut}) per cui la possibilità di \itindex{race~condition}
- \textit{race condition} permaneva; in tale situazione si può ricorrere ad una
- soluzione alternativa, chiamata \itindex{self-pipe trick} \textit{self-pipe
- trick}, che consiste nell'aprire una pipe (vedi sez.~\ref{sec:ipc_pipes})
- ed usare \func{select} sul capo in lettura della stessa; si può indicare
- l'arrivo di un segnale scrivendo sul capo in scrittura all'interno del
- gestore dello stesso; in questo modo anche se il segnale va perso prima
- della chiamata di \func{select} questa lo riconoscerà comunque dalla
- presenza di dati sulla pipe.} ribloccandolo non appena essa ritorna, così
-che il precedente codice potrebbe essere riscritto nel seguente modo:
+ kernel 2.6.16, non era presente la relativa \textit{system call}, e la
+ funzione era implementata nelle \acr{glibc} attraverso \func{select} (vedi
+ \texttt{man select\_tut}) per cui la possibilità di \itindex{race~condition}
+ \textit{race condition} permaneva; in tale situazione si può ricorrere ad
+ una soluzione alternativa, chiamata \itindex{self-pipe trick}
+ \textit{self-pipe trick}, che consiste nell'aprire una pipe (vedi
+ sez.~\ref{sec:ipc_pipes}) ed usare \func{select} sul capo in lettura della
+ stessa; si può indicare l'arrivo di un segnale scrivendo sul capo in
+ scrittura all'interno del gestore dello stesso; in questo modo anche se il
+ segnale va perso prima della chiamata di \func{select} questa lo riconoscerà
+ comunque dalla presenza di dati sulla pipe.} ribloccandolo non appena essa
+ritorna, così che il precedente codice potrebbe essere riscritto nel seguente
+modo:
\includecodesnip{listati/pselect_norace.c}
in questo caso utilizzando \var{oldmask} durante l'esecuzione di
\func{pselect} la ricezione del segnale sarà abilitata, ed in caso di
\itindex{race~condition} \textit{race conditions}.\footnote{in sostanza se non
fossero per i segnali non ci sarebbe da doversi preoccupare, fintanto che si
effettuano operazioni all'interno di un processo, della non atomicità delle
- \index{system~call~lente} system call lente che vengono interrotte e devono
- essere riavviate.}
+ \index{system~call~lente} \textit{system call} lente che vengono interrotte
+ e devono essere riavviate.}
Abbiamo visto però in sez.~\ref{sec:sig_real_time} che insieme ai segnali
\textit{real-time} sono state introdotte anche delle interfacce di gestione
del nome del file restituito insieme a \struct{inotify\_event}.} In caso di
errore di lettura (\texttt{\small 35--40}) il programma esce con un messaggio
di errore (\texttt{\small 37--39}), a meno che non si tratti di una
-interruzione della system call, nel qual caso (\texttt{\small 36}) si ripete la
-lettura.
+interruzione della \textit{system call}, nel qual caso (\texttt{\small 36}) si
+ripete la lettura.
Se la lettura è andata a buon fine invece si esegue un ciclo (\texttt{\small
43--52}) per leggere tutti gli eventi restituiti, al solito si inizializza
Benché la modalità di apertura asincrona di un file possa risultare utile in
varie occasioni (in particolar modo con i socket e gli altri file per i quali
-le funzioni di I/O sono \index{system~call~lente} system call lente), essa è
-comunque limitata alla notifica della disponibilità del file descriptor per le
-operazioni di I/O, e non ad uno svolgimento asincrono delle medesime. Lo
-standard POSIX.1b definisce una interfaccia apposita per l'I/O asincrono vero
-e proprio, che prevede un insieme di funzioni dedicate per la lettura e la
-scrittura dei file, completamente separate rispetto a quelle usate
+le funzioni di I/O sono \index{system~call~lente} \textit{system call} lente),
+essa è comunque limitata alla notifica della disponibilità del file descriptor
+per le operazioni di I/O, e non ad uno svolgimento asincrono delle medesime.
+Lo standard POSIX.1b definisce una interfaccia apposita per l'I/O asincrono
+vero e proprio, che prevede un insieme di funzioni dedicate per la lettura e
+la scrittura dei file, completamente separate rispetto a quelle usate
normalmente.
In generale questa interfaccia è completamente astratta e può essere
codice può essere sia \errcode{EINVAL} ed \errcode{EBADF}, dovuti ad un valore
errato per \param{aiocbp}, che uno degli errori possibili durante l'esecuzione
dell'operazione di I/O richiesta, nel qual caso saranno restituiti, a seconda
-del caso, i codici di errore delle system call \func{read}, \func{write} e
-\func{fsync}.
+del caso, i codici di errore delle \textit{system call} \func{read},
+\func{write} e \func{fsync}.
Una volta che si sia certi che le operazioni siano state concluse (cioè dopo
che una chiamata ad \func{aio\_error} non ha restituito
precedente il completamento delle operazioni darebbe risultati indeterminati.
La funzione restituisce il valore di ritorno relativo all'operazione eseguita,
-così come ricavato dalla sottostante system call (il numero di byte letti,
-scritti o il valore di ritorno di \func{fsync}). É importante chiamare sempre
-questa funzione, altrimenti le risorse disponibili per le operazioni di I/O
-asincrono non verrebbero liberate, rischiando di arrivare ad un loro
+così come ricavato dalla sottostante \textit{system call} (il numero di byte
+letti, scritti o il valore di ritorno di \func{fsync}). É importante chiamare
+sempre questa funzione, altrimenti le risorse disponibili per le operazioni di
+I/O asincrono non verrebbero liberate, rischiando di arrivare ad un loro
esaurimento.
Oltre alle operazioni di lettura e scrittura l'interfaccia POSIX.1b mette a
iniziale\footnote{e quindi una sola \textit{virtual memory area} nella
\itindex{page~table} \textit{page table} del processo.} e poi rimappare a
piacere all'interno di questa i dati del file. Ciò è possibile grazie ad una
-nuova system call, \funcd{remap\_file\_pages}, il cui prototipo è:
+nuova \textit{system call}, \funcd{remap\_file\_pages}, il cui prototipo è:
\begin{functions}
\headdecl{sys/mman.h}
chiamate a \func{read} e \func{write}, ci sono casi in cui si vuole poter
contare sulla atomicità delle operazioni.
-Per questo motivo fino da BSD 4.2 vennero introdotte delle nuove system call
-che permettessero di effettuare con una sola chiamata una serie di letture o
-scritture su una serie di buffer, con quello che viene normalmente chiamato
-\textsl{I/O vettorizzato}. Queste funzioni sono \funcd{readv} e
-\funcd{writev},\footnote{in Linux le due funzioni sono riprese da BSD4.4, esse
- sono previste anche dallo standard POSIX.1-2001.} ed i relativi prototipi
-sono:
+Per questo motivo fino da BSD 4.2 vennero introdotte delle nuove
+\textit{system call} che permettessero di effettuare con una sola chiamata una
+serie di letture o scritture su una serie di buffer, con quello che viene
+normalmente chiamato \textsl{I/O vettorizzato}. Queste funzioni sono
+\funcd{readv} e \funcd{writev},\footnote{in Linux le due funzioni sono riprese
+ da BSD4.4, esse sono previste anche dallo standard POSIX.1-2001.} ed i
+relativi prototipi sono:
\begin{functions}
\headdecl{sys/uio.h}
sez.~\ref{sec:sys_limits}).
Nel caso di Linux il limite di sistema è di 1024, però se si usano le
-\acr{glibc} queste forniscono un \textit{wrapper} per le system call che si
-accorge se una operazione supererà il precedente limite, in tal caso i dati
-verranno letti o scritti con le usuali \func{read} e \func{write} usando un
-buffer di dimensioni sufficienti appositamente allocato e sufficiente a
+\acr{glibc} queste forniscono un \textit{wrapper} per le \textit{system call}
+che si accorge se una operazione supererà il precedente limite, in tal caso i
+dati verranno letti o scritti con le usuali \func{read} e \func{write} usando
+un buffer di dimensioni sufficienti appositamente allocato e sufficiente a
contenere tutti i dati indicati da \param{vector}. L'operazione avrà successo
ma si perderà l'atomicità del trasferimento da e verso la destinazione finale.
senso che un trasferimento di dati fra due file con \func{sendfile} non
sarebbe altro che la lettura degli stessi su un buffer seguita dalla
relativa scrittura, cosa che in questo caso si dovrebbe eseguire con due
- chiamate a \func{splice}.} In realtà le due system call sono profondamente
-diverse nel loro meccanismo di funzionamento;\footnote{questo fino al kernel
- 2.6.23, dove \func{sendfile} è stata reimplementata in termini di
- \func{splice}, pur mantenendo disponibile la stessa interfaccia verso l'user
- space.} \func{sendfile} infatti, come accennato, non necessita di avere a
-disposizione un buffer interno, perché esegue un trasferimento diretto di
-dati; questo la rende in generale più efficiente, ma anche limitata nelle sue
-applicazioni, dato che questo tipo di trasferimento è possibile solo in casi
-specifici.\footnote{e nel caso di Linux questi sono anche solo quelli in cui
- essa può essere effettivamente utilizzata.}
+ chiamate a \func{splice}.} In realtà le due \textit{system call} sono
+profondamente diverse nel loro meccanismo di funzionamento;\footnote{questo
+ fino al kernel 2.6.23, dove \func{sendfile} è stata reimplementata in
+ termini di \func{splice}, pur mantenendo disponibile la stessa interfaccia
+ verso l'user space.} \func{sendfile} infatti, come accennato, non necessita
+di avere a disposizione un buffer interno, perché esegue un trasferimento
+diretto di dati; questo la rende in generale più efficiente, ma anche limitata
+nelle sue applicazioni, dato che questo tipo di trasferimento è possibile solo
+in casi specifici.\footnote{e nel caso di Linux questi sono anche solo quelli
+ in cui essa può essere effettivamente utilizzata.}
Il concetto che sta dietro a \func{splice} invece è diverso,\footnote{in
realtà la proposta originale di Larry Mc Voy non differisce poi tanto negli
Infine una nota finale riguardo \func{splice}, \func{vmsplice} e \func{tee}:
occorre sottolineare che benché finora si sia parlato di trasferimenti o copie
-di dati in realtà nella implementazione di queste system call non è affatto
-detto che i dati vengono effettivamente spostati o copiati, il kernel infatti
-realizza le \textit{pipe} come un insieme di puntatori\footnote{per essere
- precisi si tratta di un semplice buffer circolare, un buon articolo sul tema
- si trova su \url{http://lwn.net/Articles/118750/}.} alle pagine di memoria
-interna che contengono i dati, per questo una volta che i dati sono presenti
-nella memoria del kernel tutto quello che viene fatto è creare i suddetti
-puntatori ed aumentare il numero di referenze; questo significa che anche con
-\func{tee} non viene mai copiato nessun byte, vengono semplicemente copiati i
-puntatori.
+di dati in realtà nella implementazione di queste \textit{system call} non è
+affatto detto che i dati vengono effettivamente spostati o copiati, il kernel
+infatti realizza le \textit{pipe} come un insieme di puntatori\footnote{per
+ essere precisi si tratta di un semplice buffer circolare, un buon articolo
+ sul tema si trova su \url{http://lwn.net/Articles/118750/}.} alle pagine di
+memoria interna che contengono i dati, per questo una volta che i dati sono
+presenti nella memoria del kernel tutto quello che viene fatto è creare i
+suddetti puntatori ed aumentare il numero di referenze; questo significa che
+anche con \func{tee} non viene mai copiato nessun byte, vengono semplicemente
+copiati i puntatori.
% TODO?? dal 2.6.25 splice ha ottenuto il supporto per la ricezione su rete
% http://lwn.net/Articles/432757/
-% LocalWords: dell'I locking multiplexing cap dell' sez system call socket BSD
+% LocalWords: dell'I locking multiplexing cap sez system call socket BSD
% LocalWords: descriptor client deadlock NONBLOCK EAGAIN polling select kernel
% LocalWords: pselect like sys unistd int fd readfds writefds exceptfds struct
% LocalWords: timeval errno EBADF EINTR EINVAL ENOMEM sleep tab signal void of