+ \funcdecl{void \macro{FD\_SET}(int fd, fd\_set *set)}
+ Inserisce il file descriptor \param{fd} nell'insieme.
+
+ \funcdecl{void \macro{FD\_CLR}(int fd, fd\_set *set)}
+ Rimuove il file descriptor \param{fd} dall'insieme.
+
+ \funcdecl{int \macro{FD\_ISSET}(int fd, fd\_set *set)}
+ Controlla se il file descriptor \param{fd} è nell'insieme.
+\end{functions}
+
+In genere un \textit{file descriptor set} può contenere fino ad un massimo di
+\const{FD\_SETSIZE} file descriptor. Questo valore in origine corrispondeva
+al limite per il numero massimo di file aperti\footnote{ad esempio in Linux,
+ fino alla serie 2.0.x, c'era un limite di 256 file per processo.}, ma da
+quando, come nelle versioni più recenti del kernel, questo limite è stato
+rimosso, esso indica le dimensioni massime dei numeri usati nei \textit{file
+ descriptor set}.\footnote{il suo valore, secondo lo standard POSIX
+ 1003.1-2001, è definito in \file{sys/select.h}, ed è pari a 1024.}
+
+Si tenga presente che i \textit{file descriptor set} devono sempre essere
+inizializzati con \macro{FD\_ZERO}; passare a \func{select} un valore non
+inizializzato può dar luogo a comportamenti non prevedibili; allo stesso modo
+usare \macro{FD\_SET} o \macro{FD\_CLR} con un file descriptor il cui valore
+eccede \const{FD\_SETSIZE} può dare luogo ad un comportamento indefinito.
+
+La funzione richiede di specificare tre insiemi distinti di file descriptor;
+il primo, \param{readfds}, verrà osservato per rilevare la disponibilità di
+effettuare una lettura,\footnote{per essere precisi la funzione ritornerà in
+ tutti i casi in cui la successiva esecuzione di \func{read} risulti non
+ bloccante, quindi anche in caso di \textit{end-of-file}; inoltre con Linux
+ possono verificarsi casi particolari, ad esempio quando arrivano dati su un
+ socket dalla rete che poi risultano corrotti e vengono scartati, può
+ accadere che \func{select} riporti il relativo file descriptor come
+ leggibile, ma una successiva \func{read} si blocchi.} il secondo,
+\param{writefds}, per verificare la possibilità di effettuare una scrittura ed
+il terzo, \param{exceptfds}, per verificare l'esistenza di eccezioni (come i
+dati urgenti \itindex{out-of-band} su un socket, vedi
+sez.~\ref{sec:TCP_urgent_data}).
+
+Dato che in genere non si tengono mai sotto controllo fino a
+\const{FD\_SETSIZE} file contemporaneamente la funzione richiede di
+specificare qual è il valore più alto fra i file descriptor indicati nei tre
+insiemi precedenti. Questo viene fatto per efficienza, per evitare di passare
+e far controllare al kernel una quantità di memoria superiore a quella
+necessaria. Questo limite viene indicato tramite l'argomento \param{ndfs}, che
+deve corrispondere al valore massimo aumentato di uno.\footnote{si ricordi che
+ i file descriptor sono numerati progressivamente a partire da zero, ed il
+ valore indica il numero più alto fra quelli da tenere sotto controllo;
+ dimenticarsi di aumentare di uno il valore di \param{ndfs} è un errore
+ comune.}
+
+Infine l'argomento \param{timeout}, espresso con una struttura di tipo
+\struct{timeval} (vedi fig.~\ref{fig:sys_timeval_struct}) specifica un tempo
+massimo di attesa prima che la funzione ritorni; se impostato a \val{NULL} la
+funzione attende indefinitamente. Si può specificare anche un tempo nullo
+(cioè una struttura \struct{timeval} con i campi impostati a zero), qualora si
+voglia semplicemente controllare lo stato corrente dei file descriptor.
+
+La funzione restituisce il numero di file descriptor pronti,\footnote{questo è
+ il comportamento previsto dallo standard, ma la standardizzazione della
+ funzione è recente, ed esistono ancora alcune versioni di Unix che non si
+ comportano in questo modo.} e ciascun insieme viene sovrascritto per
+indicare quali sono i file descriptor pronti per le operazioni ad esso
+relative, in modo da poterli controllare con \macro{FD\_ISSET}. Se invece si
+ha un timeout viene restituito un valore nullo e gli insiemi non vengono
+modificati. In caso di errore la funzione restituisce -1, ed i valori dei tre
+insiemi sono indefiniti e non si può fare nessun affidamento sul loro
+contenuto.
+
+\itindend{file~descriptor~set}
+
+Una volta ritornata la funzione si potrà controllare quali sono i file
+descriptor pronti ed operare su di essi, si tenga presente però che si tratta
+solo di un suggerimento, esistono infatti condizioni\footnote{ad esempio
+ quando su un socket arrivano dei dati che poi vengono scartati perché
+ corrotti.} in cui \func{select} può riportare in maniera spuria che un file
+descriptor è pronto in lettura, quando una successiva lettura si bloccherebbe.
+Per questo quando si usa \textit{I/O multiplexing} è sempre raccomandato l'uso
+delle funzioni di lettura e scrittura in modalità non bloccante.
+
+In Linux \func{select} modifica anche il valore di \param{timeout},
+impostandolo al tempo restante, quando la funzione viene interrotta da un
+segnale. In tal caso infatti si ha un errore di \errcode{EINTR}, ed occorre
+rilanciare la funzione; in questo modo non è necessario ricalcolare tutte le
+volte il tempo rimanente. Questo può causare problemi di portabilità sia
+quando si usa codice scritto su Linux che legge questo valore, sia quando si
+usano programmi scritti per altri sistemi che non dispongono di questa
+caratteristica e ricalcolano \param{timeout} tutte le volte.\footnote{in
+ genere questa caratteristica è disponibile nei sistemi che derivano da
+ System V e non è disponibile per quelli che derivano da BSD; lo standard
+ POSIX.1-2001 non permette questo comportamento.}
+
+Uno dei problemi che si presentano con l'uso di \func{select} è che il suo
+comportamento dipende dal valore del file descriptor che si vuole tenere sotto
+controllo. Infatti il kernel riceve con \param{ndfs} un limite massimo per
+tale valore, e per capire quali sono i file descriptor da tenere sotto
+controllo dovrà effettuare una scansione su tutto l'intervallo, che può anche
+essere molto ampio anche se i file descriptor sono solo poche unità; tutto ciò
+ha ovviamente delle conseguenze ampiamente negative per le prestazioni.
+
+Inoltre c'è anche il problema che il numero massimo dei file che si possono
+tenere sotto controllo, la funzione è nata quando il kernel consentiva un
+numero massimo di 1024 file descriptor per processo, adesso che il numero può
+essere arbitrario si viene a creare una dipendenza del tutto artificiale dalle
+dimensioni della struttura \type{fd\_set}, che può necessitare di essere
+estesa, con ulteriori perdite di prestazioni.
+
+Lo standard POSIX è rimasto a lungo senza primitive per l'\textit{I/O
+ multiplexing}, introdotto solo con le ultime revisioni dello standard (POSIX
+1003.1g-2000 e POSIX 1003.1-2001). La scelta è stata quella di seguire
+l'interfaccia creata da BSD, ma prevede che tutte le funzioni ad esso relative
+vengano dichiarate nell'header \file{sys/select.h}, che sostituisce i
+precedenti, ed inoltre aggiunge a \func{select} una nuova funzione
+\funcd{pselect},\footnote{il supporto per lo standard POSIX 1003.1-2001, ed
+ l'header \file{sys/select.h}, compaiono in Linux a partire dalle \acr{glibc}
+ 2.1. Le \acr{libc4} e \acr{libc5} non contengono questo header, le
+ \acr{glibc} 2.0 contengono una definizione sbagliata di \func{psignal},
+ senza l'argomento \param{sigmask}, la definizione corretta è presente dalle
+ \acr{glibc} 2.1-2.2.1 se si è definito \macro{\_GNU\_SOURCE} e nelle
+ \acr{glibc} 2.2.2-2.2.4 se si è definito \macro{\_XOPEN\_SOURCE} con valore
+ maggiore di 600.} il cui prototipo è:
+\begin{prototype}{sys/select.h}
+ {int pselect(int n, fd\_set *readfds, fd\_set *writefds, fd\_set *exceptfds,
+ struct timespec *timeout, sigset\_t *sigmask)}
+
+ Attende che uno dei file descriptor degli insiemi specificati diventi
+ attivo.
+
+ \bodydesc{La funzione in caso di successo restituisce il numero di file
+ descriptor (anche nullo) che sono attivi, e -1 in caso di errore, nel qual
+ caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EBADF}] si è specificato un file descriptor sbagliato in uno
+ degli insiemi.
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
+ \item[\errcode{EINVAL}] si è specificato per \param{ndfs} un valore negativo
+ o un valore non valido per \param{timeout}.
+ \end{errlist}
+ ed inoltre \errval{ENOMEM}.}
+\end{prototype}
+
+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 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
+attesa sia di un segnale che di dati. La tecnica classica è quella di
+utilizzare il gestore per impostare una \index{variabili!globali} variabile
+globale e controllare questa nel corpo principale del programma; abbiamo visto
+in sez.~\ref{sec:sig_example} come questo lasci spazio a possibili
+\itindex{race~condition} \textit{race condition}, per cui diventa essenziale
+utilizzare \func{sigprocmask} per disabilitare la ricezione del segnale prima
+di eseguire il controllo e riabilitarlo dopo l'esecuzione delle relative
+operazioni, onde evitare l'arrivo di un segnale immediatamente dopo il
+controllo, che andrebbe perso.
+
+Nel nostro caso il problema si pone quando oltre al segnale si devono tenere
+sotto controllo anche dei file descriptor con \func{select}, in questo caso si
+può fare conto sul fatto che all'arrivo di un segnale essa verrebbe interrotta
+e si potrebbero eseguire di conseguenza le operazioni relative al segnale e
+alla gestione dati con un ciclo del tipo:
+\includecodesnip{listati/select_race.c}
+qui però emerge una \itindex{race~condition} \textit{race condition}, perché
+se il segnale arriva prima della chiamata a \func{select}, questa non verrà
+interrotta, e la ricezione del segnale non sarà rilevata.
+
+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:
+\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
+interruzione si potranno eseguire le relative operazioni.
+
+
+\subsection{Le funzioni \func{poll} e \func{ppoll}}
+\label{sec:file_poll}
+
+Nello sviluppo di System V, invece di utilizzare l'interfaccia di
+\func{select}, che è una estensione tipica di BSD, è stata introdotta un'altra
+interfaccia, basata sulla funzione \funcd{poll},\footnote{la funzione è
+ prevista dallo standard XPG4, ed è stata introdotta in Linux come system
+ call a partire dal kernel 2.1.23 ed inserita nelle \acr{libc} 5.4.28.} il
+cui prototipo è:
+\begin{prototype}{sys/poll.h}
+ {int poll(struct pollfd *ufds, unsigned int nfds, int timeout)}
+
+ La funzione attende un cambiamento di stato su un insieme di file
+ descriptor.
+
+ \bodydesc{La funzione restituisce il numero di file descriptor con attività
+ in caso di successo, o 0 se c'è stato un timeout e -1 in caso di errore,
+ ed in quest'ultimo caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EBADF}] si è specificato un file descriptor sbagliato in uno
+ degli insiemi.
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
+ \item[\errcode{EINVAL}] il valore di \param{nfds} eccede il limite
+ \macro{RLIMIT\_NOFILE}.
+ \end{errlist}
+ ed inoltre \errval{EFAULT} e \errval{ENOMEM}.}
+\end{prototype}
+
+La funzione permette di tenere sotto controllo contemporaneamente \param{ndfs}
+file descriptor, specificati attraverso il puntatore \param{ufds} ad un
+vettore di strutture \struct{pollfd}. Come con \func{select} si può
+interrompere l'attesa dopo un certo tempo, questo deve essere specificato con
+l'argomento \param{timeout} in numero di millisecondi: un valore negativo
+indica un'attesa indefinita, mentre un valore nullo comporta il ritorno
+immediato (e può essere utilizzato per impiegare \func{poll} in modalità
+\textsl{non-bloccante}).
+
+Per ciascun file da controllare deve essere inizializzata una struttura
+\struct{pollfd} nel vettore indicato dall'argomento \param{ufds}. La
+struttura, la cui definizione è riportata in fig.~\ref{fig:file_pollfd},
+prevede tre campi: in \var{fd} deve essere indicato il numero del file
+descriptor da controllare, in \var{events} deve essere specificata una
+maschera binaria di flag che indichino il tipo di evento che si vuole
+controllare, mentre in \var{revents} il kernel restituirà il relativo
+risultato. Usando un valore negativo per \param{fd} la corrispondente
+struttura sarà ignorata da \func{poll}. Dato che i dati in ingresso sono del
+tutto indipendenti da quelli in uscita (che vengono restituiti in
+\var{revents}) non è necessario reinizializzare tutte le volte il valore delle
+strutture \struct{pollfd} a meno di non voler cambiare qualche condizione.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{\textwidth}
+ \includestruct{listati/pollfd.h}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \structd{pollfd}, utilizzata per specificare le
+ modalità di controllo di un file descriptor alla funzione \func{poll}.}
+ \label{fig:file_pollfd}
+\end{figure}
+
+Le costanti che definiscono i valori relativi ai bit usati nelle maschere
+binarie dei campi \var{events} e \var{revents} sono riportati in
+tab.~\ref{tab:file_pollfd_flags}, insieme al loro significato. Le si sono
+suddivise in tre gruppi, nel primo gruppo si sono indicati i bit utilizzati
+per controllare l'attività in ingresso, nel secondo quelli per l'attività in
+uscita, mentre il terzo gruppo contiene dei valori che vengono utilizzati solo
+nel campo \var{revents} per notificare delle condizioni di errore.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|l|}
+ \hline
+ \textbf{Flag} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{POLLIN} & È possibile la lettura.\\
+ \const{POLLRDNORM}& Sono disponibili in lettura dati normali.\\
+ \const{POLLRDBAND}& Sono disponibili in lettura dati prioritari.\\
+ \const{POLLPRI} & È possibile la lettura di \itindex{out-of-band} dati
+ urgenti.\\
+ \hline
+ \const{POLLOUT} & È possibile la scrittura immediata.\\
+ \const{POLLWRNORM}& È possibile la scrittura di dati normali.\\
+ \const{POLLWRBAND}& È possibile la scrittura di dati prioritari.\\
+ \hline
+ \const{POLLERR} & C'è una condizione di errore.\\
+ \const{POLLHUP} & Si è verificato un hung-up.\\
+ \const{POLLRDHUP} & Si è avuta una \textsl{half-close} su un
+ socket.\footnotemark\\
+ \const{POLLNVAL} & Il file descriptor non è aperto.\\
+ \hline
+ \const{POLLMSG} & Definito per compatibilità con SysV.\\
+ \hline
+ \end{tabular}
+ \caption{Costanti per l'identificazione dei vari bit dei campi
+ \var{events} e \var{revents} di \struct{pollfd}.}
+ \label{tab:file_pollfd_flags}
+\end{table}
+
+\footnotetext{si tratta di una estensione specifica di Linux, disponibile a
+ partire dal kernel 2.6.17 definendo la marco \macro{\_GNU\_SOURCE}, che
+ consente di riconoscere la chiusura in scrittura dell'altro capo di un
+ socket, situazione che si viene chiamata appunto \itindex{half-close}
+ \textit{half-close} (\textsl{mezza chiusura}) su cui torneremo con maggiori
+ dettagli in sez.~\ref{sec:TCP_shutdown}.}
+
+Il valore \const{POLLMSG} non viene utilizzato ed è definito solo per
+compatibilità con l'implementazione di SysV che usa gli
+\textit{stream};\footnote{essi sono una interfaccia specifica di SysV non
+ presente in Linux, e non hanno nulla a che fare con i file \textit{stream}
+ delle librerie standard del C.} è da questi che derivano i nomi di alcune
+costanti, in quanto per essi sono definite tre classi di dati:
+\textsl{normali}, \textit{prioritari} ed \textit{urgenti}. In Linux la
+distinzione ha senso solo per i dati urgenti \itindex{out-of-band} dei socket
+(vedi sez.~\ref{sec:TCP_urgent_data}), ma su questo e su come \func{poll}
+reagisce alle varie condizioni dei socket torneremo in
+sez.~\ref{sec:TCP_serv_poll}, dove vedremo anche un esempio del suo utilizzo.
+
+Si tenga conto comunque che le costanti relative ai diversi tipi di dati
+normali e prioritari, vale a dire \const{POLLRDNORM}, \const{POLLWRNORM},
+\const{POLLRDBAND} e \const{POLLWRBAND} fanno riferimento alle implementazioni
+in stile SysV (in particolare le ultime due non vengono usate su Linux), e
+sono utilizzabili soltanto qualora si sia definita la macro
+\macro{\_XOPEN\_SOURCE}.\footnote{e ci si ricordi di farlo sempre in testa al
+ file, definirla soltanto prima di includere \file{sys/poll.h} non è
+ sufficiente.}
+
+In caso di successo funzione ritorna restituendo il numero di file (un valore
+positivo) per i quali si è verificata una delle condizioni di attesa richieste
+o per i quali si è verificato un errore, nel qual caso vengono utilizzati i
+valori di tab.~\ref{tab:file_pollfd_flags} esclusivi di \var{revents}. Un
+valore nullo indica che si è raggiunto il timeout, mentre un valore negativo
+indica un errore nella chiamata, il cui codice viene riportato al solito
+tramite \var{errno}.
+
+L'uso di \func{poll} consente di superare alcuni dei problemi illustrati in
+precedenza per \func{select}; anzitutto, dato che in questo caso si usa un
+vettore di strutture \struct{pollfd} di dimensione arbitraria, non esiste il
+limite introdotto dalle dimensioni massime di un \itindex{file~descriptor~set}
+\textit{file descriptor set} e la dimensione dei dati passati al kernel
+dipende solo dal numero dei file descriptor che si vogliono controllare, non
+dal loro valore.\footnote{anche se usando dei bit un \textit{file descriptor
+ set} può essere più efficiente di un vettore di strutture \struct{pollfd},
+ qualora si debba osservare un solo file descriptor con un valore molto alto
+ ci si troverà ad utilizzare inutilmente un maggiore quantitativo di
+ memoria.}
+
+Inoltre con \func{select} lo stesso \itindex{file~descriptor~set} \textit{file
+ descriptor set} è usato sia in ingresso che in uscita, e questo significa
+che tutte le volte che si vuole ripetere l'operazione occorre reinizializzarlo
+da capo. Questa operazione, che può essere molto onerosa se i file descriptor
+da tenere sotto osservazione sono molti, non è invece necessaria con
+\func{poll}.
+
+Abbiamo visto in sez.~\ref{sec:file_select} come lo standard POSIX preveda una
+variante di \func{select} che consente di gestire correttamente la ricezione
+dei segnali nell'attesa su un file descriptor. Con l'introduzione di una
+implementazione reale di \func{pselect} nel kernel 2.6.16, è stata aggiunta
+anche una analoga funzione che svolga lo stesso ruolo per \func{poll}.
+
+In questo caso si tratta di una estensione che è specifica di Linux e non è
+prevista da nessuno standard; essa può essere utilizzata esclusivamente se si
+definisce la macro \macro{\_GNU\_SOURCE} ed ovviamente non deve essere usata
+se si ha a cuore la portabilità. La funzione è \funcd{ppoll}, ed il suo
+prototipo è:
+\begin{prototype}{sys/poll.h}
+ {int ppoll(struct pollfd *fds, nfds\_t nfds, const struct timespec *timeout,
+ const sigset\_t *sigmask)}
+
+ La funzione attende un cambiamento di stato su un insieme di file
+ descriptor.
+
+ \bodydesc{La funzione restituisce il numero di file descriptor con attività
+ in caso di successo, o 0 se c'è stato un timeout e -1 in caso di errore,
+ ed in quest'ultimo caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EBADF}] si è specificato un file descriptor sbagliato in uno
+ degli insiemi.
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
+ \item[\errcode{EINVAL}] il valore di \param{nfds} eccede il limite
+ \macro{RLIMIT\_NOFILE}.
+ \end{errlist}
+ ed inoltre \errval{EFAULT} e \errval{ENOMEM}.}
+\end{prototype}
+
+La funzione ha lo stesso comportamento di \func{poll}, solo che si può
+specificare, con l'argomento \param{sigmask}, il puntatore ad una maschera di
+segnali; questa sarà la maschera utilizzata per tutto il tempo che la funzione
+resterà in attesa, all'uscita viene ripristinata la maschera originale. L'uso
+di questa funzione è cioè equivalente, come illustrato nella pagina di
+manuale, all'esecuzione atomica del seguente codice:
+\includecodesnip{listati/ppoll_means.c}
+
+Eccetto per \param{timeout}, che come per \func{pselect} deve essere un
+puntatore ad una struttura \struct{timespec}, gli altri argomenti comuni con
+\func{poll} hanno lo stesso significato, e la funzione restituisce gli stessi
+risultati illustrati in precedenza. Come nel caso di \func{pselect} la system
+call che implementa \func{ppoll} restituisce, se la funzione viene interrotta
+da un segnale, il tempo mancante in \param{timeout}, e come per \func{pselect}
+la funzione di libreria fornita dalle \acr{glibc} maschera questo
+comportamento non modificando mai il valore di \param{timeout}.\footnote{anche
+ se in questo caso non esiste nessuno standard che richiede questo
+ comportamento.}
+
+
+\subsection{L'interfaccia di \textit{epoll}}
+\label{sec:file_epoll}
+
+\itindbeg{epoll}
+
+Nonostante \func{poll} presenti alcuni vantaggi rispetto a \func{select},
+anche questa funzione non è molto efficiente quando deve essere utilizzata con
+un gran numero di file descriptor,\footnote{in casi del genere \func{select}
+ viene scartata a priori, perché può avvenire che il numero di file
+ descriptor ecceda le dimensioni massime di un \itindex{file~descriptor~set}
+ \textit{file descriptor set}.} in particolare nel caso in cui solo pochi di
+questi diventano attivi. Il problema in questo caso è che il tempo impiegato
+da \func{poll} a trasferire i dati da e verso il kernel è proporzionale al
+numero di file descriptor osservati, non a quelli che presentano attività.
+
+Quando ci sono decine di migliaia di file descriptor osservati e migliaia di
+eventi al secondo,\footnote{il caso classico è quello di un server web di un
+ sito con molti accessi.} l'uso di \func{poll} comporta la necessità di
+trasferire avanti ed indietro da user space a kernel space la lunga lista
+delle strutture \struct{pollfd} migliaia di volte al secondo. A questo poi si
+aggiunge il fatto che la maggior parte del tempo di esecuzione sarà impegnato
+ad eseguire una scansione su tutti i file descriptor tenuti sotto controllo
+per determinare quali di essi (in genere una piccola percentuale) sono
+diventati attivi. In una situazione come questa l'uso delle funzioni classiche
+dell'interfaccia dell'\textit{I/O multiplexing} viene a costituire un collo di
+bottiglia che degrada irrimediabilmente le prestazioni.
+
+Per risolvere questo tipo di situazioni sono state ideate delle interfacce
+specialistiche\footnote{come \texttt{/dev/poll} in Solaris, o \texttt{kqueue}
+ in BSD.} il cui scopo fondamentale è quello di restituire solamente le
+informazioni relative ai file descriptor osservati che presentano una
+attività, evitando così le problematiche appena illustrate. In genere queste
+prevedono che si registrino una sola volta i file descriptor da tenere sotto
+osservazione, e forniscono un meccanismo che notifica quali di questi
+presentano attività.
+
+Le modalità con cui avviene la notifica sono due, la prima è quella classica
+(quella usata da \func{poll} e \func{select}) che viene chiamata \textit{level
+ triggered}.\footnote{la nomenclatura è stata introdotta da Jonathan Lemon in
+ un articolo su \texttt{kqueue} al BSDCON 2000, e deriva da quella usata
+ nell'elettronica digitale.} In questa modalità vengono notificati i file
+descriptor che sono \textsl{pronti} per l'operazione richiesta, e questo
+avviene indipendentemente dalle operazioni che possono essere state fatte su
+di essi a partire dalla precedente notifica. Per chiarire meglio il concetto
+ricorriamo ad un esempio: se su un file descriptor sono diventati disponibili
+in lettura 2000 byte ma dopo la notifica ne sono letti solo 1000 (ed è quindi
+possibile eseguire una ulteriore lettura dei restanti 1000), in modalità
+\textit{level triggered} questo sarà nuovamente notificato come
+\textsl{pronto}.
+
+La seconda modalità, è detta \textit{edge triggered}, e prevede che invece
+vengano notificati solo i file descriptor che hanno subito una transizione da
+\textsl{non pronti} a \textsl{pronti}. Questo significa che in modalità
+\textit{edge triggered} nel caso del precedente esempio il file descriptor
+diventato pronto da cui si sono letti solo 1000 byte non verrà nuovamente
+notificato come pronto, nonostante siano ancora disponibili in lettura 1000
+byte. Solo una volta che si saranno esauriti tutti i dati disponibili, e che
+il file descriptor sia tornato non essere pronto, si potrà ricevere una
+ulteriore notifica qualora ritornasse pronto.
+
+Nel caso di Linux al momento la sola interfaccia che fornisce questo tipo di
+servizio è \textit{epoll},\footnote{l'interfaccia è stata creata da Davide
+ Libenzi, ed è stata introdotta per la prima volta nel kernel 2.5.44, ma la
+ sua forma definitiva è stata raggiunta nel kernel 2.5.66.} anche se sono in
+discussione altre interfacce con le quali si potranno effettuare lo stesso
+tipo di operazioni;\footnote{al momento della stesura di queste note (Giugno
+ 2007) un'altra interfaccia proposta è quella di \textit{kevent}, che
+ fornisce un sistema di notifica di eventi generico in grado di fornire le
+ stesse funzionalità di \textit{epoll}, esiste però una forte discussione
+ intorno a tutto ciò e niente di definito.} \textit{epoll} è in grado di
+operare sia in modalità \textit{level triggered} che \textit{edge triggered}.
+
+La prima versione \textit{epoll} prevedeva l'apertura di uno speciale file di
+dispositivo, \texttt{/dev/epoll}, per ottenere un file descriptor da
+utilizzare con le funzioni dell'interfaccia,\footnote{il backporting
+ dell'interfaccia per il kernel 2.4, non ufficiale, utilizza sempre questo
+ file.} ma poi si è passati all'uso di apposite \textit{system call}. Il
+primo passo per usare l'interfaccia di \textit{epoll} è pertanto quello
+ottenere detto file descriptor chiamando una delle funzioni
+\funcd{epoll\_create} e \funcd{epoll\_create1},\footnote{l'interfaccia di
+ \textit{epoll} è stata inserita nel kernel a partire dalla versione 2.5.44,
+ ed il supporto è stato aggiunto alle \acr{glibc} 2.3.2.} i cui prototipi
+sono:
+\begin{functions}
+ \headdecl{sys/epoll.h}
+
+ \funcdecl{int epoll\_create(int size)}
+ \funcdecl{int epoll\_create1(int flags)}
+
+ Apre un file descriptor per \textit{epoll}.
+
+ \bodydesc{Le funzioni restituiscono un file descriptor per \textit{epoll} in
+ caso di successo, o $-1$ in caso di errore, nel qual caso \var{errno}
+ assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] si è specificato un valore di \param{size} non
+ positivo o non valido per \param{flags}.
+ \item[\errcode{ENFILE}] si è raggiunto il massimo di file descriptor aperti
+ nel sistema.
+ \item[\errcode{EMFILE}] si è raggiunto il limite sul numero massimo di
+ istanze di \textit{epoll} per utente stabilito da
+ \procfile{/proc/sys/fs/epoll/max\_user\_instances}.
+ \item[\errcode{ENOMEM}] non c'è sufficiente memoria nel kernel per creare
+ l'istanza.
+ \end{errlist}
+}
+\end{functions}
+
+Entrambe le funzioni restituiscono un file descriptor speciale,\footnote{esso
+ non è associato a nessun file su disco, inoltre a differenza dei normali
+ file descriptor non può essere inviato ad un altro processo attraverso un
+ socket locale (vedi sez.~\ref{sec:sock_fd_passing}).} detto anche
+\textit{epoll descriptor}, che viene associato alla infrastruttura utilizzata
+dal kernel per gestire la notifica degli eventi. Nel caso di
+\func{epoll\_create} l'argomento \param{size} serviva a dare l'indicazione del
+numero di file descriptor che si vorranno tenere sotto controllo, e costituiva
+solo un suggerimento per semplificare l'allocazione di risorse sufficienti,
+non un valore massimo.\footnote{ma a partire dal kernel 2.6.8 esso viene
+ totalmente ignorato e l'allocazione è sempre dinamica.}
+
+La seconda versione della funzione, \func{epoll\_create1} è stata
+introdotta\footnote{è disponibile solo a partire dal kernel 2.6.27.} come
+estensione della precedente, per poter passare dei flag di controllo come
+maschera binaria in fase di creazione del file descriptor. Al momento l'unico
+valore legale per \param{flags} (a parte lo zero) è \const{EPOLL\_CLOEXEC},
+che consente di impostare in maniera atomica sul file descriptor il flag di
+\itindex{close-on-exec} \textit{close-on-exec} (si veda il significato di
+\const{O\_CLOEXEC} in tab.~\ref{tab:file_open_flags}), senza che sia
+necessaria una successiva chiamata a \func{fcntl}.
+
+Una volta ottenuto un file descriptor per \textit{epoll} il passo successivo è
+indicare quali file descriptor mettere sotto osservazione e quali operazioni
+controllare, per questo si deve usare la seconda funzione dell'interfaccia,
+\funcd{epoll\_ctl}, il cui prototipo è:
+\begin{prototype}{sys/epoll.h}
+ {int epoll\_ctl(int epfd, int op, int fd, struct epoll\_event *event)}
+
+ Esegue le operazioni di controllo di \textit{epoll}.
+
+ \bodydesc{La funzione restituisce $0$ in caso di successo o $-1$ in caso di
+ errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EBADF}] il file descriptor \param{epfd} o \param{fd} non sono
+ validi.
+ \item[\errcode{EEXIST}] l'operazione richiesta è \const{EPOLL\_CTL\_ADD} ma
+ \param{fd} è già stato inserito in \param{epfd}.
+ \item[\errcode{EINVAL}] il file descriptor \param{epfd} non è stato ottenuto
+ con \func{epoll\_create}, o \param{fd} è lo stesso \param{epfd} o
+ l'operazione richiesta con \param{op} non è supportata.
+ \item[\errcode{ENOENT}] l'operazione richiesta è \const{EPOLL\_CTL\_MOD} o
+ \const{EPOLL\_CTL\_DEL} ma \param{fd} non è inserito in \param{epfd}.
+ \item[\errcode{ENOMEM}] non c'è sufficiente memoria nel kernel gestire
+ l'operazione richiesta.
+ \item[\errcode{EPERM}] il file \param{fd} non supporta \textit{epoll}.
+ \item[\errcode{ENOSPC}] si è raggiunto il limite massimo di registrazioni
+ per utente di file descriptor da osservare imposto da
+ \procfile{/proc/sys/fs/epoll/max\_user\_watches}.
+ \end{errlist}
+}
+\end{prototype}
+
+Il comportamento della funzione viene controllato dal valore dall'argomento
+\param{op} che consente di specificare quale operazione deve essere eseguita.
+Le costanti che definiscono i valori utilizzabili per \param{op}
+sono riportate in tab.~\ref{tab:epoll_ctl_operation}, assieme al significato
+delle operazioni cui fanno riferimento.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|p{8cm}|}
+ \hline
+ \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{EPOLL\_CTL\_ADD}& Aggiunge un nuovo file descriptor da osservare
+ \param{fd} alla lista dei file descriptor
+ controllati tramite \param{epfd}, in
+ \param{event} devono essere specificate le
+ modalità di osservazione.\\
+ \const{EPOLL\_CTL\_MOD}& Modifica le modalità di osservazione del file
+ descriptor \param{fd} secondo il contenuto di
+ \param{event}.\\
+ \const{EPOLL\_CTL\_DEL}& Rimuove il file descriptor \param{fd} dalla lista
+ dei file controllati tramite \param{epfd}.\\
+ \hline
+ \end{tabular}
+ \caption{Valori dell'argomento \param{op} che consentono di scegliere quale
+ operazione di controllo effettuare con la funzione \func{epoll\_ctl}.}
+ \label{tab:epoll_ctl_operation}
+\end{table}
+
+La funzione prende sempre come primo argomento un file descriptor di
+\textit{epoll}, \param{epfd}, che deve essere stato ottenuto in precedenza con
+una chiamata a \func{epoll\_create}. L'argomento \param{fd} indica invece il
+file descriptor che si vuole tenere sotto controllo, quest'ultimo può essere
+un qualunque file descriptor utilizzabile con \func{poll}, ed anche un altro
+file descriptor di \textit{epoll}, ma non lo stesso \param{epfd}.
+
+L'ultimo argomento, \param{event}, deve essere un puntatore ad una struttura
+di tipo \struct{epoll\_event}, ed ha significato solo con le operazioni
+\const{EPOLL\_CTL\_MOD} e \const{EPOLL\_CTL\_ADD}, per le quali serve ad
+indicare quale tipo di evento relativo ad \param{fd} si vuole che sia tenuto
+sotto controllo. L'argomento viene ignorato con l'operazione
+\const{EPOLL\_CTL\_DEL}.\footnote{fino al kernel 2.6.9 era comunque richiesto
+ che questo fosse un puntatore valido, anche se poi veniva ignorato; a
+ partire dal 2.6.9 si può specificare anche un valore \val{NULL} ma se si
+ vuole mantenere la compatibilità con le versioni precedenti occorre usare un
+ puntatore valido.}
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{\textwidth}
+ \includestruct{listati/epoll_event.h}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \structd{epoll\_event}, che consente di specificare
+ gli eventi associati ad un file descriptor controllato con
+ \textit{epoll}.}
+ \label{fig:epoll_event}
+\end{figure}
+
+La struttura \struct{epoll\_event} è l'analoga di \struct{pollfd} e come
+quest'ultima serve sia in ingresso (quando usata con \func{epoll\_ctl}) ad
+impostare quali eventi osservare, che in uscita (nei risultati ottenuti con
+\func{epoll\_wait}) per ricevere le notifiche degli eventi avvenuti. La sua
+definizione è riportata in fig.~\ref{fig:epoll_event}.
+
+Il primo campo, \var{events}, è una maschera binaria in cui ciascun bit
+corrisponde o ad un tipo di evento, o una modalità di notifica; detto campo
+deve essere specificato come OR aritmetico delle costanti riportate in
+tab.~\ref{tab:epoll_events}. Il secondo campo, \var{data}, è una \direct{union}
+che serve a identificare il file descriptor a cui si intende fare riferimento,
+ed in astratto può contenere un valore qualsiasi (specificabile in diverse
+forme) che ne permetta una indicazione univoca. Il modo più comune di usarlo
+però è quello in cui si specifica il terzo argomento di \func{epoll\_ctl}
+nella forma \var{event.data.fd}, assegnando come valore di questo campo lo
+stesso valore dell'argomento \param{fd}, cosa che permette una immediata
+identificazione del file descriptor.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|p{8cm}|}
+ \hline
+ \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{EPOLLIN} & Il file è pronto per le operazioni di lettura
+ (analogo di \const{POLLIN}).\\
+ \const{EPOLLOUT} & Il file è pronto per le operazioni di scrittura
+ (analogo di \const{POLLOUT}).\\
+ \const{EPOLLRDHUP} & L'altro capo di un socket di tipo
+ \const{SOCK\_STREAM} (vedi sez.~\ref{sec:sock_type})
+ ha chiuso la connessione o il capo in scrittura
+ della stessa (vedi
+ sez.~\ref{sec:TCP_shutdown}).\footnotemark\\
+ \const{EPOLLPRI} & Ci sono \itindex{out-of-band} dati urgenti
+ disponibili in lettura (analogo di
+ \const{POLLPRI}); questa condizione viene comunque
+ riportata in uscita, e non è necessaria impostarla
+ in ingresso.\\
+ \const{EPOLLERR} & Si è verificata una condizione di errore
+ (analogo di \const{POLLERR}); questa condizione
+ viene comunque riportata in uscita, e non è
+ necessaria impostarla in ingresso.\\
+ \const{EPOLLHUP} & Si è verificata una condizione di hung-up; questa
+ condizione viene comunque riportata in uscita, e non
+ è necessaria impostarla in ingresso.\\
+ \const{EPOLLET} & Imposta la notifica in modalità \textit{edge
+ triggered} per il file descriptor associato.\\
+ \const{EPOLLONESHOT}& Imposta la modalità \textit{one-shot} per il file
+ descriptor associato.\footnotemark\\
+ \hline
+ \end{tabular}
+ \caption{Costanti che identificano i bit del campo \param{events} di
+ \struct{epoll\_event}.}
+ \label{tab:epoll_events}
+\end{table}
+
+\footnotetext{questa modalità è disponibile solo a partire dal kernel 2.6.17,
+ ed è utile per riconoscere la chiusura di una connessione dall'altro capo
+ quando si lavora in modalità \textit{edge triggered}.}
+
+\footnotetext[48]{questa modalità è disponibile solo a partire dal kernel
+ 2.6.2.}
+
+Le modalità di utilizzo di \textit{epoll} prevedono che si definisca qual'è
+l'insieme dei file descriptor da tenere sotto controllo tramite un certo
+\textit{epoll descriptor} \param{epfd} attraverso una serie di chiamate a
+\const{EPOLL\_CTL\_ADD}.\footnote{un difetto dell'interfaccia è che queste
+ chiamate devono essere ripetute per ciascun file descriptor, incorrendo in
+ una perdita di prestazioni qualora il numero di file descriptor sia molto
+ grande; per questo è stato proposto di introdurre come estensione una
+ funzione \func{epoll\_ctlv} che consenta di effettuare con una sola chiamata
+ le impostazioni per un blocco di file descriptor.} L'uso di
+\const{EPOLL\_CTL\_MOD} consente in seguito di modificare le modalità di
+osservazione di un file descriptor che sia già stato aggiunto alla lista di
+osservazione.
+
+Le impostazioni di default prevedono che la notifica degli eventi richiesti
+sia effettuata in modalità \textit{level triggered}, a meno che sul file
+descriptor non si sia impostata la modalità \textit{edge triggered},
+registrandolo con \const{EPOLLET} attivo nel campo \var{events}. Si tenga
+presente che è possibile tenere sotto osservazione uno stesso file descriptor
+su due \textit{epoll descriptor} diversi, ed entrambi riceveranno le
+notifiche, anche se questa pratica è sconsigliata.
+
+Qualora non si abbia più interesse nell'osservazione di un file descriptor lo
+si può rimuovere dalla lista associata a \param{epfd} con
+\const{EPOLL\_CTL\_DEL}; si tenga conto inoltre che i file descriptor sotto
+osservazione che vengono chiusi sono eliminati dalla lista automaticamente e
+non è necessario usare \const{EPOLL\_CTL\_DEL}.
+
+Infine una particolare modalità di notifica è quella impostata con
+\const{EPOLLONESHOT}: a causa dell'implementazione di \textit{epoll} infatti
+quando si è in modalità \textit{edge triggered} l'arrivo in rapida successione
+di dati in blocchi separati\footnote{questo è tipico con i socket di rete, in
+ quanto i dati arrivano a pacchetti.} può causare una generazione di eventi
+(ad esempio segnalazioni di dati in lettura disponibili) anche se la
+condizione è già stata rilevata.\footnote{si avrebbe cioè una rottura della
+ logica \textit{edge triggered}.}
+
+Anche se la situazione è facile da gestire, la si può evitare utilizzando
+\const{EPOLLONESHOT} per impostare la modalità \textit{one-shot}, in cui la
+notifica di un evento viene effettuata una sola volta, dopo di che il file
+descriptor osservato, pur restando nella lista di osservazione, viene
+automaticamente disattivato,\footnote{la cosa avviene contestualmente al
+ ritorno di \func{epoll\_wait} a causa dell'evento in questione.} e per
+essere riutilizzato dovrà essere riabilitato esplicitamente con una successiva
+chiamata con \const{EPOLL\_CTL\_MOD}.
+
+Una volta impostato l'insieme di file descriptor che si vogliono osservare con
+i relativi eventi, la funzione che consente di attendere l'occorrenza di uno
+di tali eventi è \funcd{epoll\_wait}, il cui prototipo è:
+\begin{prototype}{sys/epoll.h}
+ {int epoll\_wait(int epfd, struct epoll\_event * events, int maxevents, int
+ timeout)}
+
+ Attende che uno dei file descriptor osservati sia pronto.
+
+ \bodydesc{La funzione restituisce il numero di file descriptor pronti in
+ caso di successo o $-1$ in caso di errore, nel qual caso \var{errno}
+ assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EBADF}] il file descriptor \param{epfd} non è valido.
+ \item[\errcode{EFAULT}] il puntatore \param{events} non è valido.
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale prima
+ della scadenza di \param{timeout}.
+ \item[\errcode{EINVAL}] il file descriptor \param{epfd} non è stato ottenuto
+ con \func{epoll\_create}, o \param{maxevents} non è maggiore di zero.
+ \end{errlist}
+}
+\end{prototype}
+
+La funzione si blocca in attesa di un evento per i file descriptor registrati
+nella lista di osservazione di \param{epfd} fino ad un tempo massimo
+specificato in millisecondi tramite l'argomento \param{timeout}. Gli eventi
+registrati vengono riportati in un vettore di strutture \struct{epoll\_event}
+(che deve essere stato allocato in precedenza) all'indirizzo indicato
+dall'argomento \param{events}, fino ad un numero massimo di eventi impostato
+con l'argomento \param{maxevents}.
+
+La funzione ritorna il numero di eventi rilevati, o un valore nullo qualora
+sia scaduto il tempo massimo impostato con \param{timeout}. Per quest'ultimo,
+oltre ad un numero di millisecondi, si può utilizzare il valore nullo, che
+indica di non attendere e ritornare immediatamente,\footnote{anche in questo
+ caso il valore di ritorno sarà nullo.} o il valore $-1$, che indica
+un'attesa indefinita. L'argomento \param{maxevents} dovrà invece essere sempre
+un intero positivo.
+
+Come accennato la funzione restituisce i suoi risultati nel vettore di
+strutture \struct{epoll\_event} puntato da \param{events}; in tal caso nel
+campo \param{events} di ciascuna di esse saranno attivi i flag relativi agli
+eventi accaduti, mentre nel campo \var{data} sarà restituito il valore che era
+stato impostato per il file descriptor per cui si è verificato l'evento quando
+questo era stato registrato con le operazioni \const{EPOLL\_CTL\_MOD} o
+\const{EPOLL\_CTL\_ADD}, in questo modo il campo \var{data} consente di
+identificare il file descriptor.\footnote{ed è per questo che, come accennato,
+ è consuetudine usare per \var{data} il valore del file descriptor stesso.}
+
+Si ricordi che le occasioni per cui \func{epoll\_wait} ritorna dipendono da
+come si è impostata la modalità di osservazione (se \textit{level triggered} o
+\textit{edge triggered}) del singolo file descriptor. L'interfaccia assicura
+che se arrivano più eventi fra due chiamate successive ad \func{epoll\_wait}
+questi vengano combinati. Inoltre qualora su un file descriptor fossero
+presenti eventi non ancora notificati, e si effettuasse una modifica
+dell'osservazione con \const{EPOLL\_CTL\_MOD}, questi verrebbero riletti alla
+luce delle modifiche.
+
+Si tenga presente infine che con l'uso della modalità \textit{edge triggered}
+il ritorno di \func{epoll\_wait} indica che un file descriptor è pronto e
+resterà tale fintanto che non si sono completamente esaurite le operazioni su
+di esso. Questa condizione viene generalmente rilevata dall'occorrere di un
+errore di \errcode{EAGAIN} al ritorno di una \func{read} o una
+\func{write},\footnote{è opportuno ricordare ancora una volta che l'uso
+ dell'\textit{I/O multiplexing} richiede di operare sui file in modalità non
+ bloccante.} ma questa non è la sola modalità possibile, ad esempio la
+condizione può essere riconosciuta anche per il fatto che sono stati
+restituiti meno dati di quelli richiesti.
+
+Come già per \func{select} e \func{poll} anche per l'interfaccia di
+\textit{epoll} si pone il problema di gestire l'attesa di segnali e di dati
+contemporaneamente per le osservazioni fatte in sez.~\ref{sec:file_select},
+per fare questo di nuovo è necessaria una variante della funzione di attesa
+che consenta di reimpostare all'uscita una maschera di segnali, analoga alle
+estensioni \func{pselect} e \func{ppoll} che abbiamo visto in precedenza per
+\func{select} e \func{poll}; in questo caso la funzione si chiama
+\funcd{epoll\_pwait}\footnote{la funziona è stata introdotta a partire dal
+ kernel 2.6.19, ed è come tutta l'interfaccia di \textit{epoll}, specifica di
+ Linux.} ed il suo prototipo è:
+\begin{prototype}{sys/epoll.h}
+ {int epoll\_pwait(int epfd, struct epoll\_event * events, int maxevents,
+ int timeout, const sigset\_t *sigmask)}
+
+ Attende che uno dei file descriptor osservati sia pronto, mascherando i
+ segnali.
+
+ \bodydesc{La funzione restituisce il numero di file descriptor pronti in
+ caso di successo o $-1$ in caso di errore, nel qual caso \var{errno}
+ assumerà uno dei valori già visti con \funcd{epoll\_wait}.
+}
+\end{prototype}
+
+La funzione è del tutto analoga \funcd{epoll\_wait}, soltanto che alla sua
+uscita viene ripristinata la maschera di segnali originale, sostituita durante
+l'esecuzione da quella impostata con l'argomento \param{sigmask}; in sostanza
+la chiamata a questa funzione è equivalente al seguente codice, eseguito però
+in maniera atomica:
+\includecodesnip{listati/epoll_pwait_means.c}
+
+Si tenga presente che come le precedenti funzioni di \textit{I/O multiplexing}
+anche le funzioni dell'interfaccia di \textit{epoll} vengono utilizzate
+prevalentemente con i server di rete, quando si devono tenere sotto
+osservazione un gran numero di socket; per questo motivo rimandiamo anche in
+questo caso la trattazione di un esempio concreto a quando avremo esaminato in
+dettaglio le caratteristiche dei socket; in particolare si potrà trovare un
+programma che utilizza questa interfaccia in sez.~\ref{sec:TCP_serv_epoll}.
+
+\itindend{epoll}
+
+
+\subsection{La notifica di eventi tramite file descriptor}
+\label{sec:sig_signalfd_eventfd}
+
+Abbiamo visto in sez.~\ref{sec:file_select} come il meccanismo classico delle
+notifiche di eventi tramite i segnali, presente da sempre nei sistemi
+unix-like, porti a notevoli problemi nell'interazione con le funzioni per
+l'\textit{I/O multiplexing}, tanto che per evitare possibili
+\itindex{race~condition} \textit{race condition} sono state introdotte
+estensioni dello standard POSIX e funzioni apposite come \func{pselect},
+\func{ppoll} e \funcd{epoll\_pwait}.
+
+Benché i segnali siano il meccanismo più usato per effettuare notifiche ai
+processi, la loro interfaccia di programmazione, che comporta l'esecuzione di
+una funzione di gestione in maniera asincrona e totalmente scorrelata
+dall'ordinario flusso di esecuzione del processo, si è però dimostrata quasi
+subito assai problematica. Oltre ai limiti relativi ai limiti al cosa si può
+fare all'interno della funzione del gestore di segnali (quelli illustrati in
+sez.~\ref{sec:sig_signal_handler}), c'è il problema più generale consistente
+nel fatto che questa modalità di funzionamento cozza con altre interfacce di
+programmazione previste dal sistema in cui si opera in maniera
+\textsl{sincrona}, come quelle dell'I/O multiplexing appena illustrate.
+
+In questo tipo di interfacce infatti ci si aspetta che il processo gestisca
+gli eventi a cui vuole rispondere in maniera sincrona generando le opportune
+risposte, mentre con l'arrivo di un segnale si possono avere interruzioni
+asincrone in qualunque momento. Questo comporta la necessità di dover
+gestire, quando si deve tener conto di entrambi i tipi di eventi, le
+interruzioni delle funzioni di attesa sincrone, ed evitare possibili
+\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.}
+
+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
+sincrona dei segnali con la funzione \func{sigwait} e le sue affini. Queste
+funzioni consentono di gestire i segnali bloccando un processo fino alla
+avvenuta ricezione e disabilitando l'esecuzione asincrona rispetto al resto
+del programma del gestore del segnale. Questo consente di risolvere i problemi
+di atomicità nella gestione degli eventi associati ai segnali, avendo tutto il
+controllo nel flusso principale del programma, ottenendo così una gestione
+simile a quella dell'\textit{I/O multiplexing}, ma non risolve i problemi
+delle interazioni con quest'ultimo, perché o si aspetta la ricezione di un
+segnale o si aspetta che un file descriptor sia accessibile e nessuna delle
+rispettive funzioni consente di fare contemporaneamente entrambe le cose.
+
+Per risolvere questo problema nello sviluppo del kernel si è pensato di
+introdurre un meccanismo alternativo per la notifica dei segnali (esteso anche
+ad altri eventi generici) che, ispirandosi di nuovo alla filosofia di Unix per
+cui tutto è un file, consentisse di eseguire la notifica con l'uso di
+opportuni file descriptor.\footnote{ovviamente si tratta di una funzionalità
+ specifica di Linux, non presente in altri sistemi unix-like, e non prevista
+ da nessuno standard, per cui va evitata se si ha a cuore la portabilità.}
+
+In sostanza, come per \func{sigwait}, si può disabilitare l'esecuzione di un
+gestore in occasione dell'arrivo di un segnale, e rilevarne l'avvenuta
+ricezione leggendone la notifica tramite l'uso di uno speciale file
+descriptor. Trattandosi di un file descriptor questo potrà essere tenuto sotto
+osservazione con le ordinarie funzioni dell'\textit{I/O multiplexing} (vale a
+dire con le solite \func{select}, \func{poll} e \funcd{epoll\_wait}) allo
+stesso modo di quelli associati a file o socket, per cui alla fine si potrà
+attendere in contemporanea sia l'arrivo del segnale che la disponibilità di
+accesso ai dati relativi a questi ultimi.
+
+La funzione che permette di abilitare la ricezione dei segnali tramite file
+descriptor è \funcd{signalfd},\footnote{in realtà quella riportata è
+ l'interfaccia alla funzione fornita dalle \acr{glibc}, esistono infatti due
+ versioni diverse della \textit{system call}; una prima versione,
+ \func{signalfd}, introdotta nel kernel 2.6.22 e disponibile con le
+ \acr{glibc} 2.8 che non supporta l'argomento \texttt{flags}, ed una seconda
+ versione, \func{signalfd4}, introdotta con il kernel 2.6.27 e che è quella
+ che viene sempre usata a partire dalle \acr{glibc} 2.9, che prende un
+ argomento aggiuntivo \code{size\_t sizemask} che indica la dimensione della
+ maschera dei segnali, il cui valore viene impostato automaticamente dalle
+ \acr{glibc}.} il cui prototipo è:
+\begin{prototype}{sys/signalfd.h}
+ {int signalfd(int fd, const sigset\_t *mask, int flags)}
+
+ Crea o modifica un file descriptor per la ricezione dei segnali.
+
+ \bodydesc{La funzione restituisce un numero di file descriptor in caso di
+ successo o $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno
+ dei valori:
+ \begin{errlist}
+ \item[\errcode{EBADF}] il valore \param{fd} non indica un file descriptor.
+ \item[\errcode{EINVAL}] il file descriptor \param{fd} non è stato ottenuto
+ con \func{signalfd} o il valore di \param{flags} non è valido.
+ \item[\errcode{ENOMEM}] non c'è memoria sufficiente per creare un nuovo file
+ descriptor di \func{signalfd}.
+ \item[\errcode{ENODEV}] il kernel non può montare internamente il
+ dispositivo per la gestione anonima degli inode associati al file
+ descriptor.
+ \end{errlist}
+ ed inoltre \errval{EMFILE} e \errval{ENFILE}.
+}
+\end{prototype}
+
+La funzione consente di creare o modificare le caratteristiche di un file
+descriptor speciale su cui ricevere le notifiche della ricezione di
+segnali. Per creare ex-novo uno di questi file descriptor è necessario passare
+$-1$ come valore per l'argomento \param{fd}, ogni altro valore positivo verrà
+invece interpretato come il numero del file descriptor (che deve esser stato
+precedentemente creato sempre con \func{signalfd}) di cui si vogliono
+modificare le caratteristiche. Nel primo caso la funzione ritornerà il valore
+del nuovo file descriptor e nel secondo caso il valore indicato
+con \param{fd}, in caso di errore invece verrà restituito $-1$.
+
+L'elenco dei segnali che si vogliono gestire con \func{signalfd} deve essere
+specificato tramite l'argomento \param{mask}. Questo deve essere passato come
+puntatore ad una maschera di segnali creata con l'uso delle apposite macro già
+illustrate in sez.~\ref{sec:sig_sigset}. La maschera deve indicare su quali
+segnali si intende operare con \func{signalfd}; l'elenco può essere modificato
+con una successiva chiamata a \func{signalfd}. Dato che \signal{SIGKILL} e
+\signal{SIGSTOP} non possono essere intercettati (e non prevedono neanche la
+possibilità di un gestore) un loro inserimento nella maschera verrà ignorato
+senza generare errori.
+
+L'argomento \param{flags} consente di impostare direttamente in fase di
+creazione due flag per il file descriptor analoghi a quelli che si possono
+impostare con una creazione ordinaria con \func{open}, evitando una
+impostazione successiva con \func{fcntl}.\footnote{questo è un argomento
+ aggiuntivo, introdotto con la versione fornita a partire dal kernel 2.6.27,
+ per kernel precedenti il valore deve essere nullo.} L'argomento deve essere
+specificato come maschera binaria dei valori riportati in
+tab.~\ref{tab:signalfd_flags}.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|p{8cm}|}
+ \hline
+ \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{SFD\_NONBLOCK}& imposta sul file descriptor il flag di
+ \const{O\_NONBLOCK} per renderlo non bloccante.\\
+ \const{SFD\_CLOEXEC}& imposta il flag di \const{O\_CLOEXEC} per la
+ chiusura automatica del file descriptor nella
+ esecuzione di \func{exec}.\\
+ \hline
+ \end{tabular}
+ \caption{Valori dell'argomento \param{flags} per la funzione \func{signalfd}
+ che consentono di impostare i flag del file descriptor.}
+ \label{tab:signalfd_flags}
+\end{table}
+
+Si tenga presente che la chiamata a \func{signalfd} non disabilita la gestione
+ordinaria dei segnali indicati da \param{mask}; questa, se si vuole effettuare
+la ricezione tramite il file descriptor, dovrà essere disabilitata
+esplicitamente bloccando gli stessi segnali con \func{sigprocmask}, altrimenti
+verranno comunque eseguite le azioni di default (o un eventuale gestore
+installato in precedenza).\footnote{il blocco non ha invece nessun effetto sul
+ file descriptor restituito da \func{signalfd}, dal quale sarà possibile
+ pertanto ricevere qualunque segnale, anche se questo risultasse bloccato.}
+Si tenga presente inoltre che la lettura di una struttura
+\struct{signalfd\_siginfo} relativa ad un segnale pendente è equivalente alla
+esecuzione di un gestore, vale a dire che una volta letta il segnale non sarà
+più pendente e non potrà essere ricevuto, qualora si ripristino le normali
+condizioni di gestione, né da un gestore né dalla funzione \func{sigwaitinfo}.
+
+Come anticipato, essendo questo lo scopo principale della nuova interfaccia,
+il file descriptor può essere tenuto sotto osservazione tramite le funzioni
+dell'\textit{I/O multiplexing} (vale a dire con le solite \func{select},
+\func{poll} e \funcd{epoll\_wait}), e risulterà accessibile in lettura quando
+uno o più dei segnali indicati tramite \param{mask} sarà pendente.
+
+La funzione può essere chiamata più volte dallo stesso processo, consentendo
+così di tenere sotto osservazione segnali diversi tramite file descriptor
+diversi. Inoltre è anche possibile tenere sotto osservazione lo stesso segnale
+con più file descriptor, anche se la pratica è sconsigliata; in tal caso la
+ricezione del segnale potrà essere effettuata con una lettura da uno qualunque
+dei file descriptor a cui è associato, ma questa potrà essere eseguita
+soltanto una volta.\footnote{questo significa che tutti i file descriptor su
+ cui è presente lo stesso segnale risulteranno pronti in lettura per le
+ funzioni di \textit{I/O multiplexing}, ma una volta eseguita la lettura su
+ uno di essi il segnale sarà considerato ricevuto ed i relativi dati non
+ saranno più disponibili sugli altri file descriptor, che (a meno di una
+ ulteriore occorrenza del segnale nel frattempo) di non saranno più pronti.}
+
+Quando il file descriptor per la ricezione dei segnali non serve più potrà
+essere chiuso con \func{close} liberando tutte le risorse da esso allocate. In
+tal caso qualora vi fossero segnali pendenti questi resteranno tali, e
+potranno essere ricevuti normalmente una volta che si rimuova il blocco
+imposto con \func{sigprocmask}.
+
+Oltre che con le funzioni dell'\textit{I/O multiplexing} l'uso del file
+descriptor restituito da \func{signalfd} cerca di seguire la semantica di un
+sistema unix-like anche con altre \textit{system call}; in particolare esso
+resta aperto (come ogni altro file descriptor) attraverso una chiamata ad
+\func{exec}, a meno che non lo si sia creato con il flag di
+\const{SFD\_CLOEXEC} o si sia successivamente impostato il
+\textit{close-on-exec} con \func{fcntl}. Questo comportamento corrisponde
+anche alla ordinaria semantica relativa ai segnali bloccati, che restano
+pendenti attraverso una \func{exec}.
+
+Analogamente il file descriptor resta sempre disponibile attraverso una
+\func{fork} per il processo figlio, che ne riceve una copia; in tal caso però
+il figlio potrà leggere dallo stesso soltanto i dati relativi ai segnali
+ricevuti da lui stesso. Nel caso di \textit{thread} viene nuovamente seguita
+la semantica ordinaria dei segnali, che prevede che un singolo \textit{thread}
+possa ricevere dal file descriptor solo le notifiche di segnali inviati
+direttamente a lui o al processo in generale, e non quelli relativi ad altri
+\textit{thread} appartenenti allo stesso processo.
+
+L'interfaccia fornita da \func{signalfd} prevede che la ricezione dei segnali
+sia eseguita leggendo i dati relativi ai segnali pendenti dal file descriptor
+restituito dalla funzione con una normalissima \func{read}. Qualora non vi
+siano segnali pendenti la \func{read} si bloccherà a meno di non aver
+impostato la modalità di I/O non bloccante sul file descriptor, o direttamente
+in fase di creazione con il flag \const{SFD\_NONBLOCK}, o in un momento
+successivo con \func{fcntl}.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{\textwidth}
+ \includestruct{listati/signalfd_siginfo.h}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \structd{signalfd\_siginfo}, restituita in lettura da
+ un file descriptor creato con \func{signalfd}.}
+ \label{fig:signalfd_siginfo}
+\end{figure}
+
+I dati letti dal file descriptor vengono scritti sul buffer indicato come
+secondo argomento di \func{read} nella forma di una sequenza di una o più
+strutture \struct{signalfd\_siginfo} (la cui definizione si è riportata in
+fig.~\ref{fig:signalfd_siginfo}) a seconda sia della dimensione del buffer che
+del numero di segnali pendenti. Per questo motivo il buffer deve essere almeno
+di dimensione pari a quella di \struct{signalfd\_siginfo}, qualora sia di
+dimensione maggiore potranno essere letti in unica soluzione i dati relativi
+ad eventuali più segnali pendenti, fino al numero massimo di strutture
+\struct{signalfd\_siginfo} che possono rientrare nel buffer.
+
+Il contenuto di \struct{signalfd\_siginfo} ricalca da vicino quella della
+analoga struttura \struct{siginfo\_t} (illustrata in
+fig.~\ref{fig:sig_siginfo_t}) usata dall'interfaccia ordinaria dei segnali, e
+restituisce dati simili. Come per \struct{siginfo\_t} i campi che vengono
+avvalorati dipendono dal tipo di segnale e ricalcano i valori che abbiamo già
+illustrato in sez.~\ref{sec:sig_sigaction}.\footnote{si tenga presente però
+ che per un bug i kernel fino al 2.6.25 non avvalorano correttamente i campi
+ \var{ssi\_ptr} e \var{ssi\_int} per segnali inviati con \func{sigqueue}.}
+
+Come esempio di questa nuova interfaccia ed anche come esempio di applicazione
+della interfaccia di \itindex{epoll} \textit{epoll}, si è scritto un programma
+elementare che stampi sullo standard output sia quanto viene scritto da terzi
+su una \textit{named fifo}, che l'avvenuta ricezione di alcuni segnali. Il
+codice completo si trova al solito nei sorgenti allegati alla guida (nel file
+\texttt{FifoReporter.c}).
+
+In fig.~\ref{fig:fiforeporter_code_init} si è riportata la parte iniziale del
+programma in cui vengono effettuate le varie inizializzazioni necessarie per
+l'uso di \itindex{epoll} \textit{epoll} e \func{signalfd}, a partire
+(\texttt{\small 12--16}) dalla definizione delle varie variabili e strutture
+necessarie. Al solito si è tralasciata la parte dedicata alla decodifica delle
+opzioni che consentono ad esempio di cambiare il nome del file associato alla
+fifo.
+
+\begin{figure}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/FifoReporter-init.c}
+ \end{minipage}
+ \normalsize
+ \caption{Sezione di inizializzazione del codice del programma
+ \file{FifoReporter.c}.}
+ \label{fig:fiforeporter_code_init}
+\end{figure}
+
+Il primo passo (\texttt{\small 19--20}) è la crezione di un file descriptor
+\texttt{epfd} di \itindex{epoll} \textit{epoll} con \func{epoll\_create} che è
+quello che useremo per il controllo degli altri. É poi necessario
+disabilitare la ricezione dei segnali (nel caso \signal{SIGINT},
+\signal{SIGQUIT} e \signal{SIGTERM}) per i quali si vuole la notifica tramite
+file descriptor. Per questo prima li si inseriscono (\texttt{\small 22--25}) in
+una maschera di segnali \texttt{sigmask} che useremo con (\texttt{\small 26})
+\func{sigprocmask} per disabilitarli. Con la stessa maschera si potrà per
+passare all'uso (\texttt{\small 28--29}) di \func{signalfd} per abilitare la
+notifica sul file descriptor \var{sigfd}. Questo poi (\texttt{\small 30--33})
+dovrà essere aggiunto con \func{epoll\_ctl} all'elenco di file descriptor
+controllati con \texttt{epfd}.
+
+Occorrerà infine (\texttt{\small 35--38}) creare la \textit{named fifo} se
+questa non esiste ed aprirla per la lettura (\texttt{\small 39--40}); una
+volta fatto questo sarà necessario aggiungere il relativo file descriptor
+(\var{fifofd}) a quelli osservati da \itindex{epoll} \textit{epoll} in maniera
+del tutto analoga a quanto fatto con quello relativo alla notifica dei
+segnali.
+
+\begin{figure}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/FifoReporter-main.c}
+ \end{minipage}
+ \normalsize
+ \caption{Ciclo principale del codice del programma \file{FifoReporter.c}.}
+ \label{fig:fiforeporter_code_body}
+\end{figure}
+
+Una volta completata l'inizializzazione verrà eseguito indefinitamente il
+ciclo principale del programma (\texttt{\small 2--45}) che si è riportato in
+fig.~\ref{fig:fiforeporter_code_body}, fintanto che questo non riceva un
+segnale di \texttt{SIGINT} (ad esempio con la pressione di \texttt{C-c}). Il
+ciclo prevede che si attenda (\texttt{\small 2--3}) la presenza di un file
+descriptor pronto in lettura con \func{epoll\_wait},\footnote{si ricordi che
+ entrambi i file descriptor \var{fifofd} e \var{sigfd} sono stati posti in
+ osservazioni per eventi di tipo \const{EPOLLIN}.} che si bloccherà fintanto
+che non siano stati scritti dati sulla fifo o che non sia arrivato un
+segnale.\footnote{per semplificare il codice non si è trattato il caso in cui
+ \func{epoll\_wait} viene interrotta da un segnale, assumendo che tutti
+ quelli che possano interessare siano stati predisposti per la notifica
+ tramite file descriptor, per gli altri si otterrà semplicemente l'uscita dal
+ programma.}
+
+Anche se in questo caso i file descriptor pronti possono essere al più due, si
+è comunque adottato un approccio generico in cui questi verranno letti
+all'interno di un opportuno ciclo (\texttt{\small 5--44}) sul numero
+restituito da \func{epoll\_wait}, esaminando i risultati presenti nel vettore
+\var{events} all'interno di una catena di condizionali alternativi sul valore
+del file descriptor riconosciuto come pronto.\footnote{controllando cioè a
+ quale dei due file descriptor possibili corrisponde il campo relativo,
+ \var{events[i].data.fd}.}
+
+Il primo condizionale (\texttt{\small 6--24}) è relativo al caso che si sia
+ricevuto un segnale e che il file descriptor pronto corrisponda
+(\texttt{\small 6}) a \var{sigfd}. Dato che in generale si possono ricevere
+anche notifiche relativi a più di un singolo segnale, si è scelto di leggere
+una struttura \const{signalfd\_siginfo} alla volta, eseguendo la lettura
+all'interno di un ciclo (\texttt{\small 8--24}) che prosegue fintanto che vi
+siano dati da leggere.
+
+Per questo ad ogni lettura si esamina (\texttt{\small 9--14}) se il valore di
+ritorno della funzione \func{read} è negativo, uscendo dal programma
+(\texttt{\small 11}) in caso di errore reale, o terminando il ciclo
+(\texttt{\small 13}) con un \texttt{break} qualora si ottenga un errore di
+\errcode{EAGAIN} per via dell'esaurimento dei dati.\footnote{si ricordi come
+ sia la fifo che il file descriptor per i segnali siano stati aperti in
+ modalità non-bloccante, come previsto per l’\textit{I/O multiplexing},
+ pertanto ci si aspetta di ricevere un errore di \errcode{EAGAIN} quando non
+ vi saranno più dati da leggere.}
+
+In presenza di dati invece il programma proseguirà l'esecuzione stampando
+(\texttt{\small 19--20}) il nome del segnale ottenuto all'interno della
+struttura \const{signalfd\_siginfo} letta in \var{siginf}\footnote{per la
+ stampa si è usato il vettore \var{sig\_names} a ciascun elemento del quale
+ corrisponde il nome del segnale avente il numero corrispondente, la cui
+ definizione si è omessa dal codice di fig.~\ref{fig:fiforeporter_code_init}
+ per brevità.} ed il \textit{pid} del processo da cui lo ha ricevuto; inoltre
+(\texttt{\small 21--24}) si controllerà anche se il segnale ricevuto è
+\var{SIGINT}, che si è preso come segnale da utilizzare per la terminazione
+del programma, che verrà eseguita dopo aver rimosso il file della \textit{name
+ fifo}.
+
+Il secondo condizionale (\texttt{\small 26--39}) è invece relativo al caso in
+cui ci siano dati pronti in lettura sulla fifo e che il file descriptor pronto
+corrisponda (\texttt{\small 26}) a \var{fifofd}. Di nuovo si effettueranno le
+letture in un ciclo (\texttt{\small 28--39}) ripetendole fin tanto che la
+funzione \func{read} non resituisce un errore di \errcode{EAGAIN}
+(\texttt{\small 29--35}).\footnote{il procedimento è lo stesso adottato per il
+ file descriptor associato al segnale, in cui si esce dal programma in caso
+ di errore reale, in questo caso però alla fine dei dati prima di uscire si
+ stampa anche (\texttt{\small 32}) un messaggio di chiusura.} Se invece vi
+sono dati validi letti dalla fifo si inserirà (\texttt{\small 36}) una
+terminazione di stringa sul buffer e si stamperà il tutto (\texttt{\small
+ 37--38}) sullo \textit{standard output}. L'ultimo condizionale
+(\texttt{\small 40--44}) è semplicemente una condizione di cattura per una
+eventualità che comunque non dovrebbe mai verificarsi, e che porta alla uscita
+dal programma con una opportuna segnalazione di errore.
+
+A questo punto si potrà eseguire il comando lanciandolo su un terminale, ed
+osservarne le reazioni agli eventi generati da un altro terminale; lanciando
+il programma otterremo qualcosa del tipo:
+\begin{Verbatim}
+piccardi@hain:~/gapil/sources$ ./a.out
+FifoReporter starting, pid 4568
+\end{Verbatim}
+%$
+e scrivendo qualcosa sull'altro terminale con:
+\begin{Verbatim}
+root@hain:~# echo prova > /tmp/reporter.fifo
+\end{Verbatim}
+si otterrà:
+\begin{Verbatim}
+Message from fifo:
+prova
+end message
+\end{Verbatim}
+mentre inviando un segnale:
+\begin{Verbatim}
+root@hain:~# kill 4568
+\end{Verbatim}
+si avrà:
+\begin{Verbatim}
+Signal received:
+Got SIGTERM
+From pid 3361
+\end{Verbatim}
+ed infine premendo \texttt{C-\bslash} sul terminale in cui è in esecuzione si
+vedrà:
+\begin{Verbatim}
+^\Signal received:
+Got SIGQUIT
+From pid 0
+\end{Verbatim}
+e si potrà far uscire il programma con \texttt{C-c} ottenendo:
+\begin{Verbatim}
+^CSignal received:
+Got SIGINT
+From pid 0
+SIGINT means exit
+\end{Verbatim}
+
+
+Lo stesso paradigma di notifica tramite file descriptor usato per i segnali è
+stato adottato anche per i timer. In questo caso, rispetto a quanto visto in
+sez.~\ref{sec:sig_timer_adv}, la scadenza di un timer potrà essere letta da un
+file descriptor senza dover ricorrere ad altri meccanismi di notifica come un
+segnale o un \textit{thread}. Di nuovo questo ha il vantaggio di poter
+utilizzare le funzioni dell'\textit{I/O multiplexing} per attendere allo
+stesso tempo la disponibilità di dati o la ricezione della scadenza di un
+timer.\footnote{in realtà per questo sarebbe già sufficiente \func{signalfd}
+ per ricevere i segnali associati ai timer, ma la nuova interfaccia
+ semplifica notevolmente la gestione e consente di fare tutto con una sola
+ \textit{system call}.}
+
+Le funzioni di questa nuova interfaccia ricalcano da vicino la struttura delle
+analoghe versioni ordinarie introdotte con lo standard POSIX.1-2001, che
+abbiamo già illustrato in sez.~\ref{sec:sig_timer_adv}.\footnote{questa
+ interfaccia è stata introdotta in forma considerata difettosa con il kernel
+ 2.6.22, per cui è stata immediatamente tolta nel successivo 2.6.23 e
+ reintrodotta in una forma considerata adeguata nel kernel 2.6.25, il
+ supporto nelle \acr{glibc} è stato introdotto a partire dalla versione
+ 2.8.6, la versione del kernel 2.6.22, presente solo su questo kernel, non è
+ supportata e non deve essere usata.} La prima funzione prevista, quella che
+consente di creare un timer, è \funcd{timerfd\_create}, il cui prototipo è:
+\begin{prototype}{sys/timerfd.h}
+ {int timerfd\_create(int clockid, int flags)}
+
+ Crea un timer associato ad un file descriptor per la notifica.
+
+ \bodydesc{La funzione restituisce un numero di file descriptor in caso di
+ successo o $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno
+ dei valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] l'argomento \param{clockid} non è
+ \const{CLOCK\_MONOTONIC} o \const{CLOCK\_REALTIME}, o
+ l'argomento \param{flag} non è valido, o è diverso da zero per kernel
+ precedenti il 2.6.27.
+ \item[\errcode{ENOMEM}] non c'è memoria sufficiente per creare un nuovo file
+ descriptor di \func{signalfd}.
+ \item[\errcode{ENODEV}] il kernel non può montare internamente il
+ dispositivo per la gestione anonima degli inode associati al file
+ descriptor.
+ \end{errlist}
+ ed inoltre \errval{EMFILE} e \errval{ENFILE}.
+}
+\end{prototype}
+
+La funzione prende come primo argomento un intero che indica il tipo di
+orologio a cui il timer deve fare riferimento, i valori sono gli stessi delle
+funzioni dello standard POSIX-1.2001 già illustrati in
+tab.~\ref{tab:sig_timer_clockid_types}, ma al momento i soli utilizzabili sono
+\const{CLOCK\_REALTIME} e \const{CLOCK\_MONOTONIC}. L'argomento \param{flags},
+come l'analogo di \func{signalfd}, consente di impostare i flag per l'I/O non
+bloccante ed il \textit{close-on-exec} sul file descriptor
+restituito,\footnote{esso è stato introdotto a partire dal kernel 2.6.27, per
+ le versioni precedenti deve essere passato un valore nullo.} e deve essere
+specificato come una maschera binaria delle costanti riportate in
+tab.~\ref{tab:timerfd_flags}.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|p{8cm}|}
+ \hline
+ \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{TFD\_NONBLOCK}& imposta sul file descriptor il flag di
+ \const{O\_NONBLOCK} per renderlo non bloccante.\\
+ \const{TFD\_CLOEXEC}& imposta il flag di \const{O\_CLOEXEC} per la
+ chiusura automatica del file descriptor nella
+ esecuzione di \func{exec}.\\
+ \hline
+ \end{tabular}
+ \caption{Valori dell'argomento \param{flags} per la funzione
+ \func{timerfd\_create} che consentono di impostare i flag del file
+ descriptor.}
+ \label{tab:timerfd_flags}
+\end{table}
+
+In caso di successo la funzione restituisce un file descriptor sul quale
+verranno notificate le scadenze dei timer. Come per quelli restituiti da
+\func{signalfd} anche questo file descriptor segue la semantica dei sistemi
+unix-like, in particolare resta aperto attraverso una \func{exec},\footnote{a
+ meno che non si sia impostato il flag di \textit{close-on exec} con
+ \const{TFD\_CLOEXEC}.} e viene duplicato attraverso una \func{fork}; questa
+ultima caratteristica comporta però che anche il figlio può utilizzare i dati
+di un timer creato nel padre, a differenza di quanto avviene invece con i
+timer impostati con le funzioni ordinarie.\footnote{si ricordi infatti che,
+ come illustrato in sez.~\ref{sec:proc_fork}, allarmi, timer e segnali
+ pendenti nel padre vengono cancellati per il figlio dopo una \func{fork}.}
+
+Una volta creato il timer con \func{timerfd\_create} per poterlo utilizzare
+occorre \textsl{armarlo} impostandone un tempo di scadenza ed una eventuale
+periodicità di ripetizione, per farlo si usa la funzione omologa di
+\func{timer\_settime} per la nuova interfaccia; questa è
+\funcd{timerfd\_settime} ed il suo prototipo è:
+\begin{prototype}{sys/timerfd.h}
+ {int timerfd\_settime(int fd, int flags,
+ const struct itimerspec *new\_value,
+ struct itimerspec *old\_value)}
+
+ Crea un timer associato ad un file descriptor per la notifica.
+
+ \bodydesc{La funzione restituisce un numero di file descriptor in caso di
+ successo o $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno
+ dei valori:
+ \begin{errlist}
+ \item[\errcode{EBADF}] l'argomento \param{fd} non corrisponde ad un file
+ descriptor.
+ \item[\errcode{EINVAL}] il file descriptor \param{fd} non è stato ottenuto
+ con \func{timerfd\_create}, o i valori di \param{flag} o dei campi
+ \var{tv\_nsec} in \param{new\_value} non sono validi.
+ \item[\errcode{EFAULT}] o \param{new\_value} o \param{old\_value} non sono
+ puntatori validi.
+ \end{errlist}
+}
+\end{prototype}
+
+In questo caso occorre indicare su quale timer si intende operare specificando
+come primo argomento il file descriptor ad esso associato, che deve essere
+stato ottenuto da una precedente chiamata a \func{timerfd\_create}. I restanti
+argomenti sono del tutto analoghi a quelli della omologa funzione
+\func{timer\_settime}, e prevedono l'uso di strutture \struct{itimerspec}
+(vedi fig.~\ref{fig:struct_itimerspec}) per le indicazioni di temporizzazione.
+
+I valori ed il significato di questi argomenti sono gli stessi che sono già
+stati illustrati in dettaglio in sez.~\ref{sec:sig_timer_adv} e non staremo a
+ripetere quanto detto in quell'occasione;\footnote{per brevità si ricordi che
+ con \param{new\_value.it\_value} si indica la prima scadenza del timer e
+ con \param{new\_value.it\_interval} la sua periodicità.} l'unica differenza
+riguarda l'argomento \param{flags} che serve sempre ad indicare se il tempo di
+scadenza del timer è da considerarsi relativo o assoluto rispetto al valore
+corrente dell'orologio associato al timer, ma che in questo caso ha come
+valori possibili rispettivamente soltanto $0$ e
+\const{TFD\_TIMER\_ABSTIME}.\footnote{anche questo valore, che è l'analogo di
+ \const{TIMER\_ABSTIME} è l'unico attualmente possibile per \param{flags}.}
+
+L'ultima funzione prevista dalla nuova interfaccia è \funcd{timerfd\_gettime},
+che è l'analoga di \func{timer\_gettime}, il suo prototipo è:
+\begin{prototype}{sys/timerfd.h}
+ {int timerfd\_gettime(int fd, struct itimerspec *curr\_value)}
+
+ Crea un timer associato ad un file descriptor per la notifica.
+
+ \bodydesc{La funzione restituisce un numero di file descriptor in caso di
+ successo o $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno
+ dei valori:
+ \begin{errlist}
+ \item[\errcode{EBADF}] l'argomento \param{fd} non corrisponde ad un file
+ descriptor.
+ \item[\errcode{EINVAL}] il file descriptor \param{fd} non è stato ottenuto
+ con \func{timerfd\_create}.
+ \item[\errcode{EFAULT}] o \param{curr\_value} non è un puntatore valido.
+ \end{errlist}
+}
+\end{prototype}
+
+
+
+
+
+Questo infatti diverrà pronto in lettura per tutte le varie funzioni dell'I/O
+multiplexing in presenza di una o più scadenze del timer ad esso associato.
+
+Inoltre sarà possibile ottenere il numero di volte che il timer è scaduto
+dalla ultima impostazione
+
+che può essere
+usato per leggere le notifiche delle scadenze dei timer. Queste possono essere
+ottenute leggendo in maniera ordinaria il file descriptor con una \func{read},
+
+
+
+
+% TODO trattare qui eventfd, timerfd introdotte con il 2.6.22
+% timerfd è stata tolta nel 2.6.23 e rifatta per bene nel 2.6.25
+% vedi: http://lwn.net/Articles/233462/
+% http://lwn.net/Articles/245533/
+% http://lwn.net/Articles/267331/
+
+
+\section{L'accesso \textsl{asincrono} ai file}
+\label{sec:file_asyncronous_access}
+
+Benché l'\textit{I/O multiplexing} sia stata la prima, e sia tutt'ora una fra
+le più diffuse modalità di gestire l'I/O in situazioni complesse in cui si
+debba operare su più file contemporaneamente, esistono altre modalità di
+gestione delle stesse problematiche. In particolare sono importanti in questo
+contesto le modalità di accesso ai file eseguibili in maniera
+\textsl{asincrona}, quelle cioè in cui un processo non deve bloccarsi in
+attesa della disponibilità dell'accesso al file, ma può proseguire
+nell'esecuzione utilizzando invece un meccanismo di notifica asincrono (di
+norma un segnale, ma esistono anche altre interfacce, come \itindex{inotify}
+\textit{inotify}), per essere avvisato della possibilità di eseguire le
+operazioni di I/O volute.
+
+
+\subsection{Il \textit{Signal driven I/O}}
+\label{sec:file_asyncronous_operation}
+
+\itindbeg{signal~driven~I/O}
+
+Abbiamo accennato in sez.~\ref{sec:file_open} che è possibile, attraverso
+l'uso del flag \const{O\_ASYNC},\footnote{l'uso del flag di \const{O\_ASYNC} e
+ dei comandi \const{F\_SETOWN} e \const{F\_GETOWN} per \func{fcntl} è
+ specifico di Linux e BSD.} aprire un file in modalità asincrona, così come è
+possibile attivare in un secondo tempo questa modalità impostando questo flag
+attraverso l'uso di \func{fcntl} con il comando \const{F\_SETFL} (vedi
+sez.~\ref{sec:file_fcntl}). In realtà parlare di apertura in modalità
+asincrona non significa che le operazioni di lettura o scrittura del file
+vengono eseguite in modo asincrono (tratteremo questo, che è ciò che più
+propriamente viene chiamato \textsl{I/O asincrono}, in
+sez.~\ref{sec:file_asyncronous_io}), quanto dell'attivazione un meccanismo di
+notifica asincrona delle variazione dello stato del file descriptor aperto in
+questo modo.
+
+Quello che succede è che per tutti i file posti in questa modalità\footnote{si
+ tenga presente però che essa non è utilizzabile con i file ordinari ma solo
+ con socket, file di terminale o pseudo terminale, ed anche, a partire dal
+ kernel 2.6, anche per fifo e pipe.} il sistema genera un apposito segnale,
+\signal{SIGIO}, tutte le volte che diventa possibile leggere o scrivere dal
+file descriptor che si è posto in questa modalità. Inoltre è possibile, come
+illustrato in sez.~\ref{sec:file_fcntl}, selezionare con il comando
+\const{F\_SETOWN} di \func{fcntl} quale processo o quale gruppo di processi
+dovrà ricevere il segnale. In questo modo diventa possibile effettuare le
+operazioni di I/O in risposta alla ricezione del segnale, e non ci sarà più la
+necessità di restare bloccati in attesa della disponibilità di accesso ai
+file.
+
+% TODO: per i thread l'uso di F_SETOWN ha un significato diverso
+
+Per questo motivo Stevens, ed anche le pagine di manuale di Linux, chiamano
+questa modalità ``\textit{Signal driven I/O}''. Si tratta di un'altra
+modalità di gestione dell'I/O, alternativa all'uso di \itindex{epoll}
+\textit{epoll},\footnote{anche se le prestazioni ottenute con questa tecnica
+ sono inferiori, il vantaggio è che questa modalità è utilizzabile anche con
+ kernel che non supportano \textit{epoll}, come quelli della serie 2.4,
+ ottenendo comunque prestazioni superiori a quelle che si hanno con
+ \func{poll} e \func{select}.} che consente di evitare l'uso delle funzioni
+\func{poll} o \func{select} che, come illustrato in sez.~\ref{sec:file_epoll},
+quando vengono usate con un numero molto grande di file descriptor, non hanno
+buone prestazioni.
+
+Tuttavia con l'implementazione classica dei segnali questa modalità di I/O
+presenta notevoli problemi, dato che non è possibile determinare, quando i
+file descriptor sono più di uno, qual è quello responsabile dell'emissione del
+segnale. Inoltre dato che i segnali normali non si accodano (si ricordi quanto
+illustrato in sez.~\ref{sec:sig_notification}), in presenza di più file
+descriptor attivi contemporaneamente, più segnali emessi nello stesso momento
+verrebbero notificati una volta sola.
+
+Linux però supporta le estensioni POSIX.1b dei segnali real-time, che vengono
+accodati e che permettono di riconoscere il file descriptor che li ha emessi.
+In questo caso infatti si può fare ricorso alle informazioni aggiuntive
+restituite attraverso la struttura \struct{siginfo\_t}, utilizzando la forma
+estesa \var{sa\_sigaction} del gestore installata con il flag
+\const{SA\_SIGINFO} (si riveda quanto illustrato in
+sez.~\ref{sec:sig_sigaction}).
+
+Per far questo però occorre utilizzare le funzionalità dei segnali real-time
+(vedi sez.~\ref{sec:sig_real_time}) impostando esplicitamente con il comando
+\const{F\_SETSIG} di \func{fcntl} un segnale real-time da inviare in caso di
+I/O asincrono (il segnale predefinito è \signal{SIGIO}). In questo caso il
+gestore, tutte le volte che riceverà \const{SI\_SIGIO} come valore del campo
+\var{si\_code}\footnote{il valore resta \const{SI\_SIGIO} qualunque sia il
+ segnale che si è associato all'I/O, ed indica appunto che il segnale è stato
+ generato a causa di attività di I/O.} di \struct{siginfo\_t}, troverà nel
+campo \var{si\_fd} il valore del file descriptor che ha generato il segnale.
+
+Un secondo vantaggio dell'uso dei segnali real-time è che essendo questi
+ultimi dotati di una coda di consegna ogni segnale sarà associato ad uno solo
+file descriptor; inoltre sarà possibile stabilire delle priorità nella
+risposta a seconda del segnale usato, dato che i segnali real-time supportano
+anche questa funzionalità. In questo modo si può identificare immediatamente
+un file su cui l'accesso è diventato possibile evitando completamente l'uso di
+funzioni come \func{poll} e \func{select}, almeno fintanto che non si satura
+la coda.
+
+Se infatti si eccedono le dimensioni di quest'ultima, il kernel, non potendo
+più assicurare il comportamento corretto per un segnale real-time, invierà al
+suo posto un solo \signal{SIGIO}, su cui si saranno accumulati tutti i segnali
+in eccesso, e si dovrà allora determinare con un ciclo quali sono i file
+diventati attivi. L'unico modo per essere sicuri che questo non avvenga è di
+impostare la lunghezza della coda dei segnali real-time ad una dimensione
+identica al valore massimo del numero di file descriptor
+utilizzabili.\footnote{vale a dire impostare il contenuto di
+ \procfile{/proc/sys/kernel/rtsig-max} allo stesso valore del contenuto di
+ \procfile{/proc/sys/fs/file-max}.}
+
+% TODO fare esempio che usa O_ASYNC
+
+\itindend{signal~driven~I/O}
+
+
+
+\subsection{I meccanismi di notifica asincrona.}
+\label{sec:file_asyncronous_lease}
+
+Una delle domande più frequenti nella programmazione in ambiente unix-like è
+quella di come fare a sapere quando un file viene modificato. La
+risposta\footnote{o meglio la non risposta, tanto che questa nelle Unix FAQ
+ \cite{UnixFAQ} viene anche chiamata una \textit{Frequently Unanswered
+ Question}.} è che nell'architettura classica di Unix questo non è
+possibile. Al contrario di altri sistemi operativi infatti un kernel unix-like
+classico non prevedeva alcun meccanismo per cui un processo possa essere
+\textsl{notificato} di eventuali modifiche avvenute su un file. Questo è il
+motivo per cui i demoni devono essere \textsl{avvisati} in qualche
+modo\footnote{in genere questo vien fatto inviandogli un segnale di
+ \signal{SIGHUP} che, per una convenzione adottata dalla gran parte di detti
+ programmi, causa la rilettura della configurazione.} se il loro file di
+configurazione è stato modificato, perché possano rileggerlo e riconoscere le
+modifiche.
+
+Questa scelta è stata fatta perché provvedere un simile meccanismo a livello
+generico per qualunque file comporterebbe un notevole aumento di complessità
+dell'architettura della gestione dei file, il tutto per fornire una
+funzionalità che serve soltanto in alcuni casi particolari. Dato che
+all'origine di Unix i soli programmi che potevano avere una tale esigenza
+erano i demoni, attenendosi a uno dei criteri base della progettazione, che
+era di far fare al kernel solo le operazioni strettamente necessarie e
+lasciare tutto il resto a processi in user space, non era stata prevista
+nessuna funzionalità di notifica.
+
+Visto però il crescente interesse nei confronti di una funzionalità di questo
+tipo, che è molto richiesta specialmente nello sviluppo dei programmi ad
+interfaccia grafica, quando si deve presentare all'utente lo stato del
+filesystem, sono state successivamente introdotte delle estensioni che
+permettessero la creazione di meccanismi di notifica più efficienti dell'unica
+soluzione disponibile con l'interfaccia tradizionale, che è quella del
+\itindex{polling} \textit{polling}.
+
+Queste nuove funzionalità sono delle estensioni specifiche, non
+standardizzate, che sono disponibili soltanto su Linux (anche se altri kernel
+supportano meccanismi simili). Alcune di esse sono realizzate, e solo a
+partire dalla versione 2.4 del kernel, attraverso l'uso di alcuni
+\textsl{comandi} aggiuntivi per la funzione \func{fcntl} (vedi
+sez.~\ref{sec:file_fcntl}), che divengono disponibili soltanto se si è
+definita la macro \macro{\_GNU\_SOURCE} prima di includere \file{fcntl.h}.
+
+\index{file!lease|(}
+
+La prima di queste funzionalità è quella del cosiddetto \textit{file lease};
+questo è un meccanismo che consente ad un processo, detto \textit{lease
+ holder}, di essere notificato quando un altro processo, chiamato a sua volta
+\textit{lease breaker}, cerca di eseguire una \func{open} o una
+\func{truncate} sul file del quale l'\textit{holder} detiene il
+\textit{lease}.
+La notifica avviene in maniera analoga a come illustrato in precedenza per
+l'uso di \const{O\_ASYNC}: di default viene inviato al \textit{lease holder}
+il segnale \signal{SIGIO}, ma questo segnale può essere modificato usando il
+comando \const{F\_SETSIG} di \func{fcntl}.\footnote{anche in questo caso si
+ può rispecificare lo stesso \signal{SIGIO}.} Se si è fatto questo\footnote{è
+ in genere è opportuno farlo, come in precedenza, per utilizzare segnali
+ real-time.} e si è installato il gestore del segnale con \const{SA\_SIGINFO}
+si riceverà nel campo \var{si\_fd} della struttura \struct{siginfo\_t} il
+valore del file descriptor del file sul quale è stato compiuto l'accesso; in
+questo modo un processo può mantenere anche più di un \textit{file lease}.
+
+Esistono due tipi di \textit{file lease}: di lettura (\textit{read lease}) e
+di scrittura (\textit{write lease}). Nel primo caso la notifica avviene quando
+un altro processo esegue l'apertura del file in scrittura o usa
+\func{truncate} per troncarlo. Nel secondo caso la notifica avviene anche se
+il file viene aperto in lettura; in quest'ultimo caso però il \textit{lease}
+può essere ottenuto solo se nessun altro processo ha aperto lo stesso file.
+
+Come accennato in sez.~\ref{sec:file_fcntl} il comando di \func{fcntl} che
+consente di acquisire un \textit{file lease} è \const{F\_SETLEASE}, che viene
+utilizzato anche per rilasciarlo. In tal caso il file descriptor \param{fd}
+passato a \func{fcntl} servirà come riferimento per il file su cui si vuole
+operare, mentre per indicare il tipo di operazione (acquisizione o rilascio)
+occorrerà specificare come valore dell'argomento \param{arg} di \func{fcntl}
+uno dei tre valori di tab.~\ref{tab:file_lease_fctnl}.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|l|}
+ \hline
+ \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{F\_RDLCK} & Richiede un \textit{read lease}.\\
+ \const{F\_WRLCK} & Richiede un \textit{write lease}.\\
+ \const{F\_UNLCK} & Rilascia un \textit{file lease}.\\
+ \hline
+ \end{tabular}
+ \caption{Costanti per i tre possibili valori dell'argomento \param{arg} di
+ \func{fcntl} quando usata con i comandi \const{F\_SETLEASE} e
+ \const{F\_GETLEASE}.}
+ \label{tab:file_lease_fctnl}
+\end{table}
+
+Se invece si vuole conoscere lo stato di eventuali \textit{file lease}
+occorrerà chiamare \func{fcntl} sul relativo file descriptor \param{fd} con il
+comando \const{F\_GETLEASE}, e si otterrà indietro nell'argomento \param{arg}
+uno dei valori di tab.~\ref{tab:file_lease_fctnl}, che indicheranno la
+presenza del rispettivo tipo di \textit{lease}, o, nel caso di
+\const{F\_UNLCK}, l'assenza di qualunque \textit{file lease}.
+
+Si tenga presente che un processo può mantenere solo un tipo di \textit{lease}
+su un file, e che un \textit{lease} può essere ottenuto solo su file di dati
+(pipe e dispositivi sono quindi esclusi). Inoltre un processo non privilegiato
+può ottenere un \textit{lease} soltanto per un file appartenente ad un
+\acr{uid} corrispondente a quello del processo. Soltanto un processo con
+privilegi di amministratore (cioè con la \itindex{capabilities} capability
+\const{CAP\_LEASE}, vedi sez.~\ref{sec:proc_capabilities}) può acquisire
+\textit{lease} su qualunque file.
+
+Se su un file è presente un \textit{lease} quando il \textit{lease breaker}
+esegue una \func{truncate} o una \func{open} che confligge con
+esso,\footnote{in realtà \func{truncate} confligge sempre, mentre \func{open},
+ se eseguita in sola lettura, non confligge se si tratta di un \textit{read
+ lease}.} la funzione si blocca\footnote{a meno di non avere aperto il file
+ con \const{O\_NONBLOCK}, nel qual caso \func{open} fallirebbe con un errore
+ di \errcode{EWOULDBLOCK}.} e viene eseguita la notifica al \textit{lease
+ holder}, così che questo possa completare le sue operazioni sul file e
+rilasciare il \textit{lease}. In sostanza con un \textit{read lease} si
+rilevano i tentativi di accedere al file per modificarne i dati da parte di un
+altro processo, mentre con un \textit{write lease} si rilevano anche i
+tentativi di accesso in lettura. Si noti comunque che le operazioni di
+notifica avvengono solo in fase di apertura del file e non sulle singole
+operazioni di lettura e scrittura.
+
+L'utilizzo dei \textit{file lease} consente al \textit{lease holder} di
+assicurare la consistenza di un file, a seconda dei due casi, prima che un
+altro processo inizi con le sue operazioni di scrittura o di lettura su di
+esso. In genere un \textit{lease holder} che riceve una notifica deve
+provvedere a completare le necessarie operazioni (ad esempio scaricare
+eventuali buffer), per poi rilasciare il \textit{lease} così che il
+\textit{lease breaker} possa eseguire le sue operazioni. Questo si fa con il
+comando \const{F\_SETLEASE}, o rimuovendo il \textit{lease} con
+\const{F\_UNLCK}, o, nel caso di \textit{write lease} che confligge con una
+operazione di lettura, declassando il \textit{lease} a lettura con
+\const{F\_RDLCK}.
+
+Se il \textit{lease holder} non provvede a rilasciare il \textit{lease} entro
+il numero di secondi specificato dal parametro di sistema mantenuto in
+\procfile{/proc/sys/fs/lease-break-time} sarà il kernel stesso a rimuoverlo (o
+declassarlo) automaticamente.\footnote{questa è una misura di sicurezza per
+ evitare che un processo blocchi indefinitamente l'accesso ad un file
+ acquisendo un \textit{lease}.} Una volta che un \textit{lease} è stato
+rilasciato o declassato (che questo sia fatto dal \textit{lease holder} o dal
+kernel è lo stesso) le chiamate a \func{open} o \func{truncate} eseguite dal
+\textit{lease breaker} rimaste bloccate proseguono automaticamente.
+
+Benché possa risultare utile per sincronizzare l'accesso ad uno stesso file da
+parte di più processi, l'uso dei \textit{file lease} non consente comunque di
+risolvere il problema di rilevare automaticamente quando un file o una
+directory vengono modificati,\footnote{questa funzionalità venne aggiunta
+ principalmente ad uso di Samba per poter facilitare l'emulazione del
+ comportamento di Windows sui file, ma ad oggi viene considerata una
+ interfaccia mal progettata ed il suo uso è fortemente sconsigliato a favore
+ di \textit{inotify}.} che è quanto necessario ad esempio ai programma di
+gestione dei file dei vari desktop grafici.
+
+\itindbeg{dnotify}
+
+Per risolvere questo problema a partire dal kernel 2.4 è stata allora creata
+un'altra interfaccia,\footnote{si ricordi che anche questa è una interfaccia
+ specifica di Linux che deve essere evitata se si vogliono scrivere programmi
+ portabili, e che le funzionalità illustrate sono disponibili soltanto se è
+ stata definita la macro \macro{\_GNU\_SOURCE}.} chiamata \textit{dnotify},
+che consente di richiedere una notifica quando una directory, o uno qualunque
+dei file in essa contenuti, viene modificato. Come per i \textit{file lease}
+la notifica avviene di default attraverso il segnale \signal{SIGIO}, ma se ne
+può utilizzare un altro.\footnote{e di nuovo, per le ragioni già esposte in
+ precedenza, è opportuno che si utilizzino dei segnali real-time.} Inoltre,
+come in precedenza, si potrà ottenere nel gestore del segnale il file
+descriptor che è stato modificato tramite il contenuto della struttura
+\struct{siginfo\_t}.
+
+\index{file!lease|)}
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|p{8cm}|}
+ \hline
+ \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{DN\_ACCESS} & Un file è stato acceduto, con l'esecuzione di una fra
+ \func{read}, \func{pread}, \func{readv}.\\
+ \const{DN\_MODIFY} & Un file è stato modificato, con l'esecuzione di una
+ fra \func{write}, \func{pwrite}, \func{writev},
+ \func{truncate}, \func{ftruncate}.\\
+ \const{DN\_CREATE} & È stato creato un file nella directory, con
+ l'esecuzione di una fra \func{open}, \func{creat},
+ \func{mknod}, \func{mkdir}, \func{link},
+ \func{symlink}, \func{rename} (da un'altra
+ directory).\\
+ \const{DN\_DELETE} & È stato cancellato un file dalla directory con
+ l'esecuzione di una fra \func{unlink}, \func{rename}
+ (su un'altra directory), \func{rmdir}.\\
+ \const{DN\_RENAME} & È stato rinominato un file all'interno della
+ directory (con \func{rename}).\\
+ \const{DN\_ATTRIB} & È stato modificato un attributo di un file con
+ l'esecuzione di una fra \func{chown}, \func{chmod},
+ \func{utime}.\\
+ \const{DN\_MULTISHOT}& Richiede una notifica permanente di tutti gli
+ eventi.\\
+ \hline
+ \end{tabular}
+ \caption{Le costanti che identificano le varie classi di eventi per i quali
+ si richiede la notifica con il comando \const{F\_NOTIFY} di \func{fcntl}.}
+ \label{tab:file_notify}
+\end{table}
+
+Ci si può registrare per le notifiche dei cambiamenti al contenuto di una
+certa directory eseguendo la funzione \func{fcntl} su un file descriptor
+associato alla stessa con il comando \const{F\_NOTIFY}. In questo caso
+l'argomento \param{arg} di \func{fcntl} serve ad indicare per quali classi
+eventi si vuole ricevere la notifica, e prende come valore una maschera
+binaria composta dall'OR aritmetico di una o più delle costanti riportate in
+tab.~\ref{tab:file_notify}.
+
+A meno di non impostare in maniera esplicita una notifica permanente usando il
+valore \const{DN\_MULTISHOT}, la notifica è singola: viene cioè inviata una
+sola volta quando si verifica uno qualunque fra gli eventi per i quali la si è
+richiesta. Questo significa che un programma deve registrarsi un'altra volta
+se desidera essere notificato di ulteriori cambiamenti. Se si eseguono diverse
+chiamate con \const{F\_NOTIFY} e con valori diversi per \param{arg} questi
+ultimi si \textsl{accumulano}; cioè eventuali nuovi classi di eventi
+specificate in chiamate successive vengono aggiunte a quelle già impostate
+nelle precedenti. Se si vuole rimuovere la notifica si deve invece
+specificare un valore nullo.
+
+\itindbeg{inotify}
+
+Il maggiore problema di \textit{dnotify} è quello della scalabilità: si deve
+usare un file descriptor per ciascuna directory che si vuole tenere sotto
+controllo, il che porta facilmente ad avere un eccesso di file aperti. Inoltre
+quando la directory che si controlla è all'interno di un dispositivo
+rimovibile, mantenere il relativo file descriptor aperto comporta
+l'impossibilità di smontare il dispositivo e di rimuoverlo, il che in genere
+complica notevolmente la gestione dell'uso di questi dispositivi.
+
+Un altro problema è che l'interfaccia di \textit{dnotify} consente solo di
+tenere sotto controllo il contenuto di una directory; la modifica di un file
+viene segnalata, ma poi è necessario verificare di quale file si tratta
+(operazione che può essere molto onerosa quando una directory contiene un gran
+numero di file). Infine l'uso dei segnali come interfaccia di notifica
+comporta tutti i problemi di gestione visti in sez.~\ref{sec:sig_management} e
+sez.~\ref{sec:sig_adv_control}. Per tutta questa serie di motivi in generale
+quella di \textit{dnotify} viene considerata una interfaccia di usabilità
+problematica ed il suo uso oggi è fortemente sconsigliato.
+
+\itindend{dnotify}
+
+Per risolvere i problemi appena illustrati è stata introdotta una nuova
+interfaccia per l'osservazione delle modifiche a file o directory, chiamata
+\textit{inotify}.\footnote{l'interfaccia è disponibile a partire dal kernel
+ 2.6.13, le relative funzioni sono state introdotte nelle glibc 2.4.} Anche
+questa è una interfaccia specifica di Linux (pertanto non deve essere usata se
+si devono scrivere programmi portabili), ed è basata sull'uso di una coda di
+notifica degli eventi associata ad un singolo file descriptor, il che permette
+di risolvere il principale problema di \itindex{dnotify} \textit{dnotify}. La
+coda viene creata attraverso la funzione \funcd{inotify\_init}, il cui
+prototipo è:
+\begin{prototype}{sys/inotify.h}
+ {int inotify\_init(void)}
+
+ Inizializza una istanza di \textit{inotify}.
+
+ \bodydesc{La funzione restituisce un file descriptor in caso di successo, o
+ $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EMFILE}] si è raggiunto il numero massimo di istanze di
+ \textit{inotify} consentite all'utente.
+ \item[\errcode{ENFILE}] si è raggiunto il massimo di file descriptor aperti
+ nel sistema.
+ \item[\errcode{ENOMEM}] non c'è sufficiente memoria nel kernel per creare
+ l'istanza.
+ \end{errlist}
+}
+\end{prototype}
+
+La funzione non prende alcun argomento; inizializza una istanza di
+\textit{inotify} e restituisce un file descriptor attraverso il quale verranno
+effettuate le operazioni di notifica;\footnote{per evitare abusi delle risorse
+ di sistema è previsto che un utente possa utilizzare un numero limitato di
+ istanze di \textit{inotify}; il valore di default del limite è di 128, ma
+ questo valore può essere cambiato con \func{sysctl} o usando il file
+ \procfile{/proc/sys/fs/inotify/max\_user\_instances}.} si tratta di un file
+descriptor speciale che non è associato a nessun file su disco, e che viene
+utilizzato solo per notificare gli eventi che sono stati posti in
+osservazione. Dato che questo file descriptor non è associato a nessun file o
+directory reale, l'inconveniente di non poter smontare un filesystem i cui
+file sono tenuti sotto osservazione viene completamente
+eliminato.\footnote{anzi, una delle capacità dell'interfaccia di
+ \textit{inotify} è proprio quella di notificare il fatto che il filesystem
+ su cui si trova il file o la directory osservata è stato smontato.}
+
+Inoltre trattandosi di un file descriptor a tutti gli effetti, esso potrà
+essere utilizzato come argomento per le funzioni \func{select} e \func{poll} e
+con l'interfaccia di \textit{epoll};\footnote{ed a partire dal kernel 2.6.25 è
+ stato introdotto anche il supporto per il \itindex{signal~driven~I/O}
+ \texttt{signal-driven I/O} trattato in
+ sez.~\ref{sec:file_asyncronous_operation}.} siccome gli eventi vengono
+notificati come dati disponibili in lettura, dette funzioni ritorneranno tutte
+le volte che si avrà un evento di notifica. Così, invece di dover utilizzare i
+segnali,\footnote{considerati una pessima scelta dal punto di vista
+ dell'interfaccia utente.} si potrà gestire l'osservazione degli eventi con
+una qualunque delle modalità di \textit{I/O multiplexing} illustrate in
+sez.~\ref{sec:file_multiplexing}. Qualora si voglia cessare l'osservazione,
+sarà sufficiente chiudere il file descriptor e tutte le risorse allocate
+saranno automaticamente rilasciate.
+
+Infine l'interfaccia di \textit{inotify} consente di mettere sotto
+osservazione, oltre che una directory, anche singoli file. Una volta creata
+la coda di notifica si devono definire gli eventi da tenere sotto
+osservazione; questo viene fatto attraverso una \textsl{lista di osservazione}
+(o \textit{watch list}) che è associata alla coda. Per gestire la lista di
+osservazione l'interfaccia fornisce due funzioni, la prima di queste è
+\funcd{inotify\_add\_watch}, il cui prototipo è:
+\begin{prototype}{sys/inotify.h}
+ {int inotify\_add\_watch(int fd, const char *pathname, uint32\_t mask)}
+
+ Aggiunge un evento di osservazione alla lista di osservazione di \param{fd}.
+
+ \bodydesc{La funzione restituisce un valore positivo in caso di successo, o
+ $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCESS}] non si ha accesso in lettura al file indicato.
+ \item[\errcode{EINVAL}] \param{mask} non contiene eventi legali o \param{fd}
+ non è un file descriptor di \textit{inotify}.
+ \item[\errcode{ENOSPC}] si è raggiunto il numero massimo di voci di
+ osservazione o il kernel non ha potuto allocare una risorsa necessaria.
+ \end{errlist}
+ ed inoltre \errval{EFAULT}, \errval{ENOMEM} e \errval{EBADF}.}
+\end{prototype}
+
+La funzione consente di creare un ``\textsl{osservatore}'' (il cosiddetto
+``\textit{watch}'') nella lista di osservazione di una coda di notifica, che
+deve essere indicata specificando il file descriptor ad essa associato
+nell'argomento \param{fd}.\footnote{questo ovviamente dovrà essere un file
+ descriptor creato con \func{inotify\_init}.} Il file o la directory da
+porre sotto osservazione vengono invece indicati per nome, da passare
+nell'argomento \param{pathname}. Infine il terzo argomento, \param{mask},
+indica che tipo di eventi devono essere tenuti sotto osservazione e le
+modalità della stessa. L'operazione può essere ripetuta per tutti i file e le
+directory che si vogliono tenere sotto osservazione,\footnote{anche in questo
+ caso c'è un limite massimo che di default è pari a 8192, ed anche questo
+ valore può essere cambiato con \func{sysctl} o usando il file
+ \procfile{/proc/sys/fs/inotify/max\_user\_watches}.} e si utilizzerà sempre
+un solo file descriptor.
+
+Il tipo di evento che si vuole osservare deve essere specificato
+nell'argomento \param{mask} come maschera binaria, combinando i valori delle
+costanti riportate in tab.~\ref{tab:inotify_event_watch} che identificano i
+singoli bit della maschera ed il relativo significato. In essa si sono marcati
+con un ``$\bullet$'' gli eventi che, quando specificati per una directory,
+vengono osservati anche su tutti i file che essa contiene. Nella seconda
+parte della tabella si sono poi indicate alcune combinazioni predefinite dei
+flag della prima parte.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|c|p{10cm}|}
+ \hline
+ \textbf{Valore} & & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{IN\_ACCESS} &$\bullet$& C'è stato accesso al file in
+ lettura.\\
+ \const{IN\_ATTRIB} &$\bullet$& Ci sono stati cambiamenti sui dati
+ dell'inode (o sugli attributi
+ estesi, vedi
+ sez.~\ref{sec:file_xattr}).\\
+ \const{IN\_CLOSE\_WRITE} &$\bullet$& È stato chiuso un file aperto in
+ scrittura.\\
+ \const{IN\_CLOSE\_NOWRITE}&$\bullet$& È stato chiuso un file aperto in
+ sola lettura.\\
+ \const{IN\_CREATE} &$\bullet$& È stato creato un file o una
+ directory in una directory sotto
+ osservazione.\\
+ \const{IN\_DELETE} &$\bullet$& È stato cancellato un file o una
+ directory in una directory sotto
+ osservazione.\\
+ \const{IN\_DELETE\_SELF} & -- & È stato cancellato il file (o la
+ directory) sotto osservazione.\\
+ \const{IN\_MODIFY} &$\bullet$& È stato modificato il file.\\
+ \const{IN\_MOVE\_SELF} & & È stato rinominato il file (o la
+ directory) sotto osservazione.\\
+ \const{IN\_MOVED\_FROM} &$\bullet$& Un file è stato spostato fuori dalla
+ directory sotto osservazione.\\
+ \const{IN\_MOVED\_TO} &$\bullet$& Un file è stato spostato nella
+ directory sotto osservazione.\\
+ \const{IN\_OPEN} &$\bullet$& Un file è stato aperto.\\
+ \hline
+ \const{IN\_CLOSE} & & Combinazione di
+ \const{IN\_CLOSE\_WRITE} e
+ \const{IN\_CLOSE\_NOWRITE}.\\
+ \const{IN\_MOVE} & & Combinazione di
+ \const{IN\_MOVED\_FROM} e
+ \const{IN\_MOVED\_TO}.\\
+ \const{IN\_ALL\_EVENTS} & & Combinazione di tutti i flag
+ possibili.\\
+ \hline
+ \end{tabular}
+ \caption{Le costanti che identificano i bit della maschera binaria
+ dell'argomento \param{mask} di \func{inotify\_add\_watch} che indicano il
+ tipo di evento da tenere sotto osservazione.}
+ \label{tab:inotify_event_watch}
+\end{table}
+
+Oltre ai flag di tab.~\ref{tab:inotify_event_watch}, che indicano il tipo di
+evento da osservare e che vengono utilizzati anche in uscita per indicare il
+tipo di evento avvenuto, \func{inotify\_add\_watch} supporta ulteriori
+flag,\footnote{i flag \const{IN\_DONT\_FOLLOW}, \const{IN\_MASK\_ADD} e
+ \const{IN\_ONLYDIR} sono stati introdotti a partire dalle glibc 2.5, se si
+ usa la versione 2.4 è necessario definirli a mano.} riportati in
+tab.~\ref{tab:inotify_add_watch_flag}, che indicano le modalità di
+osservazione (da passare sempre nell'argomento \param{mask}) e che al
+contrario dei precedenti non vengono mai impostati nei risultati in uscita.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|p{10cm}|}
+ \hline
+ \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{IN\_DONT\_FOLLOW}& Non dereferenzia \param{pathname} se questo è un
+ link simbolico.\\
+ \const{IN\_MASK\_ADD} & Aggiunge a quelli già impostati i flag indicati
+ nell'argomento \param{mask}, invece di
+ sovrascriverli.\\
+ \const{IN\_ONESHOT} & Esegue l'osservazione su \param{pathname} per una
+ sola volta, rimuovendolo poi dalla \textit{watch
+ list}.\\
+ \const{IN\_ONLYDIR} & Se \param{pathname} è una directory riporta
+ soltanto gli eventi ad essa relativi e non
+ quelli per i file che contiene.\\
+ \hline
+ \end{tabular}
+ \caption{Le costanti che identificano i bit della maschera binaria
+ dell'argomento \param{mask} di \func{inotify\_add\_watch} che indicano le
+ modalità di osservazione.}
+ \label{tab:inotify_add_watch_flag}
+\end{table}
+
+Se non esiste nessun \textit{watch} per il file o la directory specificata
+questo verrà creato per gli eventi specificati dall'argomento \param{mask},
+altrimenti la funzione sovrascriverà le impostazioni precedenti, a meno che
+non si sia usato il flag \const{IN\_MASK\_ADD}, nel qual caso gli eventi
+specificati saranno aggiunti a quelli già presenti.
+
+Come accennato quando si tiene sotto osservazione una directory vengono
+restituite le informazioni sia riguardo alla directory stessa che ai file che
+essa contiene; questo comportamento può essere disabilitato utilizzando il
+flag \const{IN\_ONLYDIR}, che richiede di riportare soltanto gli eventi
+relativi alla directory stessa. Si tenga presente inoltre che quando si
+osserva una directory vengono riportati solo gli eventi sui file che essa
+contiene direttamente, non quelli relativi a file contenuti in eventuali
+sottodirectory; se si vogliono osservare anche questi sarà necessario creare
+ulteriori \textit{watch} per ciascuna sottodirectory.
+
+Infine usando il flag \const{IN\_ONESHOT} è possibile richiedere una notifica
+singola;\footnote{questa funzionalità però è disponibile soltanto a partire dal
+ kernel 2.6.16.} una volta verificatosi uno qualunque fra gli eventi
+richiesti con \func{inotify\_add\_watch} l'\textsl{osservatore} verrà
+automaticamente rimosso dalla lista di osservazione e nessun ulteriore evento
+sarà più notificato.
+
+In caso di successo \func{inotify\_add\_watch} ritorna un intero positivo,
+detto \textit{watch descriptor}, che identifica univocamente un
+\textsl{osservatore} su una coda di notifica; esso viene usato per farvi
+riferimento sia riguardo i risultati restituiti da \textit{inotify}, che per
+la eventuale rimozione dello stesso.
+
+La seconda funzione per la gestione delle code di notifica, che permette di
+rimuovere un \textsl{osservatore}, è \funcd{inotify\_rm\_watch}, ed il suo
+prototipo è:
+\begin{prototype}{sys/inotify.h}
+ {int inotify\_rm\_watch(int fd, uint32\_t wd)}
+
+ Rimuove un \textsl{osservatore} da una coda di notifica.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo, o $-1$ in caso di
+ errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EBADF}] non si è specificato in \param{fd} un file descriptor
+ valido.
+ \item[\errcode{EINVAL}] il valore di \param{wd} non è corretto, o \param{fd}
+ non è associato ad una coda di notifica.
+ \end{errlist}
+}
+\end{prototype}
+
+La funzione rimuove dalla coda di notifica identificata dall'argomento
+\param{fd} l'osservatore identificato dal \textit{watch descriptor}
+\param{wd};\footnote{ovviamente deve essere usato per questo argomento un
+ valore ritornato da \func{inotify\_add\_watch}, altrimenti si avrà un errore
+ di \errval{EINVAL}.} in caso di successo della rimozione, contemporaneamente
+alla cancellazione dell'osservatore, sulla coda di notifica verrà generato un
+evento di tipo \const{IN\_IGNORED} (vedi
+tab.~\ref{tab:inotify_read_event_flag}). Si tenga presente che se un file
+viene cancellato o un filesystem viene smontato i relativi osservatori vengono
+rimossi automaticamente e non è necessario utilizzare
+\func{inotify\_rm\_watch}.
+
+Come accennato l'interfaccia di \textit{inotify} prevede che gli eventi siano
+notificati come dati presenti in lettura sul file descriptor associato alla
+coda di notifica. Una applicazione pertanto dovrà leggere i dati da detto file
+con una \func{read}, che ritornerà sul buffer i dati presenti nella forma di
+una o più strutture di tipo \struct{inotify\_event} (la cui definizione è
+riportata in fig.~\ref{fig:inotify_event}). Qualora non siano presenti dati la
+\func{read} si bloccherà (a meno di non aver impostato il file descriptor in
+modalità non bloccante) fino all'arrivo di almeno un evento.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{\textwidth}
+ \includestruct{listati/inotify_event.h}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \structd{inotify\_event} usata dall'interfaccia di
+ \textit{inotify} per riportare gli eventi.}
+ \label{fig:inotify_event}
+\end{figure}
+
+Una ulteriore caratteristica dell'interfaccia di \textit{inotify} è che essa
+permette di ottenere con \func{ioctl}, come per i file descriptor associati ai
+socket (si veda sez.~\ref{sec:sock_ioctl_IP}) il numero di byte disponibili in
+lettura sul file descriptor, utilizzando su di esso l'operazione
+\const{FIONREAD}.\footnote{questa è una delle operazioni speciali per i file
+ (vedi sez.~\ref{sec:file_ioctl}), che è disponibile solo per i socket e per
+ i file descriptor creati con \func{inotify\_init}.} Si può così utilizzare
+questa operazione, oltre che per predisporre una operazione di lettura con un
+buffer di dimensioni adeguate, anche per ottenere rapidamente il numero di
+file che sono cambiati.
+
+Una volta effettuata la lettura con \func{read} a ciascun evento sarà
+associata una struttura \struct{inotify\_event} contenente i rispettivi dati.
+Per identificare a quale file o directory l'evento corrisponde viene
+restituito nel campo \var{wd} il \textit{watch descriptor} con cui il relativo
+osservatore è stato registrato. Il campo \var{mask} contiene invece una
+maschera di bit che identifica il tipo di evento verificatosi; in essa
+compariranno sia i bit elencati nella prima parte di
+tab.~\ref{tab:inotify_event_watch}, che gli eventuali valori
+aggiuntivi\footnote{questi compaiono solo nel campo \var{mask} di
+ \struct{inotify\_event}, e non utilizzabili in fase di registrazione
+ dell'osservatore.} di tab.~\ref{tab:inotify_read_event_flag}.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|p{10cm}|}
+ \hline
+ \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{IN\_IGNORED} & L'osservatore è stato rimosso, sia in maniera
+ esplicita con l'uso di \func{inotify\_rm\_watch},
+ che in maniera implicita per la rimozione
+ dell'oggetto osservato o per lo smontaggio del
+ filesystem su cui questo si trova.\\
+ \const{IN\_ISDIR} & L'evento avvenuto fa riferimento ad una directory
+ (consente così di distinguere, quando si pone
+ sotto osservazione una directory, fra gli eventi
+ relativi ad essa e quelli relativi ai file che
+ essa contiene).\\
+ \const{IN\_Q\_OVERFLOW}& Si sono eccedute le dimensioni della coda degli
+ eventi (\textit{overflow} della coda); in questo
+ caso il valore di \var{wd} è $-1$.\footnotemark\\
+ \const{IN\_UNMOUNT} & Il filesystem contenente l'oggetto posto sotto
+ osservazione è stato smontato.\\
+ \hline
+ \end{tabular}
+ \caption{Le costanti che identificano i bit aggiuntivi usati nella maschera
+ binaria del campo \var{mask} di \struct{inotify\_event}.}
+ \label{tab:inotify_read_event_flag}
+\end{table}
+
+\footnotetext{la coda di notifica ha una dimensione massima specificata dal
+ parametro di sistema \procfile{/proc/sys/fs/inotify/max\_queued\_events} che
+ indica il numero massimo di eventi che possono essere mantenuti sulla
+ stessa; quando detto valore viene ecceduto gli ulteriori eventi vengono
+ scartati, ma viene comunque generato un evento di tipo
+ \const{IN\_Q\_OVERFLOW}.}
+
+Il campo \var{cookie} contiene invece un intero univoco che permette di
+identificare eventi correlati (per i quali avrà lo stesso valore), al momento
+viene utilizzato soltanto per rilevare lo spostamento di un file, consentendo
+così all'applicazione di collegare la corrispondente coppia di eventi
+\const{IN\_MOVED\_TO} e \const{IN\_MOVED\_FROM}.
+
+Infine due campi \var{name} e \var{len} sono utilizzati soltanto quando
+l'evento è relativo ad un file presente in una directory posta sotto
+osservazione, in tal caso essi contengono rispettivamente il nome del file
+(come pathname relativo alla directory osservata) e la relativa dimensione in
+byte. Il campo \var{name} viene sempre restituito come stringa terminata da
+NUL, con uno o più zeri di terminazione, a seconda di eventuali necessità di
+allineamento del risultato, ed il valore di \var{len} corrisponde al totale
+della dimensione di \var{name}, zeri aggiuntivi compresi. La stringa con il
+nome del file viene restituita nella lettura subito dopo la struttura
+\struct{inotify\_event}; questo significa che le dimensioni di ciascun evento
+di \textit{inotify} saranno pari a \code{sizeof(\struct{inotify\_event}) +
+ len}.
+
+Vediamo allora un esempio dell'uso dell'interfaccia di \textit{inotify} con un
+semplice programma che permette di mettere sotto osservazione uno o più file e
+directory. Il programma si chiama \texttt{inotify\_monitor.c} ed il codice
+completo è disponibile coi sorgenti allegati alla guida, il corpo principale
+del programma, che non contiene la sezione di gestione delle opzioni e le
+funzioni di ausilio è riportato in fig.~\ref{fig:inotify_monitor_example}.
+
+\begin{figure}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/inotify_monitor.c}
+ \end{minipage}
+ \normalsize
+ \caption{Esempio di codice che usa l'interfaccia di \textit{inotify}.}
+ \label{fig:inotify_monitor_example}
+\end{figure}
+
+Una volta completata la scansione delle opzioni il corpo principale del
+programma inizia controllando (\texttt{\small 11--15}) che sia rimasto almeno
+un argomento che indichi quale file o directory mettere sotto osservazione (e
+qualora questo non avvenga esce stampando la pagina di aiuto); dopo di che
+passa (\texttt{\small 16--20}) all'inizializzazione di \textit{inotify}
+ottenendo con \func{inotify\_init} il relativo file descriptor (oppure usce in
+caso di errore).
+
+Il passo successivo è aggiungere (\texttt{\small 21--30}) alla coda di
+notifica gli opportuni osservatori per ciascuno dei file o directory indicati
+all'invocazione del comando; questo viene fatto eseguendo un ciclo
+(\texttt{\small 22--29}) fintanto che la variabile \var{i}, inizializzata a
+zero (\texttt{\small 21}) all'inizio del ciclo, è minore del numero totale di
+argomenti rimasti. All'interno del ciclo si invoca (\texttt{\small 23})
+\func{inotify\_add\_watch} per ciascuno degli argomenti, usando la maschera
+degli eventi data dalla variabile \var{mask} (il cui valore viene impostato
+nella scansione delle opzioni), in caso di errore si esce dal programma
+altrimenti si incrementa l'indice (\texttt{\small 29}).
+
+Completa l'inizializzazione di \textit{inotify} inizia il ciclo principale
+(\texttt{\small 32--56}) del programma, nel quale si resta in attesa degli
+eventi che si intendono osservare. Questo viene fatto eseguendo all'inizio del
+ciclo (\texttt{\small 33}) una \func{read} che si bloccherà fintanto che non
+si saranno verificati eventi.
+
+Dato che l'interfaccia di \textit{inotify} può riportare anche più eventi in
+una sola lettura, si è avuto cura di passare alla \func{read} un buffer di
+dimensioni adeguate, inizializzato in (\texttt{\small 7}) ad un valore di
+approssimativamente 512 eventi.\footnote{si ricordi che la quantità di dati
+ restituita da \textit{inotify} è variabile a causa della diversa lunghezza
+ 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.
+
+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
+l'indice \var{i} a zero (\texttt{\small 42}) e si ripetono le operazioni
+(\texttt{\small 43}) fintanto che esso non supera il numero di byte restituiti
+in lettura. Per ciascun evento all'interno del ciclo si assegna\footnote{si
+ noti come si sia eseguito un opportuno \textit{casting} del puntatore.} alla
+variabile \var{event} l'indirizzo nel buffer della corrispondente struttura
+\struct{inotify\_event} (\texttt{\small 44}), e poi si stampano il numero di
+\textit{watch descriptor} (\texttt{\small 45}) ed il file a cui questo fa
+riferimento (\texttt{\small 46}), ricavato dagli argomenti passati a riga di
+comando sfruttando il fatto che i \textit{watch descriptor} vengono assegnati
+in ordine progressivo crescente a partire da 1.
+
+Qualora sia presente il riferimento ad un nome di file associato all'evento lo
+si stampa (\texttt{\small 47--49}); si noti come in questo caso si sia
+utilizzato il valore del campo \var{event->len} e non al fatto che
+\var{event->name} riporti o meno un puntatore nullo.\footnote{l'interfaccia
+ infatti, qualora il nome non sia presente, non avvalora il campo
+ \var{event->name}, che si troverà a contenere quello che era precedentemente
+ presente nella rispettiva locazione di memoria, nel caso più comune il
+ puntatore al nome di un file osservato in precedenza.} Si utilizza poi
+(\texttt{\small 50}) la funzione \code{printevent}, che interpreta il valore
+del campo \var{event->mask} per stampare il tipo di eventi
+accaduti.\footnote{per il relativo codice, che non riportiamo in quanto non
+ essenziale alla comprensione dell'esempio, si possono utilizzare direttamente
+ i sorgenti allegati alla guida.} Infine (\texttt{\small 51}) si provvede ad
+aggiornare l'indice \var{i} per farlo puntare all'evento successivo.
+
+Se adesso usiamo il programma per mettere sotto osservazione una directory, e
+da un altro terminale eseguiamo il comando \texttt{ls} otterremo qualcosa del
+tipo di:
+\begin{verbatim}
+piccardi@gethen:~/gapil/sources$ ./inotify_monitor -a /home/piccardi/gapil/
+Watch descriptor 1
+Observed event on /home/piccardi/gapil/
+IN_OPEN,
+Watch descriptor 1
+Observed event on /home/piccardi/gapil/
+IN_CLOSE_NOWRITE,
+\end{verbatim}
+
+I lettori più accorti si saranno resi conto che nel ciclo di lettura degli
+eventi appena illustrato non viene trattato il caso particolare in cui la
+funzione \func{read} restituisce in \var{nread} un valore nullo. Lo si è fatto
+perché con \textit{inotify} il ritorno di una \func{read} con un valore nullo
+avviene soltanto, come forma di avviso, quando si sia eseguita la funzione
+specificando un buffer di dimensione insufficiente a contenere anche un solo
+evento. Nel nostro caso le dimensioni erano senz'altro sufficienti, per cui
+tale evenienza non si verificherà mai.
+
+Ci si potrà però chiedere cosa succede se il buffer è sufficiente per un
+evento, ma non per tutti gli eventi verificatisi. Come si potrà notare nel
+codice illustrato in precedenza non si è presa nessuna precauzione per
+verificare che non ci fossero stati troncamenti dei dati. Anche in questo caso
+il comportamento scelto è corretto, perché l'interfaccia di \textit{inotify}
+garantisce automaticamente, anche quando ne sono presenti in numero maggiore,
+di restituire soltanto il numero di eventi che possono rientrare completamente
+nelle dimensioni del buffer specificato.\footnote{si avrà cioè, facendo
+ riferimento sempre al codice di fig.~\ref{fig:inotify_monitor_example}, che
+ \var{read} sarà in genere minore delle dimensioni di \var{buffer} ed uguale
+ soltanto qualora gli eventi corrispondano esattamente alle dimensioni di
+ quest'ultimo.} Se gli eventi sono di più saranno restituiti solo quelli che
+entrano interamente nel buffer e gli altri saranno restituiti alla successiva
+chiamata di \func{read}.
+
+Infine un'ultima caratteristica dell'interfaccia di \textit{inotify} è che gli
+eventi restituiti nella lettura formano una sequenza ordinata, è cioè
+garantito che se si esegue uno spostamento di un file gli eventi vengano
+generati nella sequenza corretta. L'interfaccia garantisce anche che se si
+verificano più eventi consecutivi identici (vale a dire con gli stessi valori
+dei campi \var{wd}, \var{mask}, \var{cookie}, e \var{name}) questi vengono
+raggruppati in un solo evento.
+
+\itindend{inotify}
+
+% TODO trattare fanotify, vedi http://lwn.net/Articles/339399/ e
+% http://lwn.net/Articles/343346/ (incluso nel 2.6.36)
+
+
+\subsection{L'interfaccia POSIX per l'I/O asincrono}
+\label{sec:file_asyncronous_io}
+
+% vedere anche http://davmac.org/davpage/linux/async-io.html
+
+Una modalità alternativa all'uso dell'\textit{I/O multiplexing} per gestione
+dell'I/O simultaneo su molti file è costituita dal cosiddetto \textsl{I/O
+ asincrono}. Il concetto base dell'\textsl{I/O asincrono} è che le funzioni
+di I/O non attendono il completamento delle operazioni prima di ritornare,
+così che il processo non viene bloccato. In questo modo diventa ad esempio
+possibile effettuare una richiesta preventiva di dati, in modo da poter
+effettuare in contemporanea le operazioni di calcolo e quelle di I/O.
+
+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
+normalmente.
+
+In generale questa interfaccia è completamente astratta e può essere
+implementata sia direttamente nel kernel, che in user space attraverso l'uso
+di \itindex{thread} \textit{thread}. Per le versioni del kernel meno recenti
+esiste una implementazione di questa interfaccia fornita delle \acr{glibc},
+che è realizzata completamente in user space, ed è accessibile linkando i
+programmi con la libreria \file{librt}. Nelle versioni più recenti (a partire
+dalla 2.5.32) è stato introdotto direttamente nel kernel un nuovo layer per
+l'I/O asincrono.
+
+Lo standard prevede che tutte le operazioni di I/O asincrono siano controllate
+attraverso l'uso di una apposita struttura \struct{aiocb} (il cui nome sta per
+\textit{asyncronous I/O control block}), che viene passata come argomento a
+tutte le funzioni dell'interfaccia. La sua definizione, come effettuata in
+\file{aio.h}, è riportata in fig.~\ref{fig:file_aiocb}. Nello steso file è
+definita la macro \macro{\_POSIX\_ASYNCHRONOUS\_IO}, che dichiara la
+disponibilità dell'interfaccia per l'I/O asincrono.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{\textwidth}
+ \includestruct{listati/aiocb.h}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \structd{aiocb}, usata per il controllo dell'I/O
+ asincrono.}
+ \label{fig:file_aiocb}
+\end{figure}
+
+Le operazioni di I/O asincrono possono essere effettuate solo su un file già
+aperto; il file deve inoltre supportare la funzione \func{lseek}, pertanto
+terminali e pipe sono esclusi. Non c'è limite al numero di operazioni
+contemporanee effettuabili su un singolo file. Ogni operazione deve
+inizializzare opportunamente un \textit{control block}. Il file descriptor su
+cui operare deve essere specificato tramite il campo \var{aio\_fildes}; dato
+che più operazioni possono essere eseguita in maniera asincrona, il concetto
+di posizione corrente sul file viene a mancare; pertanto si deve sempre
+specificare nel campo \var{aio\_offset} la posizione sul file da cui i dati
+saranno letti o scritti. Nel campo \var{aio\_buf} deve essere specificato
+l'indirizzo del buffer usato per l'I/O, ed in \var{aio\_nbytes} la lunghezza
+del blocco di dati da trasferire.
+
+Il campo \var{aio\_reqprio} permette di impostare la priorità delle operazioni
+di I/O.\footnote{in generale perché ciò sia possibile occorre che la
+ piattaforma supporti questa caratteristica, questo viene indicato definendo
+ le macro \macro{\_POSIX\_PRIORITIZED\_IO}, e
+ \macro{\_POSIX\_PRIORITY\_SCHEDULING}.} La priorità viene impostata a
+partire da quella del processo chiamante (vedi sez.~\ref{sec:proc_priority}),
+cui viene sottratto il valore di questo campo. Il campo
+\var{aio\_lio\_opcode} è usato solo dalla funzione \func{lio\_listio}, che,
+come vedremo, permette di eseguire con una sola chiamata una serie di
+operazioni, usando un vettore di \textit{control block}. Tramite questo campo
+si specifica quale è la natura di ciascuna di esse.
+
+Infine il campo \var{aio\_sigevent} è una struttura di tipo \struct{sigevent}
+(illustrata in in fig.~\ref{fig:struct_sigevent}) che serve a specificare il
+modo in cui si vuole che venga effettuata la notifica del completamento delle
+operazioni richieste; per la trattazione delle modalità di utilizzo della
+stessa si veda quanto già visto in proposito in sez.~\ref{sec:sig_timer_adv}.
+
+Le due funzioni base dell'interfaccia per l'I/O asincrono sono
+\funcd{aio\_read} ed \funcd{aio\_write}. Esse permettono di richiedere una
+lettura od una scrittura asincrona di dati, usando la struttura \struct{aiocb}
+appena descritta; i rispettivi prototipi sono:
+\begin{functions}
+ \headdecl{aio.h}
+
+ \funcdecl{int aio\_read(struct aiocb *aiocbp)}
+ Richiede una lettura asincrona secondo quanto specificato con \param{aiocbp}.
+
+ \funcdecl{int aio\_write(struct aiocb *aiocbp)}
+ Richiede una scrittura asincrona secondo quanto specificato con
+ \param{aiocbp}.
+
+ \bodydesc{Le funzioni restituiscono 0 in caso di successo, e -1 in caso di
+ errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EBADF}] si è specificato un file descriptor sbagliato.
+ \item[\errcode{ENOSYS}] la funzione non è implementata.
+ \item[\errcode{EINVAL}] si è specificato un valore non valido per i campi
+ \var{aio\_offset} o \var{aio\_reqprio} di \param{aiocbp}.
+ \item[\errcode{EAGAIN}] la coda delle richieste è momentaneamente piena.
+ \end{errlist}
+}
+\end{functions}
+
+Entrambe le funzioni ritornano immediatamente dopo aver messo in coda la
+richiesta, o in caso di errore. Non è detto che gli errori \errcode{EBADF} ed
+\errcode{EINVAL} siano rilevati immediatamente al momento della chiamata,
+potrebbero anche emergere nelle fasi successive delle operazioni. Lettura e
+scrittura avvengono alla posizione indicata da \var{aio\_offset}, a meno che
+il file non sia stato aperto in \itindex{append~mode} \textit{append mode}
+(vedi sez.~\ref{sec:file_open}), nel qual caso le scritture vengono effettuate
+comunque alla fine de file, nell'ordine delle chiamate a \func{aio\_write}.
+
+Si tenga inoltre presente che deallocare la memoria indirizzata da
+\param{aiocbp} o modificarne i valori prima della conclusione di una
+operazione può dar luogo a risultati impredicibili, perché l'accesso ai vari
+campi per eseguire l'operazione può avvenire in un momento qualsiasi dopo la
+richiesta. Questo comporta che non si devono usare per \param{aiocbp}
+\index{variabili!automatiche} variabili automatiche e che non si deve
+riutilizzare la stessa struttura per un'altra operazione fintanto che la
+precedente non sia stata ultimata. In generale per ogni operazione si deve
+utilizzare una diversa struttura \struct{aiocb}.
+
+Dato che si opera in modalità asincrona, il successo di \func{aio\_read} o
+\func{aio\_write} non implica che le operazioni siano state effettivamente
+eseguite in maniera corretta; per verificarne l'esito l'interfaccia prevede
+altre due funzioni, che permettono di controllare lo stato di esecuzione. La
+prima è \funcd{aio\_error}, che serve a determinare un eventuale stato di
+errore; il suo prototipo è:
+\begin{prototype}{aio.h}
+ {int aio\_error(const struct aiocb *aiocbp)}
+
+ Determina lo stato di errore delle operazioni di I/O associate a
+ \param{aiocbp}.
+
+ \bodydesc{La funzione restituisce 0 se le operazioni si sono concluse con
+ successo, altrimenti restituisce il codice di errore relativo al loro
+ fallimento.}
+\end{prototype}
+
+Se l'operazione non si è ancora completata viene restituito l'errore di
+\errcode{EINPROGRESS}. La funzione ritorna zero quando l'operazione si è
+conclusa con successo, altrimenti restituisce il codice dell'errore
+verificatosi, ed esegue la corrispondente impostazione di \var{errno}. Il
+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}.
+
+Una volta che si sia certi che le operazioni siano state concluse (cioè dopo
+che una chiamata ad \func{aio\_error} non ha restituito
+\errcode{EINPROGRESS}), si potrà usare la funzione \funcd{aio\_return}, che
+permette di verificare il completamento delle operazioni di I/O asincrono; il
+suo prototipo è:
+\begin{prototype}{aio.h}
+{ssize\_t aio\_return(const struct aiocb *aiocbp)}
+
+Recupera il valore dello stato di ritorno delle operazioni di I/O associate a
+\param{aiocbp}.
+
+\bodydesc{La funzione restituisce lo stato di uscita dell'operazione
+ eseguita.}
+\end{prototype}
+
+La funzione deve essere chiamata una sola volte per ciascuna operazione
+asincrona, essa infatti fa sì che il sistema rilasci le risorse ad essa
+associate. É per questo motivo che occorre chiamare la funzione solo dopo che
+l'operazione cui \param{aiocbp} fa riferimento si è completata. Una chiamata
+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
+esaurimento.
+
+Oltre alle operazioni di lettura e scrittura l'interfaccia POSIX.1b mette a
+disposizione un'altra operazione, quella di sincronizzazione dell'I/O,
+compiuta dalla funzione \funcd{aio\_fsync}, che ha lo stesso effetto della
+analoga \func{fsync}, ma viene eseguita in maniera asincrona; il suo prototipo
+è:
+\begin{prototype}{aio.h}
+{int aio\_fsync(int op, struct aiocb *aiocbp)}
+
+Richiede la sincronizzazione dei dati per il file indicato da \param{aiocbp}.
+
+\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+ errore, che può essere, con le stesse modalità di \func{aio\_read},
+ \errval{EAGAIN}, \errval{EBADF} o \errval{EINVAL}.}
+\end{prototype}
+
+La funzione richiede la sincronizzazione delle operazioni di I/O, ritornando
+immediatamente. L'esecuzione effettiva della sincronizzazione dovrà essere
+verificata con \func{aio\_error} e \func{aio\_return} come per le operazioni
+di lettura e scrittura. L'argomento \param{op} permette di indicare la
+modalità di esecuzione, se si specifica il valore \const{O\_DSYNC} le
+operazioni saranno completate con una chiamata a \func{fdatasync}, se si
+specifica \const{O\_SYNC} con una chiamata a \func{fsync} (per i dettagli vedi
+sez.~\ref{sec:file_sync}).
+
+Il successo della chiamata assicura la sincronizzazione delle operazioni fino
+allora richieste, niente è garantito riguardo la sincronizzazione dei dati
+relativi ad eventuali operazioni richieste successivamente. Se si è
+specificato un meccanismo di notifica questo sarà innescato una volta che le
+operazioni di sincronizzazione dei dati saranno completate.
+
+In alcuni casi può essere necessario interrompere le operazioni (in genere
+quando viene richiesta un'uscita immediata dal programma), per questo lo
+standard POSIX.1b prevede una funzione apposita, \funcd{aio\_cancel}, che
+permette di cancellare una operazione richiesta in precedenza; il suo
+prototipo è:
+\begin{prototype}{aio.h}
+{int aio\_cancel(int fildes, struct aiocb *aiocbp)}
+
+Richiede la cancellazione delle operazioni sul file \param{fildes} specificate
+da \param{aiocbp}.
+
+\bodydesc{La funzione restituisce il risultato dell'operazione con un codice
+ di positivo, e -1 in caso di errore, che avviene qualora si sia specificato
+ un valore non valido di \param{fildes}, imposta \var{errno} al valore
+ \errval{EBADF}.}
+\end{prototype}
+
+La funzione permette di cancellare una operazione specifica sul file
+\param{fildes}, o tutte le operazioni pendenti, specificando \val{NULL} come
+valore di \param{aiocbp}. Quando una operazione viene cancellata una
+successiva chiamata ad \func{aio\_error} riporterà \errcode{ECANCELED} come
+codice di errore, ed il suo codice di ritorno sarà -1, inoltre il meccanismo
+di notifica non verrà invocato. Se si specifica una operazione relativa ad un
+altro file descriptor il risultato è indeterminato. In caso di successo, i
+possibili valori di ritorno per \func{aio\_cancel} (anch'essi definiti in
+\file{aio.h}) sono tre:
+\begin{basedescript}{\desclabelwidth{3.0cm}}
+\item[\const{AIO\_ALLDONE}] indica che le operazioni di cui si è richiesta la
+ cancellazione sono state già completate,
+
+\item[\const{AIO\_CANCELED}] indica che tutte le operazioni richieste sono
+ state cancellate,
+
+\item[\const{AIO\_NOTCANCELED}] indica che alcune delle operazioni erano in
+ corso e non sono state cancellate.
+\end{basedescript}
+
+Nel caso si abbia \const{AIO\_NOTCANCELED} occorrerà chiamare
+\func{aio\_error} per determinare quali sono le operazioni effettivamente
+cancellate. Le operazioni che non sono state cancellate proseguiranno il loro
+corso normale, compreso quanto richiesto riguardo al meccanismo di notifica
+del loro avvenuto completamento.
+
+Benché l'I/O asincrono preveda un meccanismo di notifica, l'interfaccia
+fornisce anche una apposita funzione, \funcd{aio\_suspend}, che permette di
+sospendere l'esecuzione del processo chiamante fino al completamento di una
+specifica operazione; il suo prototipo è:
+\begin{prototype}{aio.h}
+{int aio\_suspend(const struct aiocb * const list[], int nent, const struct
+ timespec *timeout)}
+
+ Attende, per un massimo di \param{timeout}, il completamento di una delle
+ operazioni specificate da \param{list}.
+
+ \bodydesc{La funzione restituisce 0 se una (o più) operazioni sono state
+ completate, e -1 in caso di errore nel qual caso \var{errno} assumerà uno
+ dei valori:
+ \begin{errlist}
+ \item[\errcode{EAGAIN}] nessuna operazione è stata completata entro
+ \param{timeout}.
+ \item[\errcode{ENOSYS}] la funzione non è implementata.
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
+ \end{errlist}
+ }
+\end{prototype}
+
+La funzione permette di bloccare il processo fintanto che almeno una delle
+\param{nent} operazioni specificate nella lista \param{list} è completata, per
+un tempo massimo specificato da \param{timout}, o fintanto che non arrivi un
+segnale.\footnote{si tenga conto che questo segnale può anche essere quello
+ utilizzato come meccanismo di notifica.} La lista deve essere inizializzata
+con delle strutture \struct{aiocb} relative ad operazioni effettivamente
+richieste, ma può contenere puntatori nulli, che saranno ignorati. In caso si
+siano specificati valori non validi l'effetto è indefinito. Un valore
+\val{NULL} per \param{timout} comporta l'assenza di timeout.
+
+Lo standard POSIX.1b infine ha previsto pure una funzione, \funcd{lio\_listio},
+che permette di effettuare la richiesta di una intera lista di operazioni di
+lettura o scrittura; il suo prototipo è:
+\begin{prototype}{aio.h}
+ {int lio\_listio(int mode, struct aiocb * const list[], int nent, struct
+ sigevent *sig)}
+
+ Richiede l'esecuzione delle operazioni di I/O elencata da \param{list},
+ secondo la modalità \param{mode}.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
+ errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EAGAIN}] nessuna operazione è stata completata entro
+ \param{timeout}.
+ \item[\errcode{EINVAL}] si è passato un valore di \param{mode} non valido
+ o un numero di operazioni \param{nent} maggiore di
+ \const{AIO\_LISTIO\_MAX}.
+ \item[\errcode{ENOSYS}] la funzione non è implementata.
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
+ \end{errlist}
+ }
+\end{prototype}
+
+La funzione esegue la richiesta delle \param{nent} operazioni indicate nella
+lista \param{list} che deve contenere gli indirizzi di altrettanti
+\textit{control block} opportunamente inizializzati; in particolare dovrà
+essere specificato il tipo di operazione con il campo \var{aio\_lio\_opcode},
+che può prendere i valori:
+\begin{basedescript}{\desclabelwidth{2.0cm}}
+\item[\const{LIO\_READ}] si richiede una operazione di lettura.
+\item[\const{LIO\_WRITE}] si richiede una operazione di scrittura.
+\item[\const{LIO\_NOP}] non si effettua nessuna operazione.
+\end{basedescript}
+dove \const{LIO\_NOP} viene usato quando si ha a che fare con un vettore di
+dimensione fissa, per poter specificare solo alcune operazioni, o quando si
+sono dovute cancellare delle operazioni e si deve ripetere la richiesta per
+quelle non completate.
+
+L'argomento \param{mode} controlla il comportamento della funzione, se viene
+usato il valore \const{LIO\_WAIT} la funzione si blocca fino al completamento
+di tutte le operazioni richieste; se si usa \const{LIO\_NOWAIT} la funzione
+ritorna immediatamente dopo aver messo in coda tutte le richieste. In tal caso
+il chiamante può richiedere la notifica del completamento di tutte le
+richieste, impostando l'argomento \param{sig} in maniera analoga a come si fa
+per il campo \var{aio\_sigevent} di \struct{aiocb}.
+
+
+\section{Altre modalità di I/O avanzato}
+\label{sec:file_advanced_io}
+
+Oltre alle precedenti modalità di \textit{I/O multiplexing} e \textsl{I/O
+ asincrono}, esistono altre funzioni che implementano delle modalità di
+accesso ai file più evolute rispetto alle normali funzioni di lettura e
+scrittura che abbiamo esaminato in sez.~\ref{sec:file_base_func}. In questa
+sezione allora prenderemo in esame le interfacce per l'\textsl{I/O mappato in
+ memoria}, per l'\textsl{I/O vettorizzato} e altre funzioni di I/O avanzato.
+
+
+\subsection{File mappati in memoria}
+\label{sec:file_memory_map}
+
+\itindbeg{memory~mapping}
+Una modalità alternativa di I/O, che usa una interfaccia completamente diversa
+rispetto a quella classica vista in cap.~\ref{cha:file_unix_interface}, è il
+cosiddetto \textit{memory-mapped I/O}, che, attraverso il meccanismo della
+\textsl{paginazione} \index{paginazione} usato dalla memoria virtuale (vedi
+sez.~\ref{sec:proc_mem_gen}), permette di \textsl{mappare} il contenuto di un
+file in una sezione dello spazio di indirizzi del processo che lo ha allocato.
+
+\begin{figure}[htb]
+ \centering
+ \includegraphics[width=12cm]{img/mmap_layout}
+ \caption{Disposizione della memoria di un processo quando si esegue la
+ mappatura in memoria di un file.}
+ \label{fig:file_mmap_layout}
+\end{figure}
+
+Il meccanismo è illustrato in fig.~\ref{fig:file_mmap_layout}, una sezione del
+file viene \textsl{mappata} direttamente nello spazio degli indirizzi del
+programma. Tutte le operazioni di lettura e scrittura su variabili contenute
+in questa zona di memoria verranno eseguite leggendo e scrivendo dal contenuto
+del file attraverso il sistema della memoria virtuale \index{memoria~virtuale}
+che in maniera analoga a quanto avviene per le pagine che vengono salvate e
+rilette nella swap, si incaricherà di sincronizzare il contenuto di quel
+segmento di memoria con quello del file mappato su di esso. Per questo motivo
+si può parlare tanto di \textsl{file mappato in memoria}, quanto di
+\textsl{memoria mappata su file}.
+
+L'uso del \textit{memory-mapping} comporta una notevole semplificazione delle
+operazioni di I/O, in quanto non sarà più necessario utilizzare dei buffer
+intermedi su cui appoggiare i dati da traferire, poiché questi potranno essere
+acceduti direttamente nella sezione di memoria mappata; inoltre questa
+interfaccia è più efficiente delle usuali funzioni di I/O, in quanto permette
+di caricare in memoria solo le parti del file che sono effettivamente usate ad
+un dato istante.
+
+Infatti, dato che l'accesso è fatto direttamente attraverso la
+\index{memoria~virtuale} memoria virtuale, la sezione di memoria mappata su
+cui si opera sarà a sua volta letta o scritta sul file una pagina alla volta e
+solo per le parti effettivamente usate, il tutto in maniera completamente
+trasparente al processo; l'accesso alle pagine non ancora caricate avverrà
+allo stesso modo con cui vengono caricate in memoria le pagine che sono state
+salvate sullo swap.
+
+Infine in situazioni in cui la memoria è scarsa, le pagine che mappano un file
+vengono salvate automaticamente, così come le pagine dei programmi vengono
+scritte sulla swap; questo consente di accedere ai file su dimensioni il cui
+solo limite è quello dello spazio di indirizzi disponibile, e non della
+memoria su cui possono esserne lette delle porzioni.
+
+L'interfaccia POSIX implementata da Linux prevede varie funzioni per la
+gestione del \textit{memory mapped I/O}, la prima di queste, che serve ad
+eseguire la mappatura in memoria di un file, è \funcd{mmap}; il suo prototipo
+è:
+\begin{functions}
+
+ \headdecl{unistd.h}
+ \headdecl{sys/mman.h}
+
+ \funcdecl{void * mmap(void * start, size\_t length, int prot, int flags, int
+ fd, off\_t offset)}
+
+ Esegue la mappatura in memoria della sezione specificata del file \param{fd}.
+
+ \bodydesc{La funzione restituisce il puntatore alla zona di memoria mappata
+ in caso di successo, e \const{MAP\_FAILED} (-1) in caso di errore, nel
+ qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EBADF}] il file descriptor non è valido, e non si è usato
+ \const{MAP\_ANONYMOUS}.
+ \item[\errcode{EACCES}] o \param{fd} non si riferisce ad un file regolare,
+ o si è usato \const{MAP\_PRIVATE} ma \param{fd} non è aperto in lettura,
+ o si è usato \const{MAP\_SHARED} e impostato \const{PROT\_WRITE} ed
+ \param{fd} non è aperto in lettura/scrittura, o si è impostato
+ \const{PROT\_WRITE} ed \param{fd} è in \textit{append-only}.
+ \item[\errcode{EINVAL}] i valori di \param{start}, \param{length} o
+ \param{offset} non sono validi (o troppo grandi o non allineati sulla
+ dimensione delle pagine).
+ \item[\errcode{ETXTBSY}] si è impostato \const{MAP\_DENYWRITE} ma
+ \param{fd} è aperto in scrittura.
+ \item[\errcode{EAGAIN}] il file è bloccato, o si è bloccata troppa memoria
+ rispetto a quanto consentito dai limiti di sistema (vedi
+ sez.~\ref{sec:sys_resource_limit}).
+ \item[\errcode{ENOMEM}] non c'è memoria o si è superato il limite sul
+ numero di mappature possibili.
+ \item[\errcode{ENODEV}] il filesystem di \param{fd} non supporta il memory
+ mapping.
+ \item[\errcode{EPERM}] l'argomento \param{prot} ha richiesto
+ \const{PROT\_EXEC}, ma il filesystem di \param{fd} è montato con
+ l'opzione \texttt{noexec}.
+ \item[\errcode{ENFILE}] si è superato il limite del sistema sul numero di
+ file aperti (vedi sez.~\ref{sec:sys_resource_limit}).
+ \end{errlist}
+ }
+\end{functions}
+
+La funzione richiede di mappare in memoria la sezione del file \param{fd} a
+partire da \param{offset} per \param{length} byte, preferibilmente
+all'indirizzo \param{start}. Il valore di \param{offset} deve essere un
+multiplo della dimensione di una pagina di memoria.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|l|}
+ \hline
+ \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{PROT\_EXEC} & Le pagine possono essere eseguite.\\
+ \const{PROT\_READ} & Le pagine possono essere lette.\\
+ \const{PROT\_WRITE} & Le pagine possono essere scritte.\\
+ \const{PROT\_NONE} & L'accesso alle pagine è vietato.\\
+ \hline
+ \end{tabular}
+ \caption{Valori dell'argomento \param{prot} di \func{mmap}, relativi alla
+ protezione applicate alle pagine del file mappate in memoria.}
+ \label{tab:file_mmap_prot}
+\end{table}
+
+Il valore dell'argomento \param{prot} indica la protezione\footnote{come
+ accennato in sez.~\ref{sec:proc_memory} in Linux la memoria reale è divisa
+ in pagine: ogni processo vede la sua memoria attraverso uno o più segmenti
+ lineari di memoria virtuale. Per ciascuno di questi segmenti il kernel
+ mantiene nella \itindex{page~table} \textit{page table} la mappatura sulle
+ pagine di memoria reale, ed le modalità di accesso (lettura, esecuzione,
+ scrittura); una loro violazione causa quella una \itindex{segment~violation}
+ \textit{segment violation}, e la relativa emissione del segnale
+ \signal{SIGSEGV}.} da applicare al segmento di memoria e deve essere
+specificato come maschera binaria ottenuta dall'OR di uno o più dei valori
+riportati in tab.~\ref{tab:file_mmap_prot}; il valore specificato deve essere
+compatibile con la modalità di accesso con cui si è aperto il file.
+
+L'argomento \param{flags} specifica infine qual è il tipo di oggetto mappato,
+le opzioni relative alle modalità con cui è effettuata la mappatura e alle
+modalità con cui le modifiche alla memoria mappata vengono condivise o
+mantenute private al processo che le ha effettuate. Deve essere specificato
+come maschera binaria ottenuta dall'OR di uno o più dei valori riportati in
+tab.~\ref{tab:file_mmap_flag}.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|p{11cm}|}
+ \hline
+ \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{MAP\_FIXED} & Non permette di restituire un indirizzo diverso
+ da \param{start}, se questo non può essere usato
+ \func{mmap} fallisce. Se si imposta questo flag il
+ valore di \param{start} deve essere allineato
+ alle dimensioni di una pagina.\\
+ \const{MAP\_SHARED} & I cambiamenti sulla memoria mappata vengono
+ riportati sul file e saranno immediatamente
+ visibili agli altri processi che mappano lo stesso
+ file.\footnotemark Il file su disco però non sarà
+ aggiornato fino alla chiamata di \func{msync} o
+ \func{munmap}), e solo allora le modifiche saranno
+ visibili per l'I/O convenzionale. Incompatibile
+ con \const{MAP\_PRIVATE}.\\
+ \const{MAP\_PRIVATE} & I cambiamenti sulla memoria mappata non vengono
+ riportati sul file. Ne viene fatta una copia
+ privata cui solo il processo chiamante ha
+ accesso. Le modifiche sono mantenute attraverso
+ il meccanismo del \textit{copy on
+ write} \itindex{copy~on~write} e
+ salvate su swap in caso di necessità. Non è
+ specificato se i cambiamenti sul file originale
+ vengano riportati sulla regione
+ mappata. Incompatibile con \const{MAP\_SHARED}.\\
+ \const{MAP\_DENYWRITE} & In Linux viene ignorato per evitare
+ \textit{DoS} \itindex{Denial~of~Service~(DoS)}
+ (veniva usato per segnalare che tentativi di
+ scrittura sul file dovevano fallire con
+ \errcode{ETXTBSY}).\\
+ \const{MAP\_EXECUTABLE}& Ignorato.\\
+ \const{MAP\_NORESERVE} & Si usa con \const{MAP\_PRIVATE}. Non riserva
+ delle pagine di swap ad uso del meccanismo del
+ \textit{copy on write} \itindex{copy~on~write}
+ per mantenere le
+ modifiche fatte alla regione mappata, in
+ questo caso dopo una scrittura, se non c'è più
+ memoria disponibile, si ha l'emissione di
+ un \signal{SIGSEGV}.\\
+ \const{MAP\_LOCKED} & Se impostato impedisce lo swapping delle pagine
+ mappate.\\
+ \const{MAP\_GROWSDOWN} & Usato per gli \itindex{stack} \textit{stack}.
+ Indica che la mappatura deve essere effettuata
+ con gli indirizzi crescenti verso il basso.\\
+ \const{MAP\_ANONYMOUS} & La mappatura non è associata a nessun file. Gli
+ argomenti \param{fd} e \param{offset} sono
+ ignorati.\footnotemark\\
+ \const{MAP\_ANON} & Sinonimo di \const{MAP\_ANONYMOUS}, deprecato.\\
+ \const{MAP\_FILE} & Valore di compatibilità, ignorato.\\
+ \const{MAP\_32BIT} & Esegue la mappatura sui primi 2Gb dello spazio
+ degli indirizzi, viene supportato solo sulle
+ piattaforme \texttt{x86-64} per compatibilità con
+ le applicazioni a 32 bit. Viene ignorato se si è
+ richiesto \const{MAP\_FIXED}.\\
+ \const{MAP\_POPULATE} & Esegue il \itindex{prefaulting}
+ \textit{prefaulting} delle pagine di memoria
+ necessarie alla mappatura.\\
+ \const{MAP\_NONBLOCK} & Esegue un \textit{prefaulting} più limitato che
+ non causa I/O.\footnotemark\\
+% \const{MAP\_DONTEXPAND}& Non consente una successiva espansione dell'area
+% mappata con \func{mremap}, proposto ma pare non
+% implementato.\\
+ \hline
+ \end{tabular}
+ \caption{Valori possibili dell'argomento \param{flag} di \func{mmap}.}
+ \label{tab:file_mmap_flag}
+\end{table}
+
+\footnotetext[68]{dato che tutti faranno riferimento alle stesse pagine di
+ memoria.}
+
+\footnotetext[69]{l'uso di questo flag con \const{MAP\_SHARED} è stato
+ implementato in Linux a partire dai kernel della serie 2.4.x; esso consente
+ di creare segmenti di memoria condivisa e torneremo sul suo utilizzo in
+ sez.~\ref{sec:ipc_mmap_anonymous}.}
+
+\footnotetext{questo flag ed il precedente \const{MAP\_POPULATE} sono stati
+ introdotti nel kernel 2.5.46 insieme alla mappatura non lineare di cui
+ parleremo più avanti.}
+
+Gli effetti dell'accesso ad una zona di memoria mappata su file possono essere
+piuttosto complessi, essi si possono comprendere solo tenendo presente che
+tutto quanto è comunque basato sul meccanismo della \index{memoria~virtuale}
+memoria virtuale. Questo comporta allora una serie di conseguenze. La più
+ovvia è che se si cerca di scrivere su una zona mappata in sola lettura si
+avrà l'emissione di un segnale di violazione di accesso (\signal{SIGSEGV}),
+dato che i permessi sul segmento di memoria relativo non consentono questo
+tipo di accesso.
+
+È invece assai diversa la questione relativa agli accessi al di fuori della
+regione di cui si è richiesta la mappatura. A prima vista infatti si potrebbe
+ritenere che anch'essi debbano generare un segnale di violazione di accesso;
+questo però non tiene conto del fatto che, essendo basata sul meccanismo della
+\index{paginazione} paginazione, la mappatura in memoria non può che essere
+eseguita su un segmento di dimensioni rigorosamente multiple di quelle di una
+pagina, ed in generale queste potranno non corrispondere alle dimensioni
+effettive del file o della sezione che si vuole mappare.
+
+\begin{figure}[!htb]
+ \centering
+ \includegraphics[height=6cm]{img/mmap_boundary}
+ \caption{Schema della mappatura in memoria di una sezione di file di
+ dimensioni non corrispondenti al bordo di una pagina.}
+ \label{fig:file_mmap_boundary}
+\end{figure}
+
+Il caso più comune è quello illustrato in fig.~\ref{fig:file_mmap_boundary},
+in cui la sezione di file non rientra nei confini di una pagina: in tal caso
+verrà il file sarà mappato su un segmento di memoria che si estende fino al
+bordo della pagina successiva.
+
+In questo caso è possibile accedere a quella zona di memoria che eccede le
+dimensioni specificate da \param{length}, senza ottenere un \signal{SIGSEGV}
+poiché essa è presente nello spazio di indirizzi del processo, anche se non è
+mappata sul file. Il comportamento del sistema è quello di restituire un
+valore nullo per quanto viene letto, e di non riportare su file quanto viene
+scritto.
+
+Un caso più complesso è quello che si viene a creare quando le dimensioni del
+file mappato sono più corte delle dimensioni della mappatura, oppure quando il
+file è stato troncato, dopo che è stato mappato, ad una dimensione inferiore a
+quella della mappatura in memoria.
+
+In questa situazione, per la sezione di pagina parzialmente coperta dal
+contenuto del file, vale esattamente quanto visto in precedenza; invece per la
+parte che eccede, fino alle dimensioni date da \param{length}, l'accesso non
+sarà più possibile, ma il segnale emesso non sarà \signal{SIGSEGV}, ma
+\signal{SIGBUS}, come illustrato in fig.~\ref{fig:file_mmap_exceed}.
+
+Non tutti i file possono venire mappati in memoria, dato che, come illustrato
+in fig.~\ref{fig:file_mmap_layout}, la mappatura introduce una corrispondenza
+biunivoca fra una sezione di un file ed una sezione di memoria. Questo
+comporta che ad esempio non è possibile mappare in memoria file descriptor
+relativi a pipe, socket e fifo, per i quali non ha senso parlare di
+\textsl{sezione}. Lo stesso vale anche per alcuni file di dispositivo, che non
+dispongono della relativa operazione \func{mmap} (si ricordi quanto esposto in
+sez.~\ref{sec:file_vfs_work}). Si tenga presente però che esistono anche casi
+di dispositivi (un esempio è l'interfaccia al ponte PCI-VME del chip Universe)
+che sono utilizzabili solo con questa interfaccia.
+
+\begin{figure}[htb]
+ \centering
+ \includegraphics[height=6cm]{img/mmap_exceed}
+ \caption{Schema della mappatura in memoria di file di dimensioni inferiori
+ alla lunghezza richiesta.}
+ \label{fig:file_mmap_exceed}
+\end{figure}
+
+Dato che passando attraverso una \func{fork} lo spazio di indirizzi viene
+copiato integralmente, i file mappati in memoria verranno ereditati in maniera
+trasparente dal processo figlio, mantenendo gli stessi attributi avuti nel
+padre; così se si è usato \const{MAP\_SHARED} padre e figlio accederanno allo
+stesso file in maniera condivisa, mentre se si è usato \const{MAP\_PRIVATE}
+ciascuno di essi manterrà una sua versione privata indipendente. Non c'è
+invece nessun passaggio attraverso una \func{exec}, dato che quest'ultima
+sostituisce tutto lo spazio degli indirizzi di un processo con quello di un
+nuovo programma.
+
+Quando si effettua la mappatura di un file vengono pure modificati i tempi ad
+esso associati (di cui si è trattato in sez.~\ref{sec:file_file_times}). Il
+valore di \var{st\_atime} può venir cambiato in qualunque istante a partire
+dal momento in cui la mappatura è stata effettuata: il primo riferimento ad
+una pagina mappata su un file aggiorna questo tempo. I valori di
+\var{st\_ctime} e \var{st\_mtime} possono venir cambiati solo quando si è
+consentita la scrittura sul file (cioè per un file mappato con
+\const{PROT\_WRITE} e \const{MAP\_SHARED}) e sono aggiornati dopo la scrittura
+o in corrispondenza di una eventuale \func{msync}.
+
+Dato per i file mappati in memoria le operazioni di I/O sono gestite
+direttamente dalla \index{memoria~virtuale}memoria virtuale, occorre essere
+consapevoli delle interazioni che possono esserci con operazioni effettuate
+con l'interfaccia standard dei file di cap.~\ref{cha:file_unix_interface}. Il
+problema è che una volta che si è mappato un file, le operazioni di lettura e
+scrittura saranno eseguite sulla memoria, e riportate su disco in maniera
+autonoma dal sistema della memoria virtuale.
+
+Pertanto se si modifica un file con l'interfaccia standard queste modifiche
+potranno essere visibili o meno a seconda del momento in cui la memoria
+virtuale trasporterà dal disco in memoria quella sezione del file, perciò è
+del tutto imprevedibile il risultato della modifica di un file nei confronti
+del contenuto della memoria su cui è mappato.
+
+Per questo, è sempre sconsigliabile eseguire scritture su file attraverso
+l'interfaccia standard quando lo si è mappato in memoria, è invece possibile
+usare l'interfaccia standard per leggere un file mappato in memoria, purché si
+abbia una certa cura; infatti l'interfaccia dell'I/O mappato in memoria mette
+a disposizione la funzione \funcd{msync} per sincronizzare il contenuto della
+memoria mappata con il file su disco; il suo prototipo è:
+\begin{functions}
+ \headdecl{unistd.h}
+ \headdecl{sys/mman.h}
+
+ \funcdecl{int msync(const void *start, size\_t length, int flags)}
+
+ Sincronizza i contenuti di una sezione di un file mappato in memoria.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
+ errore nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] o \param{start} non è multiplo di
+ \const{PAGE\_SIZE}, o si è specificato un valore non valido per
+ \param{flags}.
+ \item[\errcode{EFAULT}] l'intervallo specificato non ricade in una zona
+ precedentemente mappata.
+ \end{errlist}
+ }
+\end{functions}
+
+La funzione esegue la sincronizzazione di quanto scritto nella sezione di
+memoria indicata da \param{start} e \param{offset}, scrivendo le modifiche sul
+file (qualora questo non sia già stato fatto). Provvede anche ad aggiornare i
+relativi tempi di modifica. In questo modo si è sicuri che dopo l'esecuzione
+di \func{msync} le funzioni dell'interfaccia standard troveranno un contenuto
+del file aggiornato.
+
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|p{11cm}|}
+ \hline
+ \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{MS\_SYNC} & richiede una sincronizzazione e ritorna soltanto
+ quando questa è stata completata.\\
+ \const{MS\_ASYNC} & richiede una sincronizzazione, ma ritorna subito
+ non attendendo che questa sia finita.\\
+ \const{MS\_INVALIDATE} & invalida le pagine per tutte le mappature
+ in memoria così da rendere necessaria una
+ rilettura immediata delle stesse.\\
+ \hline
+ \end{tabular}
+ \caption{Valori possibili dell'argomento \param{flag} di \func{msync}.}
+ \label{tab:file_mmap_msync}
+\end{table}
+
+L'argomento \param{flag} è specificato come maschera binaria composta da un OR
+dei valori riportati in tab.~\ref{tab:file_mmap_msync}, di questi però
+\const{MS\_ASYNC} e \const{MS\_SYNC} sono incompatibili; con il primo valore
+infatti la funzione si limita ad inoltrare la richiesta di sincronizzazione al
+meccanismo della memoria virtuale, ritornando subito, mentre con il secondo
+attende che la sincronizzazione sia stata effettivamente eseguita. Il terzo
+flag fa sì che vengano invalidate, per tutte le mappature dello stesso file,
+le pagine di cui si è richiesta la sincronizzazione, così che esse possano
+essere immediatamente aggiornate con i nuovi valori.
+
+Una volta che si sono completate le operazioni di I/O si può eliminare la
+mappatura della memoria usando la funzione \funcd{munmap}, il suo prototipo è:
+\begin{functions}
+ \headdecl{unistd.h}
+ \headdecl{sys/mman.h}
+
+ \funcdecl{int munmap(void *start, size\_t length)}
+
+ Rilascia la mappatura sulla sezione di memoria specificata.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
+ errore nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] l'intervallo specificato non ricade in una zona
+ precedentemente mappata.
+ \end{errlist}
+ }
+\end{functions}
+
+La funzione cancella la mappatura per l'intervallo specificato con
+\param{start} e \param{length}; ogni successivo accesso a tale regione causerà
+un errore di accesso in memoria. L'argomento \param{start} deve essere
+allineato alle dimensioni di una pagina, e la mappatura di tutte le pagine
+contenute anche parzialmente nell'intervallo indicato, verrà rimossa.
+Indicare un intervallo che non contiene mappature non è un errore. Si tenga
+presente inoltre che alla conclusione di un processo ogni pagina mappata verrà
+automaticamente rilasciata, mentre la chiusura del file descriptor usato per
+il \textit{memory mapping} non ha alcun effetto su di esso.
+
+Lo standard POSIX prevede anche una funzione che permetta di cambiare le
+protezioni delle pagine di memoria; lo standard prevede che essa si applichi
+solo ai \textit{memory mapping} creati con \func{mmap}, ma nel caso di Linux
+la funzione può essere usata con qualunque pagina valida nella memoria
+virtuale. Questa funzione è \funcd{mprotect} ed il suo prototipo è:
+\begin{functions}
+% \headdecl{unistd.h}
+ \headdecl{sys/mman.h}
+
+ \funcdecl{int mprotect(const void *addr, size\_t len, int prot)}
+
+ Modifica le protezioni delle pagine di memoria comprese nell'intervallo
+ specificato.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
+ errore nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] il valore di \param{addr} non è valido o non è un
+ multiplo di \const{PAGE\_SIZE}.
+ \item[\errcode{EACCESS}] l'operazione non è consentita, ad esempio si è
+ cercato di marcare con \const{PROT\_WRITE} un segmento di memoria cui si
+ ha solo accesso in lettura.
+% \item[\errcode{ENOMEM}] non è stato possibile allocare le risorse
+% necessarie all'interno del kernel.
+% \item[\errcode{EFAULT}] si è specificato un indirizzo di memoria non
+% accessibile.
+ \end{errlist}
+ ed inoltre \errval{ENOMEM} ed \errval{EFAULT}.
+ }
+\end{functions}
+
+
+La funzione prende come argomenti un indirizzo di partenza in \param{addr},
+allineato alle dimensioni delle pagine di memoria, ed una dimensione
+\param{size}. La nuova protezione deve essere specificata in \param{prot} con
+una combinazione dei valori di tab.~\ref{tab:file_mmap_prot}. La nuova
+protezione verrà applicata a tutte le pagine contenute, anche parzialmente,
+dall'intervallo fra \param{addr} e \param{addr}+\param{size}-1.
+
+Infine Linux supporta alcune operazioni specifiche non disponibili su altri
+kernel unix-like. La prima di queste è la possibilità di modificare un
+precedente \textit{memory mapping}, ad esempio per espanderlo o restringerlo.
+Questo è realizzato dalla funzione \funcd{mremap}, il cui prototipo è:
+\begin{functions}
+ \headdecl{unistd.h}
+ \headdecl{sys/mman.h}
+
+ \funcdecl{void * mremap(void *old\_address, size\_t old\_size , size\_t
+ new\_size, unsigned long flags)}
+
+ Restringe o allarga una mappatura in memoria di un file.
+
+ \bodydesc{La funzione restituisce l'indirizzo alla nuova area di memoria in
+ caso di successo od il valore \const{MAP\_FAILED} (pari a \texttt{(void *)
+ -1}) in caso di errore, nel qual caso \var{errno} assumerà uno dei
+ valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] il valore di \param{old\_address} non è un
+ puntatore valido.
+ \item[\errcode{EFAULT}] ci sono indirizzi non validi nell'intervallo
+ specificato da \param{old\_address} e \param{old\_size}, o ci sono altre
+ mappature di tipo non corrispondente a quella richiesta.
+ \item[\errcode{ENOMEM}] non c'è memoria sufficiente oppure l'area di
+ memoria non può essere espansa all'indirizzo virtuale corrente, e non si
+ è specificato \const{MREMAP\_MAYMOVE} nei flag.
+ \item[\errcode{EAGAIN}] il segmento di memoria scelto è bloccato e non può
+ essere rimappato.
+ \end{errlist}
+ }
+\end{functions}
+
+La funzione richiede come argomenti \param{old\_address} (che deve essere
+allineato alle dimensioni di una pagina di memoria) che specifica il
+precedente indirizzo del \textit{memory mapping} e \param{old\_size}, che ne
+indica la dimensione. Con \param{new\_size} si specifica invece la nuova
+dimensione che si vuole ottenere. Infine l'argomento \param{flags} è una
+maschera binaria per i flag che controllano il comportamento della funzione.
+Il solo valore utilizzato è \const{MREMAP\_MAYMOVE}\footnote{per poter
+ utilizzare questa costante occorre aver definito \macro{\_GNU\_SOURCE} prima
+ di includere \file{sys/mman.h}.} che consente di eseguire l'espansione
+anche quando non è possibile utilizzare il precedente indirizzo. Per questo
+motivo, se si è usato questo flag, la funzione può restituire un indirizzo
+della nuova zona di memoria che non è detto coincida con \param{old\_address}.
+
+La funzione si appoggia al sistema della \index{memoria~virtuale} memoria
+virtuale per modificare l'associazione fra gli indirizzi virtuali del processo
+e le pagine di memoria, modificando i dati direttamente nella
+\itindex{page~table} \textit{page table} del processo. Come per
+\func{mprotect} la funzione può essere usata in generale, anche per pagine di
+memoria non corrispondenti ad un \textit{memory mapping}, e consente così di
+implementare la funzione \func{realloc} in maniera molto efficiente.
+
+Una caratteristica comune a tutti i sistemi unix-like è che la mappatura in
+memoria di un file viene eseguita in maniera lineare, cioè parti successive di
+un file vengono mappate linearmente su indirizzi successivi in memoria.
+Esistono però delle applicazioni\footnote{in particolare la tecnica è usata
+ dai database o dai programmi che realizzano macchine virtuali.} in cui è
+utile poter mappare sezioni diverse di un file su diverse zone di memoria.
+
+Questo è ovviamente sempre possibile eseguendo ripetutamente la funzione
+\func{mmap} per ciascuna delle diverse aree del file che si vogliono mappare
+in sequenza non lineare,\footnote{ed in effetti è quello che veniva fatto
+ anche con Linux prima che fossero introdotte queste estensioni.} ma questo
+approccio ha delle conseguenze molto pesanti in termini di prestazioni.
+Infatti per ciascuna mappatura in memoria deve essere definita nella
+\itindex{page~table} \textit{page table} del processo una nuova area di
+memoria virtuale\footnote{quella che nel gergo del kernel viene chiamata VMA
+ (\textit{virtual memory area}).} che corrisponda alla mappatura, in modo che
+questa diventi visibile nello spazio degli indirizzi come illustrato in
+fig.~\ref{fig:file_mmap_layout}.
+
+Quando un processo esegue un gran numero di mappature diverse\footnote{si può
+ arrivare anche a centinaia di migliaia.} per realizzare a mano una mappatura
+non-lineare si avrà un accrescimento eccessivo della sua \itindex{page~table}
+\textit{page table}, e lo stesso accadrà per tutti gli altri processi che
+utilizzano questa tecnica. In situazioni in cui le applicazioni hanno queste
+esigenze si avranno delle prestazioni ridotte, dato che il kernel dovrà
+impiegare molte risorse\footnote{sia in termini di memoria interna per i dati
+ delle \itindex{page~table} \textit{page table}, che di CPU per il loro
+ aggiornamento.} solo per mantenere i dati di una gran quantità di
+\textit{memory mapping}.
+
+Per questo motivo con il kernel 2.5.46 è stato introdotto, ad opera di Ingo
+Molnar, un meccanismo che consente la mappatura non-lineare. Anche questa è
+una caratteristica specifica di Linux, non presente in altri sistemi
+unix-like. Diventa così possibile utilizzare una sola mappatura
+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 è:
+\begin{functions}
+ \headdecl{sys/mman.h}
+
+ \funcdecl{int remap\_file\_pages(void *start, size\_t size, int prot,
+ ssize\_t pgoff, int flags)}
+
+ Permette di rimappare non linearmente un precedente \textit{memory mapping}.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
+ errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] si è usato un valore non valido per uno degli
+ argomenti o \param{start} non fa riferimento ad un \textit{memory
+ mapping} valido creato con \const{MAP\_SHARED}.
+ \end{errlist}
+ }
+\end{functions}
+
+Per poter utilizzare questa funzione occorre anzitutto effettuare
+preliminarmente una chiamata a \func{mmap} con \const{MAP\_SHARED} per
+definire l'area di memoria che poi sarà rimappata non linearmente. Poi di
+chiamerà questa funzione per modificare le corrispondenze fra pagine di
+memoria e pagine del file; si tenga presente che \func{remap\_file\_pages}
+permette anche di mappare la stessa pagina di un file in più pagine della
+regione mappata.
+
+La funzione richiede che si identifichi la sezione del file che si vuole
+riposizionare all'interno del \textit{memory mapping} con gli argomenti
+\param{pgoff} e \param{size}; l'argomento \param{start} invece deve indicare
+un indirizzo all'interno dell'area definita dall'\func{mmap} iniziale, a
+partire dal quale la sezione di file indicata verrà rimappata. L'argomento
+\param{prot} deve essere sempre nullo, mentre \param{flags} prende gli stessi
+valori di \func{mmap} (quelli di tab.~\ref{tab:file_mmap_prot}) ma di tutti i
+flag solo \const{MAP\_NONBLOCK} non viene ignorato.
+
+Insieme alla funzione \func{remap\_file\_pages} nel kernel 2.5.46 con sono
+stati introdotti anche due nuovi flag per \func{mmap}: \const{MAP\_POPULATE} e
+\const{MAP\_NONBLOCK}. Il primo dei due consente di abilitare il meccanismo
+del \itindex{prefaulting} \textit{prefaulting}. Questo viene di nuovo in aiuto
+per migliorare le prestazioni in certe condizioni di utilizzo del
+\textit{memory mapping}.
+
+Il problema si pone tutte le volte che si vuole mappare in memoria un file di
+grosse dimensioni. Il comportamento normale del sistema della
+\index{memoria~virtuale} memoria virtuale è quello per cui la regione mappata
+viene aggiunta alla \itindex{page~table} \textit{page table} del processo, ma
+i dati verranno effettivamente utilizzati (si avrà cioè un
+\itindex{page~fault} \textit{page fault} che li trasferisce dal disco alla
+memoria) soltanto in corrispondenza dell'accesso a ciascuna delle pagine
+interessate dal \textit{memory mapping}.
+
+Questo vuol dire che il passaggio dei dati dal disco alla memoria avverrà una
+pagina alla volta con un gran numero di \itindex{page~fault} \textit{page
+ fault}, chiaramente se si sa in anticipo che il file verrà utilizzato
+immediatamente, è molto più efficiente eseguire un \itindex{prefaulting}
+\textit{prefaulting} in cui tutte le pagine di memoria interessate alla
+mappatura vengono ``\textsl{popolate}'' in una sola volta, questo
+comportamento viene abilitato quando si usa con \func{mmap} il flag
+\const{MAP\_POPULATE}.
+
+Dato che l'uso di \const{MAP\_POPULATE} comporta dell'I/O su disco che può
+rallentare l'esecuzione di \func{mmap} è stato introdotto anche un secondo
+flag, \const{MAP\_NONBLOCK}, che esegue un \itindex{prefaulting}
+\textit{prefaulting} più limitato in cui vengono popolate solo le pagine della
+mappatura che già si trovano nella cache del kernel.\footnote{questo può
+ essere utile per il linker dinamico, in particolare quando viene effettuato
+ il \textit{prelink} delle applicazioni.}
+
+Per i vantaggi illustrati all'inizio del paragrafo l'interfaccia del
+\textit{memory mapped I/O} viene usata da una grande varietà di programmi,
+spesso con esigenze molto diverse fra di loro riguardo le modalità con cui
+verranno eseguiti gli accessi ad un file; è ad esempio molto comune per i
+database effettuare accessi ai dati in maniera pressoché casuale, mentre un
+riproduttore audio o video eseguirà per lo più letture sequenziali.
+
+Per migliorare le prestazioni a seconda di queste modalità di accesso è
+disponibile una apposita funzione, \funcd{madvise},\footnote{tratteremo in
+ sez.~\ref{sec:file_fadvise} le funzioni che consentono di ottimizzare
+ l'accesso ai file con l'interfaccia classica.} che consente di fornire al
+kernel delle indicazioni su dette modalità, così che possano essere adottate
+le opportune strategie di ottimizzazione. Il suo prototipo è:
+\begin{functions}
+ \headdecl{sys/mman.h}
+
+ \funcdecl{int madvise(void *start, size\_t length, int advice)}
+
+ Fornisce indicazioni sull'uso previsto di un \textit{memory mapping}.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
+ errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EBADF}] la mappatura esiste ma non corrisponde ad un file.
+ \item[\errcode{EINVAL}] \param{start} non è allineato alla dimensione di
+ una pagina, \param{length} ha un valore negativo, o \param{advice} non è
+ un valore valido, o si è richiesto il rilascio (con
+ \const{MADV\_DONTNEED}) di pagine bloccate o condivise.
+ \item[\errcode{EIO}] la paginazione richiesta eccederebbe i limiti (vedi
+ sez.~\ref{sec:sys_resource_limit}) sulle pagine residenti in memoria del
+ processo (solo in caso di \const{MADV\_WILLNEED}).
+ \item[\errcode{ENOMEM}] gli indirizzi specificati non sono mappati, o, in
+ caso \const{MADV\_WILLNEED}, non c'è sufficiente memoria per soddisfare
+ la richiesta.
+ \end{errlist}
+ ed inoltre \errval{EAGAIN} e \errval{ENOSYS}.
+ }
+\end{functions}
+
+La sezione di memoria sulla quale si intendono fornire le indicazioni deve
+essere indicata con l'indirizzo iniziale \param{start} e l'estensione
+\param{length}, il valore di \param{start} deve essere allineato,
+mentre \param{length} deve essere un numero positivo.\footnote{la versione di
+ Linux consente anche un valore nullo per \param{length}, inoltre se una
+ parte dell'intervallo non è mappato in memoria l'indicazione viene comunque
+ applicata alle restanti parti, anche se la funzione ritorna un errore di
+ \errval{ENOMEM}.} L'indicazione viene espressa dall'argomento \param{advice}
+che deve essere specificato con uno dei valori\footnote{si tenga presente che
+ gli ultimi tre valori sono specifici di Linux (introdotti a partire dal
+ kernel 2.6.16) e non previsti dallo standard POSIX.1b.} riportati in
+tab.~\ref{tab:madvise_advice_values}.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|p{10 cm}|}
+ \hline
+ \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{MADV\_NORMAL} & nessuna indicazione specifica, questo è il valore
+ di default usato quando non si è chiamato
+ \func{madvise}.\\
+ \const{MADV\_RANDOM} & ci si aspetta un accesso casuale all'area
+ indicata, pertanto l'applicazione di una lettura
+ anticipata con il meccanismo del
+ \itindex{read-ahead} \textit{read-ahead} (vedi
+ sez.~\ref{sec:file_fadvise}) è di
+ scarsa utilità e verrà disabilitata.\\
+ \const{MADV\_SEQUENTIAL}& ci si aspetta un accesso sequenziale al file,
+ quindi da una parte sarà opportuno eseguire una
+ lettura anticipata, e dall'altra si potranno
+ scartare immediatamente le pagine una volta che
+ queste siano state lette.\\
+ \const{MADV\_WILLNEED}& ci si aspetta un accesso nell'immediato futuro,
+ pertanto l'applicazione del \textit{read-ahead}
+ deve essere incentivata.\\
+ \const{MADV\_DONTNEED}& non ci si aspetta nessun accesso nell'immediato
+ futuro, pertanto le pagine possono essere
+ liberate dal kernel non appena necessario; l'area
+ di memoria resterà accessibile, ma un accesso
+ richiederà che i dati vengano ricaricati dal file
+ a cui la mappatura fa riferimento.\\
+ \hline
+ \const{MADV\_REMOVE} & libera un intervallo di pagine di memoria ed il
+ relativo supporto sottostante; è supportato
+ soltanto sui filesystem in RAM \textit{tmpfs} e
+ \textit{shmfs}.\footnotemark\\
+ \const{MADV\_DONTFORK}& impedisce che l'intervallo specificato venga
+ ereditato dal processo figlio dopo una
+ \func{fork}; questo consente di evitare che il
+ meccanismo del \itindex{copy~on~write}
+ \textit{copy on write} effettui la rilocazione
+ delle pagine quando il padre scrive sull'area
+ di memoria dopo la \func{fork}, cosa che può
+ causare problemi per l'hardware che esegue
+ operazioni in DMA su quelle pagine.\\
+ \const{MADV\_DOFORK} & rimuove l'effetto della precedente
+ \const{MADV\_DONTFORK}.\\
+ \const{MADV\_MERGEABLE}& marca la pagina come accorpabile (indicazione
+ principalmente ad uso dei sistemi di
+ virtualizzazione).\footnotemark\\
+ \hline
+ \end{tabular}
+ \caption{Valori dell'argomento \param{advice} di \func{madvise}.}
+ \label{tab:madvise_advice_values}
+\end{table}
+
+\footnotetext{se usato su altri tipi di filesystem causa un errore di
+ \errcode{ENOSYS}.}
+
+\footnotetext{a partire dal kernel 2.6.32 è stato introdotto un meccanismo che
+ identifica pagine di memoria identiche e le accorpa in una unica pagina
+ (soggetta al \textit{copy-on-write} per successive modifiche); per evitare
+ di controllare tutte le pagine solo quelle marcate con questo flag vengono
+ prese in considerazione per l'accorpamento; in questo modo si possono
+ migliorare le prestazioni nella gestione delle macchine virtuali diminuendo
+ la loro occupazione di memoria, ma il meccanismo può essere usato anche in
+ altre applicazioni in cui sian presenti numerosi processi che usano gli
+ stessi dati; per maggiori dettagli si veda
+ \href{http://kernelnewbies.org/Linux_2_6_32\#head-d3f32e41df508090810388a57efce73f52660ccb}{\texttt{http://kernelnewbies.org/Linux\_2\_6\_32}}.}
+
+La funzione non ha, tranne il caso di \const{MADV\_DONTFORK}, nessun effetto
+sul comportamento di un programma, ma può influenzarne le prestazioni fornendo
+al kernel indicazioni sulle esigenze dello stesso, così che sia possibile
+scegliere le opportune strategie per la gestione del \itindex{read-ahead}
+\textit{read-ahead} e del caching dei dati. A differenza da quanto specificato
+nello standard POSIX.1b, per il quale l'uso di \func{madvise} è a scopo
+puramente indicativo, Linux considera queste richieste come imperative, per
+cui ritorna un errore qualora non possa soddisfarle.\footnote{questo
+ comportamento differisce da quanto specificato nello standard.}
+
+\itindend{memory~mapping}
+
+
+\subsection{I/O vettorizzato: \func{readv} e \func{writev}}
+\label{sec:file_multiple_io}
+
+Un caso abbastanza comune è quello in cui ci si trova a dover eseguire una
+serie multipla di operazioni di I/O, come una serie di letture o scritture di
+vari buffer. Un esempio tipico è quando i dati sono strutturati nei campi di
+una struttura ed essi devono essere caricati o salvati su un file. Benché
+l'operazione sia facilmente eseguibile attraverso una serie multipla di
+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:
+\begin{functions}
+ \headdecl{sys/uio.h}
+
+ \funcdecl{int readv(int fd, const struct iovec *vector, int count)}
+ \funcdecl{int writev(int fd, const struct iovec *vector, int count)}
+
+ Eseguono rispettivamente una lettura o una scrittura vettorizzata.
+
+ \bodydesc{Le funzioni restituiscono il numero di byte letti o scritti in
+ caso di successo, e -1 in caso di errore, nel qual caso \var{errno}
+ assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] si è specificato un valore non valido per uno degli
+ argomenti (ad esempio \param{count} è maggiore di \const{IOV\_MAX}).
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale prima di
+ di avere eseguito una qualunque lettura o scrittura.
+ \item[\errcode{EAGAIN}] \param{fd} è stato aperto in modalità non bloccante e
+ non ci sono dati in lettura.
+ \item[\errcode{EOPNOTSUPP}] la coda delle richieste è momentaneamente piena.
+ \end{errlist}
+ ed anche \errval{EISDIR}, \errval{EBADF}, \errval{ENOMEM}, \errval{EFAULT}
+ (se non sono stati allocati correttamente i buffer specificati nei campi
+ \var{iov\_base}), più gli eventuali errori delle funzioni di lettura e
+ scrittura eseguite su \param{fd}.}
+\end{functions}
+
+Entrambe le funzioni usano una struttura \struct{iovec}, la cui definizione è
+riportata in fig.~\ref{fig:file_iovec}, che definisce dove i dati devono
+essere letti o scritti ed in che quantità. Il primo campo della struttura,
+\var{iov\_base}, contiene l'indirizzo del buffer ed il secondo,
+\var{iov\_len}, la dimensione dello stesso.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{\textwidth}
+ \includestruct{listati/iovec.h}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \structd{iovec}, usata dalle operazioni di I/O
+ vettorizzato.}
+ \label{fig:file_iovec}
+\end{figure}
+
+La lista dei buffer da utilizzare viene indicata attraverso l'argomento
+\param{vector} che è un vettore di strutture \struct{iovec}, la cui lunghezza
+è specificata dall'argomento \param{count}.\footnote{fino alle libc5, Linux
+ usava \type{size\_t} come tipo dell'argomento \param{count}, una scelta
+ logica, che però è stata dismessa per restare aderenti allo standard
+ POSIX.1-2001.} Ciascuna struttura dovrà essere inizializzata opportunamente
+per indicare i vari buffer da e verso i quali verrà eseguito il trasferimento
+dei dati. Essi verranno letti (o scritti) nell'ordine in cui li si sono
+specificati nel vettore \param{vector}.
+
+La standardizzazione delle due funzioni all'interno della revisione
+POSIX.1-2001 prevede anche che sia possibile avere un limite al numero di
+elementi del vettore \param{vector}. Qualora questo sussista, esso deve essere
+indicato dal valore dalla costante \const{IOV\_MAX}, definita come le altre
+costanti analoghe (vedi sez.~\ref{sec:sys_limits}) in \file{limits.h}; lo
+stesso valore deve essere ottenibile in esecuzione tramite la funzione
+\func{sysconf} richiedendo l'argomento \const{\_SC\_IOV\_MAX} (vedi
+sez.~\ref{sec:sys_sysconf}).
+
+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
+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.
+
+Si tenga presente infine che queste funzioni operano sui file con
+l'interfaccia dei file descriptor, e non è consigliabile mescolarle con
+l'interfaccia classica dei \textit{file stream} di
+cap.~\ref{cha:files_std_interface}; a causa delle bufferizzazioni interne di
+quest'ultima infatti si potrebbero avere risultati indefiniti e non
+corrispondenti a quanto aspettato.
+
+Come per le normali operazioni di lettura e scrittura, anche per l'\textsl{I/O
+ vettorizzato} si pone il problema di poter effettuare le operazioni in
+maniera atomica a partire da un certa posizione sul file. Per questo motivo a
+partire dal kernel 2.6.30 sono state introdotte anche per l'\textsl{I/O
+ vettorizzato} le analoghe delle funzioni \func{pread} e \func{pwrite} (vedi
+sez.~\ref{sec:file_read} e \ref{sec:file_write}); le due funzioni sono
+\funcd{preadv} e \func{pwritev} ed i rispettivi prototipi sono:\footnote{le
+ due funzioni sono analoghe alle omonime presenti in BSD; le \textit{system
+ call} usate da Linux (introdotte a partire dalla versione 2.6.30)
+ utilizzano degli argomenti diversi per problemi collegati al formato a 64
+ bit dell'argomento \param{offset}, che varia a seconda delle architetture,
+ ma queste differenze vengono gestite dalle funzioni di librerie di libreria
+ che mantengono l'interfaccia delle analoghe tratte da BSD.}
+\begin{functions}
+ \headdecl{sys/uio.h}
+
+ \funcdecl{int preadv(int fd, const struct iovec *vector, int count, off\_t
+ offset)}
+ \funcdecl{int pwritev(int fd, const struct iovec *vector, int count, off\_t
+ offset)}
+
+ Eseguono una lettura o una scrittura vettorizzata a partire da una data
+ posizione sul file.
+
+ \bodydesc{Le funzioni hanno gli stessi valori di ritorno delle
+ corrispondenti \func{readv} e \func{writev}; anche gli eventuali errori
+ sono gli stessi già visti in precedenza, ma ad essi si possono aggiungere
+ per \var{errno} anche i valori:
+ \begin{errlist}
+ \item[\errcode{EOVERFLOW}] \param{offset} ha un valore che non può essere
+ usato come \type{off\_t}.
+ \item[\errcode{ESPIPE}] \param{fd} è associato ad un socket o una pipe.
+ \end{errlist}
+}
+\end{functions}
+
+Le due funzioni eseguono rispettivamente una lettura o una scrittura
+vettorizzata a partire dalla posizione \param{offset} sul file indicato
+da \param{fd}, la posizione corrente sul file, come vista da eventuali altri
+processi che vi facciano riferimento, non viene alterata. A parte la presenza
+dell'ulteriore argomento il comportamento delle funzioni è identico alle
+precedenti \func{readv} e \func{writev}.
+
+Con l'uso di queste funzioni si possono evitare eventuali
+\itindex{race~condition} \textit{race condition} quando si deve eseguire la
+una operazione di lettura e scrittura vettorizzata a partire da una certa
+posizione su un file, mentre al contempo si possono avere in concorrenza
+processi che utilizzano lo stesso file descriptor (si ricordi quanto visto in
+sez.~\ref{sec:file_adv_func}) con delle chiamate a \func{lseek}.
+
+
+
+\subsection{L'I/O diretto fra file descriptor: \func{sendfile} e
+ \func{splice}}
+\label{sec:file_sendfile_splice}
+
+Uno dei problemi che si presentano nella gestione dell'I/O è quello in cui si
+devono trasferire grandi quantità di dati da un file descriptor ed un altro;
+questo usualmente comporta la lettura dei dati dal primo file descriptor in un
+buffer in memoria, da cui essi vengono poi scritti sul secondo.
+
+Benché il kernel ottimizzi la gestione di questo processo quando si ha a che
+fare con file normali, in generale quando i dati da trasferire sono molti si
+pone il problema di effettuare trasferimenti di grandi quantità di dati da
+kernel space a user space e all'indietro, quando in realtà potrebbe essere più
+efficiente mantenere tutto in kernel space. Tratteremo in questa sezione
+alcune funzioni specialistiche che permettono di ottimizzare le prestazioni in
+questo tipo di situazioni.