\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
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 opzione, con 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
\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}}
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
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.
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
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 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.
Si tenga presente inoltre che il \textit{mandatory locking} funziona solo
sull'interfaccia POSIX di \func{fcntl}. Questo ha due conseguenze: che non si
attuale delle cose è sconsigliabile fare affidamento sul \textit{mandatory
locking}.
-
\itindend{file~locking}
\itindend{mandatory~locking}
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
\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
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