}
\end{prototype}
-La funzione restituisce un file descriptor speciale, detto anche \textit{epoll
- descriptor} che viene associato alla infrastruttura utilizzata dal kernel
+La funzione restituisce 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; l'argomento \param{size} serve a dare
l'indicazione del numero di file descriptor che si vorranno tenere sotto
controllo, ma costituisce solo un suggerimento per semplificare l'allocazione
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 l'argomento \param{op}
+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|l|}
+ \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}.\\
- \const{EPOLL\_CTL\_MOD}& .\\
- \const{EPOLL\_CTL\_DEL}& .\\
+ 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
\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 anche un valore \texttt{NULL}.}
+
\begin{figure}[!htb]
\includestruct{listati/epoll_event.h}
\end{minipage}
\normalsize
- \caption{La struttura \structd{epoll\_event}, .}
- \label{fig:}
+ \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}, serve ad indicare a
+quale file descriptor si intende fare riferimento, ed in astratto può
+contenere un valore qualsiasi che permetta di identificarlo, di norma comunque
+si usa come valore lo stesso \param{fd}.
\begin{table}[htb]
\centering
\footnotesize
- \begin{tabular}[c]{|l|l|}
+ \begin{tabular}[c]{|l|p{8cm}|}
\hline
\textbf{Valore} & \textbf{Significato} \\
\hline
\hline
- \const{EPOLLIN}& .\\
- \const{EPOLLOUT}& .\\
- \const{EPOLLRDHUP}& .\\
- \const{EPOLLPRI}& .\\
- \const{EPOLLERR}& .\\
- \const{EPOLLHUP}& .\\
- \const{EPOLLET}& .\\
- \const{EPOLLONESHOT}& .\\
+ \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}).\\
+ \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.\\
+ \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{Valori del campo \param{events} di \struct{epoll\_event}.}
+ \caption{Costanti che identificano i bit del campo \param{events} di
+ \struct{epoll\_event}.}
\label{tab:epoll_events}
\end{table}
-
-, da
-specificare con le costanti riportate in tab.,
-La funzione prende come primo argomento un file descriptor di \textit{epoll}
-\param{epfd}, che deve essere stato ottenuto tramite \func{epoll\_create}, e
-consente di impostare le operazioni di osservazione su un altro file
-descriptor \param{fd}
-
-
-
-
-La funzione esegue l'operazione di controllo specificata dall'argomento
-\param{op},
-
-
-\param{fd} alla lista dei file descriptor osservati
-
-sull'\textit{epoll descripter} \param{epfd}
-
-
-La funzione che consente di attendere è \funcd{epoll\_wait}, il cui prototipo
-è:
+\footnotetext{questa modalità è disponibile solo a partire dal kernel 2.6.2.}
+
+Le modalità di utilizzo di \textit{epoll} prevedano 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)}
\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{fd} è lo stesso \param{epfd} o
- l'operazione richiesta con \param{op} non è supportata.
+ 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 $-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}.
+
+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 di esso 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 un file descriptor è pronto e resterà
+tale fintanto che non si sono completamente esaurite le operazioni su di esso,
+questo può essere rilevato con un errore di \errcode{EAGAIN} in una
+\func{read} o una \func{write},\footnote{è opportuno ricordare ancora una
+ volta che l'uso dell'I/O multiplexing richiede di operare sui file in
+ modalità non bloccante.} ma anche con il fatto che sono stati restituiti
+meno dati di quelli richiesti.
+
+Come per le precedenti \func{select} e \func{poll}, essendo queste funzioni
+utiilizzate prevalentemente con i server di rete, tratteremo degli esempi del
+loro più avanti, nella trattazione dei socket, ed in particolare in
+sez.~\ref{sec:TCP_sock_multiplexing}.
+
\itindend{epoll}
-% TODO epoll
-%
+
+
\section{L'accesso \textsl{asincrono} ai file}
\label{sec:file_asyncronous_access}
\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), per essere avvisato della possibilità di eseguire le
+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{Operazioni asincrone sui file}
+\subsection{Il \textit{Signal driven I/O}}
\label{sec:file_asyncronous_operation}
-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à in questo caso non si tratta di eseguire delle operazioni di lettura
-o scrittura del file in modo asincrono (tratteremo questo, che più
-propriamente è detto \textsl{I/O asincrono} in
-sez.~\ref{sec:file_asyncronous_io}), quanto di un meccanismo asincrono di
-notifica delle variazione dello stato del file descriptor aperto in questo
-modo.
-
-Quello che succede in questo caso è che il sistema genera un segnale
-(normalmente \const{SIGIO}, ma è possibile usarne altri con il comando
-\const{F\_SETSIG} di \func{fcntl}) tutte le volte che diventa possibile
-leggere o scrivere dal file descriptor che si è posto in questa modalità. Si
-può inoltre selezionare, con il comando \const{F\_SETOWN} di \func{fcntl},
+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 in questo caso è che il
+sistema genera un segnale (normalmente \const{SIGIO}, ma è possibile usarne
+altri con il comando \const{F\_SETSIG} di \func{fcntl}) tutte le volte che
+diventa possibile leggere o scrivere dal file descriptor che si è posto in
+questa modalità.\footnote{questa modalità non è utilizzabile con i file
+ ordinari ma solo con socket, file di terminale o pseudo terminale, e, a
+ partire dal kernel 2.6, anche per fifo e pipe.}
+
+Si può inoltre selezionare, con il comando \const{F\_SETOWN} di \func{fcntl},
quale processo (o gruppo di processi) riceverà il segnale. Se pertanto si
effettuano le operazioni di I/O in risposta alla ricezione del segnale non ci
sarà più la necessità di restare bloccati in attesa della disponibilità di
-accesso ai file; per questo motivo Stevens chiama questa modalità
-\textit{signal driven I/O}.
-
-Questa è un'altra modalità di gestione I/O, alternativa all'uso di
-\itindex{epoll} \textit{epoll}, 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.
+accesso ai file.
+
+Per questo motivo Stevens, ed anche le pagine di manuale di
+Linux, chiamano questa modalità ``\textit{Signal driven I/O}''. Questa è
+ancora 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
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 \const{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.
+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 \const{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
+ \texttt{/proc/sys/kernel/rtsig-max} allo stesso valore di quello di
+ \texttt{/proc/sys/fs/file-max}.}
% TODO fare esempio che usa O_ASYNC
% TODO inserire anche eventfd (vedi http://lwn.net/Articles/233462/)
-
+% e le restanti signalfd e timerfd introdotte con il 2.6.22
+% o trovargli un posto migliore
\subsection{L'interfaccia POSIX per l'I/O asincrono}
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 funzioni apposita, \funcd{aio\_cancel}, che
+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}
\itindend{memory~mapping}
-\subsection{L'I/O diretto fra file descriptor}
-\label{sec:file_sendfile_splice}
+%\subsection{L'I/O diretto fra file descriptor}
+%\label{sec:file_sendfile_splice}
+
+
+%Uno dei problemi
-Uno dei problemi
+%NdA è da finire, sul perché non è abilitata fra file vedi:
-NdA è da finire, sul perché non è abilitata fra file vedi:
+%\href{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}
+%{\texttt{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}}
-\href{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}
-{\texttt{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}}
% TODO documentare la funzione sendfile
% TODO documentare le funzioni tee e splice
% e http://en.wikipedia.org/wiki/Splice_(system_call)
+
+
+%\subsection{Gestione avanzata del caching dei dati}
+%\label{sec:file_fadvise}
+
+% TODO documentare \func{madvise}
+% TODO documentare \func{mincore}
+% TODO documentare \func{posix\_fadvise}
+% vedi http://insights.oetiker.ch/linux/fadvise.html
+% questo tread? http://www.ussg.iu.edu/hypermail/linux/kernel/0703.1/0032.html
+
%\subsection{L'utilizzo delle porte di I/O}
%\label{sec:file_io_port}
%
% LocalWords: dell'inode CLOSE NOWRITE MOVE MOVED FROM TO rm wd event page ctl
% LocalWords: attribute Universe epoll Solaris kqueue level triggered Jonathan
% LocalWords: Lemon BSDCON edge Libenzi kevent backporting epfd EEXIST ENOENT
-% LocalWords: MOD
+% LocalWords: MOD wait EPOLLIN EPOLLOUT EPOLLRDHUP SOCK EPOLLPRI EPOLLERR one
+% LocalWords: EPOLLHUP EPOLLET EPOLLONESHOT shot maxevents
%%% Local Variables: