Aggiunta nota sul self-pipe trick ed un po' di indici
[gapil.git] / fileadv.tex
index f4ccd79ade39d6c3a482d7f16498e362c9b5a368..de7ae5d50ae1aa153e836965c4ffd8691b579a3a 100644 (file)
@@ -59,18 +59,17 @@ da quanto si otterrebbe dal file descriptor ``\textsl{disponibile}'') si
 potrebbe addirittura arrivare ad un \textit{deadlock}\index{deadlock}.
 
 Abbiamo già accennato in sez.~\ref{sec:file_open} che è possibile prevenire
-questo tipo di comportamento delle funzioni di I/O aprendo un file in quella
-che viene chiamata \textsl{modalità non-bloccante}, attraverso l'uso del flag
-\const{O\_NONBLOCK} nella chiamata di \func{open}. In questo caso le funzioni
-di input/output eseguite sul file che si sarebbero bloccate, ritornano
-immediatamente, restituendo l'errore \errcode{EAGAIN}.
-
-L'utilizzo di questa modalità di I/O permette di risolvere il problema
-controllando a turno i vari file descriptor, in un ciclo in cui si ripete
-l'accesso fintanto che esso non viene garantito.  Ovviamente questa tecnica,
-detta \textit{polling}\index{polling}, è estremamente inefficiente: si tiene
-costantemente impiegata la CPU solo per eseguire in continuazione delle system
-call che nella gran parte dei casi falliranno. 
+questo tipo di comportamento delle funzioni di I/O aprendo un file in
+\textsl{modalità non-bloccante}, attraverso l'uso del flag \const{O\_NONBLOCK}
+nella chiamata di \func{open}. In questo caso le funzioni di input/output
+eseguite sul file che si sarebbero bloccate, ritornano immediatamente,
+restituendo l'errore \errcode{EAGAIN}.  L'utilizzo di questa modalità di I/O
+permette di risolvere il problema controllando a turno i vari file descriptor,
+in un ciclo in cui si ripete l'accesso fintanto che esso non viene garantito.
+Ovviamente questa tecnica, detta \textit{polling}\index{polling}, è
+estremamente inefficiente: si tiene costantemente impiegata la CPU solo per
+eseguire in continuazione delle system call che nella gran parte dei casi
+falliranno.
 
 Per superare questo problema è stato introdotto il concetto di \textit{I/O
   multiplexing}, una nuova modalità di operazioni che consenta di tenere sotto
@@ -89,11 +88,11 @@ ulteriori dettagli e qualche esempio in sez.~\ref{sec:TCP_sock_multiplexing}.
 \subsection{Le funzioni \func{select} e \func{pselect}}
 \label{sec:file_select}
 
-Il primo ad introdurre una interfaccia per l'\textit{I/O multiplexing} è stato
-BSD,\footnote{la funzione \func{select} è apparsa in BSD4.2 e standardizzata
-  in BSD4.4, ma è stata portata su tutti i sistemi che supportano i
-  \textit{socket}\index{socket}, compreso le varianti di System V.}  con la
-funzione \funcd{select}, il cui prototipo è:
+Il primo kernel unix-like ad introdurre una interfaccia per l'\textit{I/O
+  multiplexing} è stato BSD,\footnote{la funzione \func{select} è apparsa in
+  BSD4.2 e standardizzata in BSD4.4, ma è stata portata su tutti i sistemi che
+  supportano i \textit{socket}\index{socket}, compreso le varianti di System
+  V.}  con la funzione \funcd{select}, il cui prototipo è:
 \begin{functions}
   \headdecl{sys/time.h}
   \headdecl{sys/types.h}
@@ -127,7 +126,8 @@ degli insiemi specificati (\param{readfds}, \param{writefds} e
 Per specificare quali file descriptor si intende \textsl{selezionare}, la
 funzione usa un particolare oggetto, il \textit{file descriptor set},
 identificato dal tipo \type{fd\_set}, che serve ad identificare un insieme di
-file descriptor, in maniera analoga a come un \textit{signal set} (vedi
+file descriptor, in maniera analoga a come un 
+\index{\textit{signal set}}\textit{signal set} (vedi
 sez.~\ref{sec:sig_sigset}) identifica un insieme di segnali. Per la
 manipolazione di questi \textit{file descriptor set} si possono usare delle
 opportune macro di preprocessore:
@@ -179,23 +179,23 @@ necessaria. Questo limite viene indicato tramite l'argomento \param{n}, che
 deve corrispondere al valore massimo aumentato di uno.\footnote{i file
   descriptor infatti sono contati a partire da zero, ed il valore indica il
   numero di quelli da tenere sotto controllo; dimenticarsi di aumentare di uno
-  il valore di \param{n} è un errore comune.}
-
-Infine l'argomento \param{timeout}, 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.
+  il valore di \param{n} è un errore comune.}  Infine l'argomento
+\param{timeout}, 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 i file descriptor pronti per le operazioni ad esso relative, in modo
-da poterli controllare con \const{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.
+indicare quali sono i file descriptor pronti per le operazioni ad esso
+relative, in modo da poterli controllare con \const{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.
 
 In Linux \func{select} modifica anche il valore di \param{timeout},
 impostandolo al tempo restante in caso di interruzione prematura; questo è
@@ -269,13 +269,10 @@ funzione.
 
 L'uso di \param{sigmask} è stato introdotto allo scopo di prevenire possibili
 race condition\index{race condition} quando ci si deve porre in attesa sia di
-un segnale che di dati.\footnote{in Linux però non è stata ancora introdotta
-  la relativa system call, pertanto la funzione è implementata nelle
-  \acr{glibc} attraverso \func{select} e la possibilità di race condition
-  permane.} La tecnica classica è quella di utilizzare il gestore per
-impostare una variabile globale e controllare questa nel corpo principale del
-programma; abbiamo visto in sez.~\ref{sec:sig_example} come questo lasci spazio
-a possibili race condition, per cui diventa essenziale utilizzare
+un segnale che di dati. La tecnica classica è quella di utilizzare il gestore
+per impostare una variabile globale e controllare questa nel corpo principale
+del programma; abbiamo visto in sez.~\ref{sec:sig_example} come questo lasci
+spazio a possibili 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
@@ -291,15 +288,24 @@ condition,\index{race condition} perch
 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
+Per questo è stata introdotta \func{pselect} che attraverso l'argomento
 \param{sigmask} permette di riabilitare la ricezione il segnale
-contestualmente all'esecuzione della funzione, e ribloccandolo non appena essa
-ritorna. In questo modo il precedente codice potrebbe essere modificato
-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.
+contestualmente all'esecuzione della funzione,\footnote{in Linux però non è
+  presente la relativa system call, e la funzione è implementata nelle
+  \acr{glibc} attraverso \func{select} (vedi \texttt{man select\_tut}) per cui
+  la possibilità di race condition permane; esiste però una soluzione,
+  chiamata \index{\textit{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, e indicare l'arrivo di un
+  segnale scrivendo sul capo in scrittura all'interno del manipolatore; 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.
 
 
 
@@ -315,12 +321,12 @@ cui prototipo 
 \begin{prototype}{sys/poll.h}
   {int poll(struct pollfd *ufds, unsigned int nfds, int timeout)}
   
-  La funzione attende un cambiamento di stato per uno dei file descriptor
-  specificati da \param{ufds}.
+  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; in caso di errore viene
-    restituito -1 ed \var{errno} assumerà uno dei valori:
+    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.
@@ -336,8 +342,8 @@ 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 comporta il ritorno immediato (e
-può essere utilizzato per impiegare \func{poll} in modalità
+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}).
 
 \begin{figure}[!htb]