Inizio revisione select
[gapil.git] / fileadv.tex
index 480b3da5444aeafc1fc28ada86140d75f1e9c542..575504e9f09f624d47dbb830aa0b7a3d2930765e 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,33 @@ 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, in precedenza
+  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,31 +1043,31 @@ 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, come
+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