Revisione select e pselect completata
[gapil.git] / fileadv.tex
index 480b3da5444aeafc1fc28ada86140d75f1e9c542..325d8a59ea7f1d24bb472f96dff79894f5137b86 100644 (file)
@@ -382,9 +382,8 @@ tal caso l'intervallo coperto va da \var{l\_start}$+$\var{l\_len} a
 \var{l\_start}$-1$, mentre per un valore positivo l'intervallo va da
 \var{l\_start} a \var{l\_start}$+$\var{l\_len}$-1$. Si può però usare un
 valore negativo soltanto se l'inizio della regione indicata non cade prima
-dell'inizio del file, con un valore positivo invece si può anche indicare una
-regione che eccede la dimensione corrente del file, e questa verrà coperta in
-una sua futura estensione.
+dell'inizio del file, mentre come accennato con un valore positivo  si
+può anche indicare una regione che eccede la dimensione corrente del file.
 
 Il tipo di \textit{file lock} richiesto viene specificato dal campo
 \var{l\_type}, esso può assumere i tre valori definiti dalle costanti
@@ -605,11 +604,11 @@ Nel caso si sia scelta la semantica BSD (\texttt{\small 25--34}) prima si
 controlla (\texttt{\small 27--31}) il valore di \var{cmd} per determinare se
 si vuole effettuare una chiamata bloccante o meno, reimpostandone il valore
 opportunamente, dopo di che a seconda del tipo di blocco al valore viene
-aggiunta la relativa opzione (con un OR aritmetico, dato che \func{flock}
+aggiunta la relativa opzionecon un OR aritmetico, dato che \func{flock}
 vuole un argomento \param{operation} in forma di maschera binaria.  Nel caso
 invece che si sia scelta la semantica POSIX le operazioni sono molto più
-immediate, si prepara (\texttt{\small 36--40}) la struttura per il lock, e lo
-esegue (\texttt{\small 41}).
+immediate si prepara (\texttt{\small 36--40}) la struttura per il lock, e lo
+si esegue (\texttt{\small 41}).
 
 In entrambi i casi dopo aver richiesto il blocco viene controllato il
 risultato uscendo (\texttt{\small 44--46}) in caso di errore, o stampando un
@@ -723,8 +722,8 @@ Lock acquired
 \end{Console}
 %$
 che ci mostra come i due tipi di blocco siano assolutamente indipendenti; per
-questo motivo occorre sempre tenere presente quale fra le due semantiche
-disponibili stanno usando i programmi con cui si interagisce, dato che i
+questo motivo occorre sempre tenere presente quale, fra le due semantiche
+disponibili, stanno usando i programmi con cui si interagisce, dato che i
 blocchi applicati con l'altra non avrebbero nessun effetto.
 
 % \subsection{La funzione \func{lockf}}
@@ -789,7 +788,7 @@ consentiti sono i seguenti:
   sovrappone ad una che è già stata bloccata da un altro processo; in caso di
   sovrapposizione con un altro blocco già ottenuto le sezioni vengono unite.
 \item[\const{F\_TLOCK}] Richiede un \textit{exclusive lock}, in maniera
-  identica a\const{F\_LOCK} ma in caso di indisponibilità non blocca il
+  identica a \const{F\_LOCK}, ma in caso di indisponibilità non blocca il
   processo restituendo un errore di \errval{EAGAIN}.
 \item[\const{F\_ULOCK}] Rilascia il blocco sulla sezione indicata, questo può
   anche causare la suddivisione di una sezione bloccata in precedenza nelle
@@ -804,10 +803,10 @@ consentiti sono i seguenti:
 La funzione è semplicemente una diversa interfaccia al \textit{file locking}
 POSIX ed è realizzata utilizzando \func{fcntl}; pertanto la semantica delle
 operazioni è la stessa di quest'ultima e quindi la funzione presenta lo stesso
-comportamento riguardo gli effetti della chiusura dei file, degli effetti sui
-file duplicati e nel passaggio attraverso \func{fork} ed \func{exec}. Per
-questo motivo la funzione non è affatto equivalente a \func{flock} e può
-essere usata senza interferenze insieme a quest'ultima.
+comportamento riguardo gli effetti della chiusura dei file, ed il
+comportamento sui file duplicati e nel passaggio attraverso \func{fork} ed
+\func{exec}. Per questo stesso motivo la funzione non è equivalente a
+\func{flock} e può essere usata senza interferenze insieme a quest'ultima.
 
 
 
@@ -824,20 +823,20 @@ direttamente al sistema, così che, anche qualora non si predisponessero le
 opportune verifiche nei processi, questo verrebbe comunque rispettato.
 
 Per poter utilizzare il \textit{mandatory locking} è stato introdotto un
-utilizzo particolare del bit \itindex{sgid~bit} \acr{sgid}. Se si ricorda
-quanto esposto in sez.~\ref{sec:file_special_perm}), esso viene di norma
-utilizzato per cambiare il \ids{GID} effettivo con cui viene eseguito un
-programma, ed è pertanto sempre associato alla presenza del permesso di
-esecuzione per il gruppo. Impostando questo bit su un file senza permesso di
-esecuzione in un sistema che supporta il \textit{mandatory locking}, fa sì che
-quest'ultimo venga attivato per il file in questione. In questo modo una
-combinazione dei permessi originariamente non contemplata, in quanto senza
-significato, diventa l'indicazione della presenza o meno del \textit{mandatory
-  locking}.\footnote{un lettore attento potrebbe ricordare quanto detto in
-  sez.~\ref{sec:file_perm_management} e cioè che il bit \acr{sgid} viene
-  cancellato (come misura di sicurezza) quando di scrive su un file, questo
-  non vale quando esso viene utilizzato per attivare il \textit{mandatory
-    locking}.}
+utilizzo particolare del bit \itindex{sgid~bit} \acr{sgid} dei permessi dei
+file. Se si ricorda quanto esposto in sez.~\ref{sec:file_special_perm}), esso
+viene di norma utilizzato per cambiare il \ids{GID} effettivo con cui viene
+eseguito un programma, ed è pertanto sempre associato alla presenza del
+permesso di esecuzione per il gruppo. Impostando questo bit su un file senza
+permesso di esecuzione in un sistema che supporta il \textit{mandatory
+  locking}, fa sì che quest'ultimo venga attivato per il file in questione. In
+questo modo una combinazione dei permessi originariamente non contemplata, in
+quanto senza significato, diventa l'indicazione della presenza o meno del
+\textit{mandatory locking}.\footnote{un lettore attento potrebbe ricordare
+  quanto detto in sez.~\ref{sec:file_perm_management} e cioè che il bit
+  \acr{sgid} viene cancellato (come misura di sicurezza) quando di scrive su
+  un file, questo non vale quando esso viene utilizzato per attivare il
+  \textit{mandatory locking}.}
 
 L'uso del \textit{mandatory locking} presenta vari aspetti delicati, dato che
 neanche l'amministratore può passare sopra ad un \textit{file lock}; pertanto
@@ -849,9 +848,9 @@ inaccessibile, rendendo completamente inutilizzabile il sistema\footnote{il
 bloccare completamente un server NFS richiedendo una lettura su un file su cui
 è attivo un blocco. Per questo motivo l'abilitazione del \textit{mandatory
   locking} è di norma disabilitata, e deve essere attivata filesystem per
-filesystem in fase di montaggio (specificando l'apposita opzione di
-\func{mount} riportata in sez.~\ref{sec:filesystem_mounting}), o con l'opzione
-\code{-o mand} per il comando omonimo).
+filesystem in fase di montaggiospecificando l'apposita opzione di
+\func{mount} riportata in sez.~\ref{sec:filesystem_mounting}, o con l'opzione
+\code{-o mand} per il comando omonimo.
 
 Si tenga presente inoltre che il \textit{mandatory locking} funziona solo
 sull'interfaccia POSIX di \func{fcntl}. Questo ha due conseguenze: che non si
@@ -915,7 +914,6 @@ può presentare anche con l'uso di file mappati in memoria; pertanto allo stato
 attuale delle cose è sconsigliabile fare affidamento sul \textit{mandatory
   locking}.
 
-
 \itindend{file~locking}
 
 \itindend{mandatory~locking}
@@ -940,45 +938,55 @@ I/O.
 
 Abbiamo visto in sez.~\ref{sec:sig_gen_beha}, affrontando la suddivisione fra
 \textit{fast} e \textit{slow} \textit{system call},\index{system~call~lente}
-che in certi casi le funzioni di I/O possono bloccarsi
-indefinitamente.\footnote{si ricordi però che questo può accadere solo per le
-  pipe, i socket ed alcuni file di dispositivo\index{file!di~dispositivo}; sui
-  file normali le funzioni di lettura e scrittura ritornano sempre subito.}
-Ad esempio le operazioni di lettura possono bloccarsi quando non ci sono dati
-disponibili sul descrittore su cui si sta operando.
-
-Questo comportamento causa uno dei problemi più comuni che ci si trova ad
-affrontare nelle operazioni di I/O, che si verifica quando si deve operare con
-più file descriptor eseguendo funzioni che possono bloccarsi senza che sia
-possibile prevedere quando questo può avvenire (il caso più classico è quello
-di un server in attesa di dati in ingresso da vari client). Quello che può
-accadere è di restare bloccati nell'eseguire una operazione su un file
-descriptor che non è ``\textsl{pronto}'', quando ce ne potrebbe essere un
-altro disponibile. Questo comporta nel migliore dei casi una operazione
-ritardata inutilmente nell'attesa del completamento di quella bloccata, mentre
-nel peggiore dei casi (quando la conclusione della operazione bloccata dipende
-da quanto si otterrebbe dal file descriptor ``\textsl{disponibile}'') si
-potrebbe addirittura arrivare ad un \itindex{deadlock} \textit{deadlock}.
+che in certi casi le funzioni di I/O eseguite su un file descritor possono
+bloccarsi indefinitamente. Questo non avviene mai per i file normali, per i
+quali le funzioni di lettura e scrittura ritornano sempre subito, ma può
+avvenire per alcuni \index{file!di~dispositivo} file di dispositivo, come ad
+esempio una seriale o un terminale, o con l'uso di file descriptor collegati a
+meccanismi di intercomunicazione come le \textit{pipe} (vedi
+sez.~\ref{sec:ipc_unix}) ed i socket (vedi sez.~\ref{sec:sock_socket_def}). In
+casi come questi ad esempio una operazione di lettura potrebbe bloccarsi se
+non ci sono dati disponibili sul descrittore su cui la si sta effettuando.
+
+Questo comportamento è alla radice di una delle problematiche più comuni che
+ci si trova ad affrontare nella gestione delle operazioni di I/O: la necessità
+di operare su più file descriptor eseguendo funzioni che possono bloccarsi
+indefinitamente senza che sia possibile prevedere quando questo può
+avvenire. Un caso classico è quello di un server di rete (tratteremo la
+problematica in dettaglio nella seconda parte della guida) in attesa di dati
+in ingresso prevenienti da vari client.
+
+In un caso di questo tipo, se si andasse ad operare sui vari file descriptor
+aperti uno dopo l'altro, potrebbe accadere di restare bloccati nell'eseguire
+una lettura su uno di quelli che non è ``\textsl{pronto}'', quando ce ne
+potrebbe essere un altro con dati disponibili. Questo comporta nel migliore
+dei casi una operazione ritardata inutilmente nell'attesa del completamento di
+quella bloccata, mentre nel peggiore dei casi, quando la conclusione
+dell'operazione bloccata dipende da quanto si otterrebbe dal file descriptor
+``\textsl{disponibile}'', si potrebbe addirittura arrivare ad un
+\itindex{deadlock} \textit{deadlock}.
 
 Abbiamo già accennato in sez.~\ref{sec:file_open_close} che è possibile
 prevenire 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
+di lettura o scrittura 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 \itindex{polling}
+viene garantito. Ovviamente questa tecnica, detta \itindex{polling}
 \textit{polling}, è estremamente inefficiente: si tiene costantemente
 impiegata la CPU solo per eseguire in continuazione delle \textit{system call}
 che nella gran parte dei casi falliranno.
 
-Per superare questo problema è stato introdotto il concetto di \textit{I/O
-  multiplexing}, una nuova modalità di operazioni che consente di tenere sotto
-controllo più file descriptor in contemporanea, permettendo di bloccare un
-processo quando le operazioni volute non sono possibili, e di riprenderne
-l'esecuzione una volta che almeno una di quelle richieste sia effettuabile, in
-modo da poterla eseguire con la sicurezza di non restare bloccati.
+É appunto per superare questo problema è stato introdotto il concetto di
+\textit{I/O multiplexing}, una nuova modalità per la gestione dell'I/O che
+consente di tenere sotto controllo più file descriptor in contemporanea,
+permettendo di bloccare un processo quando le operazioni di lettura o
+scrittura non sono immediatamente effettuabili, e di riprenderne l'esecuzione
+una volta che almeno una di quelle che erano state richieste diventi
+possibile, in modo da poterla eseguire con la sicurezza di non restare
+bloccati.
 
 Dato che, come abbiamo già accennato, per i normali file su disco non si ha
 mai un accesso bloccante, l'uso più comune delle funzioni che esamineremo nei
@@ -992,33 +1000,34 @@ sez.~\ref{sec:TCP_sock_multiplexing}.
 \label{sec:file_select}
 
 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 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}
-  \headdecl{unistd.h}
-  \funcdecl{int select(int ndfs, fd\_set *readfds, fd\_set *writefds, fd\_set
-    *exceptfds, struct timeval *timeout)}
-  
-  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:
+  multiplexing} è stato BSD, con la funzione \funcd{select} che è apparsa in
+BSD4.2 ed è stata standardizzata in BSD4.4, in seguito è stata portata su
+tutti i sistemi che supportano i socket, compreso le varianti di System V ed
+inserita in POSIX.1-2001; il suo prototipo è:\footnote{l'header
+  \texttt{sys/select.h} è stato introdotto con POSIX.1-2001, è ed presente con
+  le \acr{glibc} a partire dalla versione 2.0, in precedenza, con le
+  \acr{libc4} e le \acr{libc5}, occorreva includere \texttt{sys/time.h},
+  \texttt{sys/types.h} e \texttt{unistd.h}.}
+
+\begin{funcproto}{
+\fhead{sys/select.h}
+\fdecl{int select(int ndfs, fd\_set *readfds, fd\_set *writefds, fd\_set
+    *exceptfds, \\
+\phantom{int select(}struct timeval *timeout)}
+\fdesc{Attende che uno fra i file descriptor degli insiemi specificati diventi
+  attivo.} 
+}
+{La funzione ritorna $0$ in caso di successo e $-1$ per un 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{EBADF}] si è specificato un file descriptor non valido
+    (chiuso o con errori) 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{functions}
+  ed inoltre \errval{ENOMEM} nel suo significato generico.}
+\end{funcproto}
 
 La funzione mette il processo in stato di \textit{sleep} (vedi
 tab.~\ref{tab:proc_proc_states}) fintanto che almeno uno dei file descriptor
@@ -1035,35 +1044,35 @@ maniera analoga a come un \itindex{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:
-\begin{functions}
-  \headdecl{sys/time.h}
-  \headdecl{sys/types.h}
-  \headdecl{unistd.h}
-  \funcdecl{void \macro{FD\_ZERO}(fd\_set *set)}
-  Inizializza l'insieme (vuoto).
 
-  \funcdecl{void \macro{FD\_SET}(int fd, fd\_set *set)}
-  Inserisce il file descriptor \param{fd} nell'insieme.
+{\centering
+\vspace{3pt}
+\begin{funcbox}{
+\fhead{sys/select.h}
+\fdecl{void \macro{FD\_ZERO}(fd\_set *set)}
+\fdesc{Inizializza l'insieme (vuoto).} 
+\fdecl{void \macro{FD\_SET}(int fd, fd\_set *set)}
+\fdesc{Inserisce il file descriptor \param{fd} nell'insieme.} 
+\fdecl{void \macro{FD\_CLR}(int fd, fd\_set *set)}
+\fdesc{Rimuove il file descriptor \param{fd} dall'insieme.} 
+\fdecl{int \macro{FD\_ISSET}(int fd, fd\_set *set)}
+\fdesc{Controlla se il file descriptor \param{fd} è nell'insieme.} 
+}
+\end{funcbox}}
 
-  \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 \headfile{sys/select.h}, ed è pari a 1024.}
+al limite per il numero massimo di file aperti (ad esempio in Linux, fino alla
+serie 2.0.x, c'era un limite di 256 file per processo), ma da quando, nelle
+versioni più recenti del kernel, questo limite è stato rimosso, esso indica le
+dimensioni massime dei numeri usati nei \textit{file descriptor set}, ed il
+suo valore, secondo lo standard POSIX 1003.1-2001, è definito in
+\headfile{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
+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.
 
@@ -1071,68 +1080,88 @@ 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,
+  bloccante, quindi anche in caso di \textit{end-of-file}.} 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
+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
+\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.
+deve corrispondere al valore massimo aumentato di uno. Si ricordi infatti 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 il puntatore ad 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, e così può essere utilizzata eseguire il \itindex{polling}
+\textit{polling} su un gruppo di file descriptor. Usare questo argomento con
+tutti i \textit{file descriptor set} vuoti è un modo portabile, disponibile
+anche su sistemi in cui non sono disponibili le funzioni avanzate di
+sez.~\ref{sec:sig_timer_adv}, per tenere un processo in stato di
+\textit{sleep} con precisioni inferiori al secondo.
+
+In caso di successo la funzione restituisce il numero di file descriptor
+pronti, seguendo il comportamento previsto dallo standard
+POSIX.1-2001,\footnote{si tenga però presente che esistono alcune versioni di
+  Unix che non si comportano in questo modo, restituendo un valore positivo
+  generico.}  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 scade il tempo indicato
+da \param{timout} viene restituito un valore nullo e i \textit{file descriptor
+  set} non vengono modificati. In caso di errore la funzione restituisce $-1$, i
+valori dei tre insiemi e di \param{timeout} sono indefiniti e non si può fare
+nessun affidamento sul loro contenuto; nelle versioni più recenti della
+funzione invece i \textit{file descriptor set} non vengono modificati anche in
+caso di errore.
+
+Si tenga presente infine che su Linux, in caso di programmazione
+\textit{multithread} se un file descriptor viene chiuso in un altro
+\textit{thread} rispetto a quello in cui si sta usando \func{select}, questa
+non subisce nessun effetto. In altre varianti di sistemi unix-like invece
+\func{select} ritorna indicando che il file descriptor è pronto, con
+conseguente possibile errore nel caso lo si usi senza che sia stato
+riaperto. Lo standard non prevede niente al riguardo e non si deve dare per
+assunto nessuno dei due comportamenti se si vogliono scrivere programmi
+portabili.
+
 
 \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.}
+Una volta ritornata la funzione, si potrà controllare quali sono i file
+descriptor pronti, ed operare su di essi. Si tenga presente però che
+\func{select} fornisce solo di un suggerimento, esistono infatti condizioni in
+cui \func{select} può riportare in maniera spuria che un file descriptor è
+pronto, ma l'esecuzione di una operazione di I/O si bloccherebbe: ad esempio
+con Linux questo avviene quando su un socket arrivano dei dati che poi vengono
+scartati perché corrotti (ma sono possibili pure altri casi); in tal caso pur
+risultando il relativo file descriptor pronto in lettura una successiva
+esecuzione di una \func{read} si bloccherebbe. Per questo motivo quando si usa
+l'\textit{I/O multiplexing} è sempre raccomandato l'uso delle funzioni di
+lettura e scrittura in modalità non bloccante.
+
+Su Linux quando la \textit{system call} \func{select} viene interrotta da un
+segnale modifica il valore nella struttura puntata da \param{timeout},
+impostandolo al tempo restante. In tal caso infatti si ha un errore di
+\errcode{EINTR} ed occorre rilanciare la funzione per proseguire l'attesa, ed
+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. 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 e per questo motivo le \acr{glibc} nascondono il comportamento
+passando alla \textit{system call} una copia dell'argomento \param{timeout}.
 
 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
@@ -1163,53 +1192,59 @@ precedenti, ed inoltre aggiunge a \func{select} una nuova funzione
   \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{funcproto}{
+\fhead{sys/select.h}
+\fdecl{int pselect(int n, fd\_set *readfds, fd\_set *writefds, 
+  fd\_set *exceptfds, \\ 
+\phantom{int pselect(}struct timespec *timeout, sigset\_t *sigmask)}
+\fdesc{Attende che uno dei file descriptor degli insiemi specificati diventi
+  attivo.} 
+}
+{La funzione ritorna il numero (anche nullo) di file descriptor che sono
+  attivi in caso di successo e $-1$ per un 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}
+   \end{errlist}
+   ed inoltre \errval{ENOMEM} nel suo significato generico.
+}
+\end{funcproto}
 
 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 \textit{system call} di Linux
-  aggiorna il valore al tempo rimanente, ma la funzione fornita dalle
-  \acr{glibc} modifica questo comportamento passando alla \textit{system call}
-  una variabile locale, in modo da mantenere l'aderenza allo standard POSIX
-  che richiede che il valore di \param{timeout} non sia modificato.} Inoltre
-prende un argomento aggiuntivo \param{sigmask} che è il puntatore ad una
-\index{maschera~dei~segnali} maschera di segnali (si veda
-sez.~\ref{sec:sig_sigmask}).  La maschera corrente viene sostituita da questa
-immediatamente prima di eseguire l'attesa, e ripristinata al ritorno della
-funzione.
-
-L'uso di \param{sigmask} è stato introdotto allo scopo di prevenire possibili
-\textit{race condition} \itindex{race~condition} quando ci si deve porre in
-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
+caso di interruzione. In realtà anche in questo caso la \textit{system call}
+di Linux aggiorna il valore al tempo rimanente, ma la funzione fornita dalle
+\acr{glibc} modifica questo comportamento passando alla \textit{system call}
+una variabile locale, in modo da mantenere l'aderenza allo standard POSIX che
+richiede che il valore di \param{timeout} non sia modificato. 
+
+Rispetto a \func{select} la nuova funzione prende un argomento
+aggiuntivo \param{sigmask}, un puntatore ad una \index{maschera~dei~segnali}
+maschera di segnali (si veda sez.~\ref{sec:sig_sigmask}).  Nell'esecuzione la
+maschera dei segnali corrente viene sostituita da quella così indicata
+immediatamente prima di eseguire l'attesa, e viene poi ripristinata al ritorno
+della funzione. L'uso di \param{sigmask} è stato introdotto allo scopo di
+prevenire possibili \textit{race condition} \itindex{race~condition} quando
+oltre alla presenza di dati sui file descriptor come nella \func{select}
+ordinaria, ci si deve porre in attesa anche dell'arrivo di un segnale.
+
+Come abbiamo visto in sez.~\ref{sec:sig_example} la tecnica classica per
+rilevare l'arrivo di un segnale è quella di utilizzare il gestore per
+impostare una \index{variabili!globali} variabile globale e controllare questa
+nel corpo principale del programma; abbiamo visto in quell'occasione 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
@@ -1250,15 +1285,16 @@ 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{funcproto}{
+\fhead{sys/poll.h}
+\fdecl{int poll(struct pollfd *ufds, unsigned int nfds, int timeout)}
+\fdesc{La funzione attende un cambiamento di stato su un insieme di file
+  descriptor.} 
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un 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.
@@ -1266,8 +1302,8 @@ cui prototipo è:
   \item[\errcode{EINVAL}] il valore di \param{nfds} eccede il limite
     \const{RLIMIT\_NOFILE}.
   \end{errlist}
-  ed inoltre \errval{EFAULT} e \errval{ENOMEM}.}
-\end{prototype}
+  ed inoltre \errval{EFAULT} e \errval{ENOMEM} nel loro significato generico.}
+\end{funcproto}
 
 La funzione permette di tenere sotto controllo contemporaneamente \param{ndfs}
 file descriptor, specificati attraverso il puntatore \param{ufds} ad un