Una lunga serie di modifiche per tenere conto della riorganizzazione della
[gapil.git] / fileadv.tex
index 531aaa0b7af806ecc604a6e7a88b15791426c5c7..2d000d8baa659e3a7e35f4bae109e3203262625b 100644 (file)
@@ -1,71 +1,99 @@
+%% fileadv.tex
+%%
+%% Copyright (C) 2000-2003 Simone Piccardi.  Permission is granted to
+%% copy, distribute and/or modify this document under the terms of the GNU Free
+%% Documentation License, Version 1.1 or any later version published by the
+%% Free Software Foundation; with the Invariant Sections being "Prefazione",
+%% with no Front-Cover Texts, and with no Back-Cover Texts.  A copy of the
+%% license is included in the section entitled "GNU Free Documentation
+%% License".
+%%
 \chapter{La gestione avanzata dei file}
 \label{cha:file_advanced}
 
 In questo capitolo affronteremo le tematiche relative alla gestione avanzata
-dei file, che non sono state trattate in \capref{cha:file_unix_interface},
-dove ci si è limitati ad una panoramica delle funzioni base. In particolare
-tratteremo delle funzioni di input/output avanzato e del \textit{file
-  locking}.
+dei file. In particolare tratteremo delle funzioni di input/output avanzato,
+che permettono una gestione più sofisticata dell'I/O su file, a partire da
+quelle che permettono di gestire l'accesso contemporaneo a più file, per
+concludere con la gestione dell'I/O mappato in memoria. Dedicheremo poi la
+fine del capitolo alle problematiche del \textit{file locking}.
 
 
-\section{Le funzioni di I/O avanzato}
-\label{sec:file_advanced_io}
+\section{L'\textit{I/O multiplexing}}
+\label{sec:file_multiplexing}
 
-In questa sezione esamineremo le funzioni che permettono una gestione più
-sofisticata dell'I/O su file, a partire da quelle che permettono di gestire
-l'accesso contemporaneo a più file, per concludere con la gestione dell'I/O
-mappato in memoria.
+Uno dei problemi che si presentano quando si deve operare contemporaneamente
+su molti file usando le funzioni illustrate in
+\capref{cha:file_unix_interface} e \capref{cha:files_std_interface} è che si
+può essere bloccati nelle operazioni su un file mentre un altro potrebbe
+essere disponibile. L'\textit{I/O multiplexing} nasce risposta a questo
+problema. In questa sezione forniremo una introduzione a questa problematica
+ed analizzeremo le varie funzioni usate per implementare questa modalità di
+I/O.
 
 
-\subsection{La modalità di I/O \textsl{non-bloccante}}
+\subsection{La problematica dell'\textit{I/O multiplexing}}
 \label{sec:file_noblocking}
 
 Abbiamo visto in \secref{sec:sig_gen_beha}, affrontando la suddivisione fra
-\textit{fast} e \textit{slow} system call, 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; 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.
+\textit{fast} e \textit{slow} 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\index{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 è quello che si verifica quando si
-devono eseguire operazioni che possono bloccarsi su più file descriptor:
-mentre si è bloccati su uno di essi su di un'altro potrebbero essere presenti
-dei dati; così che nel migliore dei casi si avrebbe una lettura ritardata
-inutilmente, e nel peggiore si potrebbe addirittura arrivare ad un deadlock.
+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 \textit{deadlock}\index{deadlock}.
 
 Abbiamo già accennato in \secref{sec:file_open} che è possibile prevenire
-questo tipo di comportamento aprendo un file in modalità
-\textsl{non-bloccante}, attraverso l'uso del flag \macro{O\_NONBLOCK} nella
-chiamata di \func{open}. In questo caso le funzioni di input/output che
-altrimenti si sarebbero bloccate ritornano immediatamente, restituendo
-l'errore \macro{EAGAIN}.
+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}, è estremamente inefficiente: si tiene costantemente
-impiegata la CPU solo per eseguire in continuazione delle system call che
-nella gran parte dei casi falliranno. Per evitare questo, come vedremo in
-\secref{sec:file_multiplexing}, è stata introdotta una nuova interfaccia di
-programmazione, che comporta comunque l'uso della modalità di I/O non
-bloccante.
-
-
-
-\subsection{L'I/O multiplexing}
-\label{sec:file_multiplexing}
-
-Per superare il problema di dover usare il \textit{polling} per controllare la
-possibilità di effettuare operazioni su un file aperto in modalità non
-bloccante, sia BSD che System V hanno introdotto delle nuove funzioni in grado
-di sospendere l'esecuzione di un processo in attesa che l'accesso diventi
-possibile.  Il primo ad introdurre questa modalità di operazione, chiamata
-usualmente \textit{I/O multiplexing}, è stato BSD,\footnote{la funzione è
-  apparsa in BSD4.2 e standardizzata in BSD4.4, ma è stata portata su tutti i
-  sistemi che supportano i \textit{socket}, compreso le varianti di System V.}
-con la funzione \func{select}, il cui prototipo è:
+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
+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 disponibile, 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
+prossimi paragrafi è per i server di rete, in cui esse vengono utilizzate per
+tenere sotto controllo dei socket; pertanto ritorneremo su di esse con
+ulteriori dettagli e qualche esempio in \secref{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 è:
 \begin{functions}
   \headdecl{sys/time.h}
   \headdecl{sys/types.h}
@@ -78,14 +106,15 @@ con la funzione \func{select}, il cui prototipo 
   
   \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} viene settata ai valori:
+    caso \var{errno} assumerà uno dei valori:
   \begin{errlist}
-  \item[\macro{EBADF}] Si è specificato un file descriptor sbagliato in uno
-  degli insiemi.
-  \item[\macro{EINTR}] La funzione è stata interrotta da un segnale.
-  \item[\macro{EINVAL}] Si è specificato per \param{n} un valore negativo.
+  \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{n} un valore negativo o
+    un valore non valido per \param{timeout}.
   \end{errlist}
-  ed inoltre \macro{ENOMEM}.
+  ed inoltre \errval{ENOMEM}.
 }
 \end{functions}
 
@@ -98,8 +127,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
-\secref{sec:sig_sigset}, identifica un insieme di segnali). Per la
+file descriptor, in maniera analoga a come un \textit{signal set} (vedi
+\secref{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}
@@ -120,245 +149,359 @@ opportune macro di preprocessore:
 \end{functions}
 
 In genere un \textit{file descriptor set} può contenere fino ad un massimo di
-\macro{FD\_SETSIZE} file descriptor.  Questo valore in origine corrispondeva
+\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
+  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, non c'è più un limite
 massimo, esso indica le dimensioni massime dei numeri usati nei \textit{file
-  descriptor set}.
+  descriptor set}.\footnote{il suo valore, secondo lo standard POSIX
+  1003.1-2001, è definito in \file{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.
 
 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, il secondo, \param{writefds}, per verificare la
-possibilità effettuare una scrittura ed il terzo, \param{exceptfds}, per
-verificare l'esistenza di condizioni eccezionali (come i messaggi urgenti su
-un \textit{socket}\index{socket}, vedi \secref{sec:xxx_urgent}).
-
-La funzione inoltre richiede anche di specificare, tramite l'argomento
-\param{n}, un valore massimo del numero dei file descriptor usati
-nell'insieme; si può usare il già citato \macro{FD\_SETSIZE}, oppure il numero
-più alto dei file descriptor usati nei tre insiemi, aumentato di uno.
-
-Infine l'argomento \param{timeout}, specifica un tempo massimo di
-attesa\footnote{il tempo è valutato come \textit{elapsed time}.} prima che la
-funzione ritorni; se settato a \macro{NULL} la funzione attende
-indefinitamente. Si può specificare anche un tempo nullo (cioè una \var{struct
-  timeval} con i campi settati a zero), qualora si voglia semplicemente
-controllare lo stato corrente dei file descriptor.
-
-La funzione restituisce il totale dei file descriptor pronti nei tre insiemi,
-il valore zero indica sempre che si è raggiunto un timeout. Ciascuno dei tre
-insiemi viene sovrascritto per indicare quale file descriptor è pronto per le
-operazioni ad esso relative, in modo da poterlo controllare con la macro
-\macro{FD\_ISSET}. In caso di errore la funzione restituisce -1 e gli insiemi
-non vengono toccati.
-
-In Linux \func{select} modifica anche il valore di \param{timeout}, settandolo
-al tempo restante; questo è utile quando la funzione viene interrotta da un
-segnale, in tal caso infatti si ha un errore di \macro{EINTR}, ed occorre
-rilanciare la funzione; in questo modo non è necessario ricalcolare tutte le
-volte il tempo rimanente.\footnote{questo può causare problemi di portabilità
-  sia quando si trasporta 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 la caratteristica è disponibile nei sistemi che derivano da System V
-  e non disponibile per quelli che derivano da BSD.}
-
-Come accennato l'interfaccia di \func{select} è una estensione di BSD; anche
-System V ha introdotto una sua interfaccia per gestire l'\textit{I/O
-  multiplexing}, basata sulla funzione \func{poll},\footnote{la funzione è
+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}.} il secondo,
+\param{writefds}, per verificare la possibilità effettuare una scrittura ed il
+terzo, \param{exceptfds}, per verificare l'esistenza di eccezioni (come i
+messaggi urgenti su un \textit{socket}\index{socket}, vedi
+\secref{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
+specificare qual'è il numero massimo dei 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{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.
+
+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.
+
+In Linux \func{select} modifica anche il valore di \param{timeout},
+impostandolo al tempo restante in caso di interruzione prematura; questo è
+utile 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.\footnote{questo può causare problemi di portabilità sia quando si
+  trasporta 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 la
+  caratteristica è disponibile nei sistemi che derivano da System V e non
+  disponibile per quelli che derivano da BSD.}
+
+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
+controllo.  Infatti il kernel riceve con \param{n} un valore massimo per tale
+valore, e per capire quali sono i file descriptor da tenere sotto controllo
+dovrà effettuare una scansione su tutto l'intervallo, che può anche essere
+anche molto ampio anche se i file descriptor sono solo poche unità; tutto ciò
+ha ovviamente delle conseguenze ampiamente negative per le prestazioni.
+
+Inoltre c'è anche il problema che il numero massimo dei file che si possono
+tenere sotto controllo, la funzione è nata quando il kernel consentiva un
+numero massimo di 1024 file descriptor per processo, adesso che il numero può
+essere arbitario si viene a creare una dipendenza del tutto artificiale dalle
+dimensioni della struttura \type{fd\_set}, che può necessitare di essere
+estesa, con ulteriori perdite di prestazioni. 
+
+Lo standard POSIX è rimasto a lungo senza primitive per l'\textit{I/O
+  multiplexing}, introdotto solo con le ultime revisioni dello standard (POSIX
+1003.1g-2000 e POSIX 1003.1-2001). La scelta è stata quella di seguire
+l'interfaccia creata da BSD, ma prevede che tutte le funzioni ad esso relative
+vengano dichiarate nell'header \file{sys/select.h}, che sostituisce i
+precedenti, ed inoltre aggiunge a \func{select} una nuova funzione
+\funcd{pselect},\footnote{il supporto per lo standard POSIX 1003.1-2001, ed
+  l'header \file{sys/select.h}, compaiono in Linux a partire dalle \acr{glibc}
+  2.1. Le \acr{libc4} e \acr{libc5} non contengono questo header, le
+  \acr{glibc} 2.0 contengono una definizione sbagliata di \func{psignal},
+  senza l'argomento \param{sigmask}, la definizione corretta è presente dalle
+  \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{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{n} un valore negativo o
+    un valore non valido per \param{timeout}.
+  \end{errlist}
+  ed inoltre \errval{ENOMEM}.}
+\end{prototype}
+
+La funzione è sostanzialmente identica a \func{select}, solo che usa una
+struttura \struct{timespec} (vedi \figref{fig:sys_timeval_struct}) per
+indicare con maggiore precisione il timeout e non ne aggiorna il valore in
+caso di interruzione. Inoltre prende un argomento aggiuntivo \param{sigmask}
+che è il puntatore ad una maschera di segnali (si veda
+\secref{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
+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 \secref{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
+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
+alla gestione dati con un ciclo del tipo:
+\includecodesnip{listati/select_race.c} qui però emerge una race
+condition,\index{race condition} perché se il segnale arriva prima della
+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
+\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 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.
+
+
+
+\subsection{La funzione \func{poll}}
+\label{sec:file_poll}
+
+Nello sviluppo di System V, invece di utilizzare l'interfaccia di
+\func{select}, che è una estensione tipica di BSD, è stata introdotta un'altra
+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 e dalle \acr{libc} 5.4.28.} il cui prototipo è:
+  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 attente un cambiamento di stato per uno dei file descriptor
-specificati da \param{ufds}.
   
-\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} viene settata ai valori:
+  La funzione attende un cambiamento di stato per uno dei file descriptor
+  specificati da \param{ufds}.
+  
+  \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:
   \begin{errlist}
-  \item[\macro{EBADF}] Si è specificato un file descriptor sbagliato in uno
-  degli insiemi.
-  \item[\macro{EINTR}] La funzione è stata interrotta da un segnale.
+  \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}] Il valore di \param{nfds} eccede il limite
+    \macro{RLIMIT\_NOFILE}.
   \end{errlist}
-  ed inoltre \macro{EFAULT} e \macro{ENOMEM}.}
+  ed inoltre \errval{EFAULT} e \errval{ENOMEM}.}
 \end{prototype}
 
-La funzione tiene sotto controllo un numero \param{ndfs} di file descriptor
-specificati attraverso un vettore di puntatori a strutture di tipo
-\type{pollfd}, la cui definizione è riportata in \figref{fig:file_pollfd}.
-Come \func{select} anche \func{poll} permette di interrompere l'attesa dopo un
-certo tempo, che va specificato attraverso \param{timeout} in numero di
-millisecondi (un valore negativo indica un'attesa indefinita).
+La funzione permette di tenere sotto controllo contemporaneamente \param{ndfs}
+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à
+\textsl{non-bloccante}).
 
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
-    \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
-struct pollfd {
-        int fd;           /* file descriptor */
-        short events;     /* requested events */
-        short revents;    /* returned events */
-};
-    \end{lstlisting}
+    \includestruct{listati/pollfd.h}
   \end{minipage} 
   \normalsize 
-  \caption{La struttura \type{pollfd}, utilizzata per specificare le modalità
-    di controllo di un file descriptor alla funzione \func{poll}.}
+  \caption{La struttura \structd{pollfd}, utilizzata per specificare le
+    modalità di controllo di un file descriptor alla funzione \func{poll}.}
   \label{fig:file_pollfd}
 \end{figure}
 
-Per ciascun file da controllare deve essere opportunamente predisposta una
-struttura \type{pollfd}; nel campo \var{fd} deve essere specificato il file
-descriptor, mentre nel campo \var{events} il tipo di evento su cui si vuole
-attendere; quest'ultimo deve essere specificato come maschera binaria dei
-primi tre valori riportati in \tabref{tab:file_pollfd_flags} (gli altri
-vengono utilizzati solo per \var{revents} come valori in uscita).
+Per ciascun file da controllare deve essere inizializzata una struttura
+\struct{pollfd} nel vettore indicato dall'argomento \param{ufds}.  La
+struttura, la cui definizione è riportata in \figref{fig:file_pollfd}, prevede
+tre campi: in \var{fd} deve essere indicato il numero del file descriptor da
+controllare, in \var{events} deve essere specificata una maschera binaria di
+flag che indichino il tipo di evento che si vuole controllare, mentre in
+\var{revents} il kernel restituirà il relativo risultato.  Usando un valore
+negativo per \param{fd} la corrispondente struttura sarà ignorata da
+\func{poll}. Dato che i dati in ingresso sono del tutto indipendenti da quelli
+in uscita (che vengono restituiti in \var{revents}) non è necessario
+reinizializzare tutte le volte il valore delle strutture \struct{pollfd} a
+meno di non voler cambiare qualche condizione.
+
+Le costanti che definiscono i valori relativi ai bit usati nelle maschere
+binarie dei campi \var{events} e \var{revents} sono riportati in
+\tabref{tab:file_pollfd_flags}, insieme al loro significato. Le si sono
+suddivise in tre gruppi, nel primo gruppo si sono indicati i bit utilizzati
+per controllare l'attività in ingresso, nel secondo quelli per l'attività in
+uscita, mentre il terzo gruppo contiene dei valori che vengono utilizzati solo
+nel campo \var{revents} per notificare delle condizioni di errore. 
 
 \begin{table}[htb]
   \centering
   \footnotesize
-  \begin{tabular}[c]{|l|c|l|}
+  \begin{tabular}[c]{|l|l|}
+    \hline
+    \textbf{Flag}  & \textbf{Significato} \\
     \hline
-    \textbf{Flag} & \textbf{Valore} & \textbf{Significato} \\
     \hline
+    \const{POLLIN}    & È possibile la lettura.\\
+    \const{POLLRDNORM}& Sono disponibili in lettura dati normali.\\ 
+    \const{POLLRDBAND}& Sono disponibili in lettura dati prioritari. \\
+    \const{POLLPRI}   & È possibile la lettura di dati urgenti.\\
     \hline
-    \macro{POLLIN}    & 0x001 & È possibile la lettura immediata.\\
-    \macro{POLLPRI}   & 0x002 & Sono presenti dati urgenti.\\
-    \macro{POLLOUT}   & 0x004 & È possibile la scrittura immediata.\\
+    \const{POLLOUT}   & È possibile la scrittura immediata.\\
+    \const{POLLWRNORM}& È possibile la scrittura di dati normali.  \\ 
+    \const{POLLWRBAND}& È possibile la scrittura di dati prioritari. \\
     \hline
-    \macro{POLLERR}   & 0x008 & C'è una condizione di errore.\\
-    \macro{POLLHUP}   & 0x010 & Si è verificato un hung-up.\\
-    \macro{POLLNVAL}  & 0x020 & Il file descriptor non è aperto.\\
+    \const{POLLERR}   & C'è una condizione di errore.\\
+    \const{POLLHUP}   & Si è verificato un hung-up.\\
+    \const{POLLNVAL}  & Il file descriptor non è aperto.\\
     \hline
-    \macro{POLLRDNORM}& 0x040 & Sono disponibili in lettura dati normali.\\ 
-    \macro{POLLRDBAND}& 0x080 & Sono disponibili in lettura dati ad alta 
-                                priorità. \\
-    \macro{POLLWRNORM}& 0x100 & È possibile la scrittura di dati normali.  \\ 
-    \macro{POLLWRBAND}& 0x200 & È possibile la scrittura di dati ad 
-                                alta priorità. \\
-    \macro{POLLMSG}   & 0x400 & Estensione propria di Linux.\\
+    \const{POLLMSG}   & Definito per compatobilità con SysV.\\
     \hline    
   \end{tabular}
   \caption{Costanti per l'identificazione dei vari bit dei campi
-    \var{events} e \var{revents} di \type{pollfd}.}
+    \var{events} e \var{revents} di \struct{pollfd}.}
   \label{tab:file_pollfd_flags}
 \end{table}
 
-La funzione ritorna, restituendo il numero di file per i quali si è verificata
-una delle condizioni di attesa richieste o un errore. Lo stato dei file
-all'uscita della funzione viene restituito nel campo \var{revents} della
-relativa struttura \type{pollfd}, che viene settato alla maschera binaria dei
-valori riportati in \tabref{tab:file_pollfd_flags}, ed oltre alle tre
-condizioni specificate tramite \var{events} può riportare anche l'occorrere di
-una condizione di errore.
-
-Lo standard POSIX è rimasto a lungo senza primitive per l'\textit{I/O
-  multiplexing}, che è stata introdotto con le ultime revisioni dello standard
-(POSIX 1003.1g-2000 e POSIX 1003.1-2001). Esso prevede che tutte le funzioni
-ad esso relative vengano dichiarate nell'header \file{sys/select.h}, che
-sostituisce i precedenti, ed aggiunge a \func{select} una nuova funzione
-\func{pselect},\footnote{il supporto per lo standard POSIX 1003.1-2001, ed
-  l'header \file{sys/select.h}, compaiono in Linux a partire dalle \acr{glibc}
-  2.1. Le \acr{libc4} e \acr{libc5} non contengono questo header, le
-  \acr{glibc} 2.0 contengono una definizione sbagliata di \func{psignal},
-  senza l'argomento \param{sigmask}, la definizione corretta è presente dalle
-  \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} viene settata ai valori:
-  \begin{errlist}
-  \item[\macro{EBADF}] Si è specificato un file descriptor sbagliato in uno
-  degli insiemi.
-  \item[\macro{EINTR}] La funzione è stata interrotta da un segnale.
-  \item[\macro{EINVAL}] Si è specificato per \param{n} un valore negativo.
-  \end{errlist}
-  ed inoltre \macro{ENOMEM}.}
-\end{prototype}
-
-La funzione è sostanzialmente identica a \func{select}, solo che usa una
-struttura \type{timespec} per indicare con maggiore precisione il timeout e
-non ne aggiorna il valore in caso di interruzione, inoltre prende un argomento
-aggiuntivo \param{sigmask} che è il puntatore ad una maschera di segnali (si
-veda \secref{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
-race condition\footnote{in Linux però, non esistendo una system call apposita,
-  la funzione è implementata nelle \acr{glibc} usando \func{select}, e la
-  possibilità di una race condition resta.} quando si deve eseguire un test su
-una variabile settata da un manipolatore sulla base dell'occorrenza di un
-segnale per decidere se lanciare \func{select}. Fra il test e l'esecuzione è
-presente una finestra in cui potrebbe arrivare il segnale che non sarebbe
-rilevato; la race condition diventa superabile disabilitando il segnale prima
-del test e riabilitandolo poi grazie all'uso di \param{sigmask}.
-
-
-
-\subsection{L'\textsl{I/O asincrono}}
-\label{sec:file_asyncronous_io}
-
-Una modalità alternativa all'uso dell'\textit{I/O multiplexing} è quella di
-fare ricorso al cosiddetto \textsl{I/O asincrono}. Il concetto base
-dell'\textsl{I/O asincrono} è che le funzioni di I/O non attendono il
-completamento delle operazioni prima di ritornare, così che il processo non
-viene bloccato.  In questo modo diventa ad esempio possibile effettuare una
-richiesta preventiva di dati, in modo da poter effettuare in contemporanea le
-operazioni di calcolo e quelle di I/O.
+Il valore \const{POLLMSG} non viene utilizzato ed è definito solo per
+compatibilità con l'implementazione di SysV che usa gli
+\textit{stream};\footnote{essi sono una interfaccia specifica di SysV non
+  presente in Linux, e non hanno nulla a che fare con i file \textit{stream}
+  delle librerie standard del C.} è da questi che derivano i nomi di alcune
+costanti, in quanto per essi sono definite tre classi di dati:
+\textsl{normali}, \textit{prioritari} ed \textit{urgenti}.  In Linux la
+distinzione ha senso solo per i dati \textit{out-of-band} dei socket (vedi
+\secref{sec:TCP_urgent_data}), ma su questo e su come \func{poll} reagisce
+alle varie condizioni dei socket torneremo in \secref{sec:TCP_serv_poll}, dove
+vedremo anche un esempio del suo utilizzo. Si tenga conto comunque che le
+costanti relative ai diversi tipi di dati (come \macro{POLLRDNORM} e
+\macro{POLLRDBAND}) sono utilizzabili soltanto qualora si sia definito
+\macro{\_XOPEN\_SOURCE}.\footnote{e ci si ricordi di farlo sempre in testa al
+  file, definirla soltanto prima di includere \file{sys/poll.h} non è
+  sufficiente.}
+
+In caso di successo funzione ritorna restituendo il numero di file (un valore
+positivo) per i quali si è verificata una delle condizioni di attesa richieste
+o per i quali si è verificato un errore (nel qual caso vengono utilizzati i
+valori di \tabref{tab:file_pollfd_flags} esclusivi di \var{revents}). Un
+valore nullo indica che si è raggiunto il timeout, mentre un valore negativo
+indica un errore nella chiamata, il cui codice viene riportato al solito
+tramite \var{errno}.
+
+
+%\subsection{L'interfaccia di \textit{epoll}}
+%\label{sec:file_epoll}
+% placeholder ...
+
+%da fare
+
+\section{L'accesso \textsl{asincrono} ai file}
+\label{sec:file_asyncronous_access}
+
+Benché l'\textit{I/O multiplexing} sia stata la prima, e sia tutt'ora una fra
+le più diffuse modalità di gestire l'I/O in situazioni complesse in cui si
+debba operare su più file contemporaneamente, esistono altre modalità di
+gestione delle stesse problematiche. In particolare sono importanti in questo
+contesto le modalità di accesso ai file eseguibili in maniera
+\textsl{asincrona}, senza cioè che un processo debba bloccarsi, ed utilizzi
+invece un meccanismo di notifica asincrono, come un segnale, per rilevare la
+possibilità di eseguire le operazioni volute.
+
+
+\subsection{Operazioni asincrone sui file}
+\label{sec:file_asyncronous_operation}
 
 Abbiamo accennato in \secref{sec:file_open} che è possibile, attraverso l'uso
-del flag \macro{O\_ASYNC},\footnote{l'uso del flag di \macro{O\_ASYNC} e dei
-  comandi \macro{F\_SETOWN} e \macro{F\_GETOWN} per \func{fcntl} è specifico
+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à settando questo flag attraverso
-l'uso di \func{fcntl} con il comando \macro{F\_SETFL} (vedi
+attivare in un secondo tempo questa modalità impostando questo flag attraverso
+l'uso di \func{fcntl} con il comando \const{F\_SETFL} (vedi
 \secref{sec:file_fcntl}). 
 
-In realtà in questo caso non si tratta di I/O asincrono vero e proprio, quanto
-di un meccanismo asincrono di notifica delle variazione dello stato del file
-descriptor; quello che succede è che il sistema genera un segnale (normalmente
-\macro{SIGIO}, ma è possibile usarne altri) 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 \macro{F\_SETOWN} di
-\func{fcntl}, quale processo (o gruppo di processi) riceverà il segnale. 
+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
+\secref{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 è 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}, quale processo (o gruppo di
+processi) riceverà il segnale. Se pertanto si effettuano le operazioni in
+risposta alla ricezione del segnale non ci sarà più la necessità di restare
+bloccati in attesa della disponibilità di accesso ai file.
 
 In questo modo si può evitare l'uso delle funzioni \func{poll} o \func{select}
 che, quando vengono usate con un numero molto grande di file descriptor, non
-hanno buone prestazioni. In tal caso infatti la maggior parte del loro tempo
+hanno buone prestazioni. % aggiungere cenno a epoll quando l'avrò scritta
+ In tal caso infatti la maggior parte del loro tempo
 di esecuzione è impegnato ad eseguire una scansione su tutti i file descriptor
 tenuti sotto controllo per determinare quali di essi (in genere una piccola
 percentuale) sono diventati attivi.
 
 Tuttavia con l'implementazione classica dei segnali questa modalità di I/O
-presenta notevoli problemi, dato che non è possibile determinare, quando sono
-più di uno, qual'è il file descriptor responsabile dell'emissione del segnale.
-Linux però supporta le estensioni POSIX.1b dei segnali che permettono di
-superare il problema facendo ricorso alle informazioni aggiuntive restituite
-attraverso la struttura \type{siginfo\_t}, utilizzando la forma estesa
-\var{sa\_sigaction} del manipolatore (si riveda quanto illustrato in
+presenta notevoli problemi, dato che non è possibile determinare, quando i
+file descriptor sono più di uno, qual'è quello responsabile dell'emissione del
+segnale; inoltre dato che i segnali normali non si accumulano, in presenza di
+più file descriptor attivi contemporaneamente, più segnali emessi nello stesso
+tempo verrebbero notificati una volta sola. Linux però supporta le estensioni
+POSIX.1b dei segnali real-time, che possono accumularsi e che permettono di
+riconoscere il file descriptor facendo ricorso alle informazioni aggiuntive
+restituite attraverso la struttura \struct{siginfo\_t}, utilizzando la forma
+estesa \var{sa\_sigaction} del gestore (si riveda quanto illustrato in
 \secref{sec:sig_sigaction}).
 
 Per far questo però occorre utilizzare le funzionalità dei segnali real-time
-(vedi \secref{sec:sig_real_time}) settando esplicitamente con il comando
-\macro{F\_SETSIG} di \func{fcntl} un segnale real-time da inviare in caso di
-I/O asincrono (il segnale di default è \macro{SIGIO}). In questo caso il
-manipolatore tutte le volte che riceverà \macro{SI\_SIGIO} come valore del
-campo \var{si\_code}\footnote{il valore resta \macro{SI\_SIGIO} qualunque sia
+(vedi \secref{sec:sig_real_time}) impostando esplicitamente con il comando
+\const{F\_SETSIG} di \func{fcntl} un segnale real-time da inviare in caso di
+I/O asincrono (il segnale predefinito è \const{SIGIO}). In questo caso il
+gestore, tutte le volte che riceverà \const{SI\_SIGIO} come valore del
+campo \var{si\_code}\footnote{il valore resta \const{SI\_SIGIO} qualunque sia
   il segnale che si è associato all'I/O asincrono, ed indica appunto che il
   segnale è stato generato a causa di attività nell'I/O asincrono.} di
-\type{siginfo\_t}, troverà nel campo \var{si\_fd} il valore del file
+\struct{siginfo\_t}, troverà nel campo \var{si\_fd} il valore del file
 descriptor che ha generato il segnale.
 
 Un secondo vantaggio dell'uso dei segnali real-time è che essendo dotati di
@@ -369,61 +512,842 @@ cui l'accesso 
 come \func{poll} e \func{select}, almeno fintanto che non si satura la coda;
 si eccedono le dimensioni di quest'ultima; in tal caso infatti il kernel, non
 potendo più assicurare il comportamento corretto per un segnale real-time,
-invierà al suo posto un \var{SIGIO}, su cui si accumuleranno tutti i segnali
-in eccesso, e si dovrà determinare al solito modo quali sono i file diventati
+invierà al suo posto un \const{SIGIO}, su cui si accumuleranno tutti i segnali
+in eccesso, e si dovrà determinare con un ciclo quali sono i file diventati
 attivi.
 
 
+\subsection{L'interfaccia POSIX per l'I/O asincrono}
+\label{sec:file_asyncronous_io}
+
+Una modalità alternativa all'uso dell'\textit{I/O multiplexing} per gestione
+dell'I/O simultaneo su molti file è costituita dal cosiddetto \textsl{I/O
+  asincrono}. Il concetto base dell'\textsl{I/O asincrono} è che le funzioni
+di I/O non attendono il completamento delle operazioni prima di ritornare,
+così che il processo non viene bloccato.  In questo modo diventa ad esempio
+possibile effettuare una richiesta preventiva di dati, in modo da poter
+effettuare in contemporanea le operazioni di calcolo e quelle di I/O.
 
 Benché la modalità di apertura asincrona di un file possa risultare utile in
-varie occasioni (in particolar modo con i socket e gli altri file per i quali
-le funzioni di I/O sono system call lente), essa è comunque limitata alla
-notifica della disponibilità del file descriptor per le operazioni di I/O, e
-non ad uno svolgimento asincrono delle medesime.  Lo standard POSIX.1b
-definisce anche una interfaccia apposita per l'I/O asincrono, che prevede un
-insieme di funzioni dedicate, completamente separate rispetto a quelle usate
-normalmente.
+varie occasioni (in particolar modo con i socket\index{socket} e gli altri
+file per i quali le funzioni di I/O sono \index{system call lente}system call
+lente), essa è comunque limitata alla notifica della disponibilità del file
+descriptor per le operazioni di I/O, e non ad uno svolgimento asincrono delle
+medesime.  Lo standard POSIX.1b definisce una interfaccia apposita per l'I/O
+asincrono vero e proprio, che prevede un insieme di funzioni dedicate per la
+lettura e la scrittura dei file, completamente separate rispetto a quelle
+usate normalmente.
 
 In generale questa interfaccia è completamente astratta e può essere
 implementata sia direttamente nel kernel, che in user space attraverso l'uso
-di thread. Al momento\footnote{fino ai kernel della serie 2.4.x, nella serie
-  2.5.x è però iniziato un lavoro completo di riscrittura di tutto il sistema
-  di I/O, che prevede anche l'introduzione di un nuovo layer per l'I/O
-  asincrono.} esiste una sola versione stabile di questa interfaccia, quella
-delle \acr{glibc}, che è realizzata completamente in user space.  Esistono
-comunque vari progetti sperimentali (come il KAIO della SGI, o i patch di
-Benjamin La Haise) che prevedono una interfaccia che utilizza un supporto
-diretto da parte del kernel.
+di thread. Al momento esiste una sola versione stabile di questa interfaccia,
+quella delle \acr{glibc}, che è realizzata completamente in user space, ed
+accessibile linkando i programmi con la libreria \file{librt}. Nei kernel
+della nuova serie è stato anche introdotta (a partire dal 2.5.32) un nuovo
+layer per l'I/O asincrono.
+
+Lo standard prevede che tutte le operazioni di I/O asincrono siano controllate
+attraverso l'uso di una apposita struttura \struct{aiocb} (il cui nome sta per
+\textit{asyncronous I/O control block}), che viene passata come argomento a
+tutte le funzioni dell'interfaccia. La sua definizione, come effettuata in
+\file{aio.h}, è riportata in \figref{fig:file_aiocb}. Nello steso file è
+definita la macro \macro{\_POSIX\_ASYNCHRONOUS\_IO}, che dichiara la
+disponibilità dell'interfaccia per l'I/O asincrono.
 
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includestruct{listati/aiocb.h}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \structd{aiocb}, usata per il controllo dell'I/O
+    asincrono.}
+  \label{fig:file_aiocb}
+\end{figure}
+
+Le operazioni di I/O asincrono possono essere effettuate solo su un file già
+aperto; il file deve inoltre supportare la funzione \func{lseek}, pertanto
+terminali e pipe sono esclusi. Non c'è limite al numero di operazioni
+contemporanee effettuabili su un singolo file.  Ogni operazione deve
+inizializzare opportunamente un \textit{control block}.  Il file descriptor su
+cui operare deve essere specificato tramite il campo \var{aio\_fildes}; dato
+che più operazioni possono essere eseguita in maniera asincrona, il concetto
+di posizione corrente sul file viene a mancare; pertanto si deve sempre
+specificare nel campo \var{aio\_offset} la posizione sul file da cui i dati
+saranno letti o scritti.  Nel campo \var{aio\_buf} deve essere specificato
+l'indirizzo del buffer usato per l'I/O, ed in \var{aio\_nbytes} la lunghezza
+del blocco di dati da trasferire.
+
+Il campo \var{aio\_reqprio} permette di impostare la priorità delle operazioni
+di I/O.\footnote{in generale perché ciò sia possibile occorre che la
+  piattaforma supporti questa caratteristica, questo viene indicato definendo
+  le macro \macro{\_POSIX\_PRIORITIZED\_IO}, e
+  \macro{\_POSIX\_PRIORITY\_SCHEDULING}.} La priorità viene impostata a
+partire da quella del processo chiamante (vedi \secref{sec:proc_priority}),
+cui viene sottratto il valore di questo campo.  Il campo
+\var{aio\_lio\_opcode} è usato solo dalla funzione \func{lio\_listio}, che,
+come vedremo, permette di eseguire con una sola chiamata una serie di
+operazioni, usando un vettore di \textit{control block}. Tramite questo campo
+si specifica quale è la natura di ciascuna di esse.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includestruct{listati/sigevent.h}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \structd{sigevent}, usata per specificare le modalità
+    di notifica degli eventi relativi alle operazioni di I/O asincrono.}
+  \label{fig:file_sigevent}
+\end{figure}
 
+Infine il campo \var{aio\_sigevent} è una struttura di tipo \struct{sigevent}
+che serve a specificare il modo in cui si vuole che venga effettuata la
+notifica del completamento delle operazioni richieste. La struttura è
+riportata in \secref{fig:file_sigevent}; il campo \var{sigev\_notify} è quello
+che indica le modalità della notifica, esso può assumere i tre valori:
+\begin{basedescript}{\desclabelwidth{2.6cm}}
+\item[\const{SIGEV\_NONE}]  Non viene inviata nessuna notifica.
+\item[\const{SIGEV\_SIGNAL}] La notifica viene effettuata inviando al processo
+  chiamante il segnale specificato da \var{sigev\_signo}; se il gestore di
+  questo è stato installato con \const{SA\_SIGINFO} gli verrà restituito il
+  valore di \var{sigev\_value} (la cui definizione è in
+  \figref{fig:sig_sigval}) come valore del campo \var{si\_value} di
+  \struct{siginfo\_t}.
+\item[\const{SIGEV\_THREAD}] La notifica viene effettuata creando un nuovo
+  thread che esegue la funzione specificata da \var{sigev\_notify\_function}
+  con argomento \var{sigev\_value}, e con gli attributi specificati da
+  \var{sigev\_notify\_attribute}.
+\end{basedescript}
+
+Le due funzioni base dell'interfaccia per l'I/O asincrono sono
+\funcd{aio\_read} ed \funcd{aio\_write}.  Esse permettono di richiedere una
+lettura od una scrittura asincrona di dati, usando la struttura \struct{aiocb}
+appena descritta; i rispettivi prototipi sono:
+\begin{functions}
+  \headdecl{aio.h}
 
+  \funcdecl{int aio\_read(struct aiocb *aiocbp)}
+  Richiede una lettura asincrona secondo quanto specificato con \param{aiocbp}.
+
+  \funcdecl{int aio\_write(struct aiocb *aiocbp)}
+  Richiede una scrittura asincrona secondo quanto specificato con
+  \param{aiocbp}.
+  
+  \bodydesc{Le funzioni restituiscono 0 in caso di successo, e -1 in caso di
+    errore, nel qual caso \var{errno} assumerà uno dei valori:
+  \begin{errlist}
+  \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato.
+  \item[\errcode{ENOSYS}] La funzione non è implementata.
+  \item[\errcode{EINVAL}] Si è specificato un valore non valido per i campi
+    \var{aio\_offset} o \var{aio\_reqprio} di \param{aiocbp}.
+  \item[\errcode{EAGAIN}] La coda delle richieste è momentaneamente piena.
+  \end{errlist}
+}
+\end{functions}
 
-\subsection{I/O multiplo}
+Entrambe le funzioni ritornano immediatamente dopo aver messo in coda la
+richiesta, o in caso di errore. Non è detto che gli errori \errcode{EBADF} ed
+\errcode{EINVAL} siano rilevati immediatamente al momento della chiamata,
+potrebbero anche emergere nelle fasi successive delle operazioni. Lettura e
+scrittura avvengono alla posizione indicata da \var{aio\_offset}, a meno che
+il file non sia stato aperto in \textit{append mode} (vedi
+\secref{sec:file_open}), nel qual caso le scritture vengono effettuate
+comunque alla fine de file, nell'ordine delle chiamate a \func{aio\_write}.
+
+Si tenga inoltre presente che deallocare la memoria indirizzata da
+\param{aiocbp} o modificarne i valori prima della conclusione di una
+operazione può dar luogo a risultati impredicibili, perché l'accesso ai vari
+campi per eseguire l'operazione può avvenire in un momento qualsiasi dopo la
+richiesta.  Questo comporta che non si devono usare per \param{aiocbp}
+variabili automatiche e che non si deve riutilizzare la stessa struttura per
+un'altra operazione fintanto che la precedente non sia stata ultimata. In
+generale per ogni operazione si deve utilizzare una diversa struttura
+\struct{aiocb}.
+
+Dato che si opera in modalità asincrona, il successo di \func{aio\_read} o
+\func{aio\_write} non implica che le operazioni siano state effettivamente
+eseguite in maniera corretta; per verificarne l'esito l'interfaccia prevede
+altre due funzioni, che permettono di controllare lo stato di esecuzione. La
+prima è \funcd{aio\_error}, che serve a determinare un eventuale stato di
+errore; il suo prototipo è:
+\begin{prototype}{aio.h}
+  {int aio\_error(const struct aiocb *aiocbp)}  
+
+  Determina lo stato di errore delle operazioni di I/O associate a
+  \param{aiocbp}.
+  
+  \bodydesc{La funzione restituisce 0 se le operazioni si sono concluse con
+    successo, altrimenti restituisce il codice di errore relativo al loro
+    fallimento.}
+\end{prototype}
+
+Se l'operazione non si è ancora completata viene restituito l'errore di
+\errcode{EINPROGRESS}. La funzione ritorna zero quando l'operazione si è
+conclusa con successo, altrimenti restituisce il codice dell'errore
+verificatosi, ed esegue la corrispondente impostazione di \var{errno}. Il
+codice può essere sia \errcode{EINVAL} ed \errcode{EBADF}, dovuti ad un valore
+errato per \param{aiocbp}, che uno degli errori possibili durante l'esecuzione
+dell'operazione di I/O richiesta, nel qual caso saranno restituiti, a seconda
+del caso, i codici di errore delle system call \func{read}, \func{write} e
+\func{fsync}.
+
+Una volta che si sia certi che le operazioni siano state concluse (cioè dopo
+che una chiamata ad \func{aio\_error} non ha restituito
+\errcode{EINPROGRESS}), si potrà usare la funzione \funcd{aio\_return}, che
+permette di verificare il completamento delle operazioni di I/O asincrono; il
+suo prototipo è:
+\begin{prototype}{aio.h}
+{ssize\_t aio\_return(const struct aiocb *aiocbp)} 
+
+Recupera il valore dello stato di ritorno delle operazioni di I/O associate a
+\param{aiocbp}.
+  
+\bodydesc{La funzione restituisce lo stato di uscita dell'operazione
+  eseguita.}
+\end{prototype}
+
+La funzione deve essere chiamata una sola volte per ciascuna operazione
+asincrona, essa infatti fa sì che il sistema rilasci le risorse ad essa
+associate. É per questo motivo che occorre chiamare la funzione solo dopo che
+l'operazione cui \param{aiocbp} fa riferimento si è completata. Una chiamata
+precedente il completamento delle operazioni darebbe risultati indeterminati.
+
+La funzione restituisce il valore di ritorno relativo all'operazione eseguita,
+così come ricavato dalla sottostante system call (il numero di byte letti,
+scritti o il valore di ritorno di \func{fsync}).  É importante chiamare sempre
+questa funzione, altrimenti le risorse disponibili per le operazioni di I/O
+asincrono non verrebbero liberate, rischiando di arrivare ad un loro
+esaurimento.
+
+Oltre alle operazioni di lettura e scrittura l'interfaccia POSIX.1b mette a
+disposizione un'altra operazione, quella di sincronizzazione dell'I/O,
+compiuta dalla funzione \func{aio\_fsync}, che ha lo stesso effetto della
+analoga \func{fsync}, ma viene eseguita in maniera asincrona; il suo prototipo
+è:
+\begin{prototype}{aio.h}
+{ssize\_t aio\_return(int op, struct aiocb *aiocbp)} 
+
+Richiede la sincronizzazione dei dati per il file indicato da \param{aiocbp}.
+  
+\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+  errore, che può essere, con le stesse modalità di \func{aio\_read},
+  \errval{EAGAIN}, \errval{EBADF} o \errval{EINVAL}.}
+\end{prototype}
+
+La funzione richiede la sincronizzazione delle operazioni di I/O, ritornando
+immediatamente. L'esecuzione effettiva della sincronizzazione dovrà essere
+verificata con \func{aio\_error} e \func{aio\_return} come per le operazioni
+di lettura e scrittura. L'argomento \param{op} permette di indicare la
+modalità di esecuzione, se si specifica il valore \const{O\_DSYNC} le
+operazioni saranno completate con una chiamata a \func{fdatasync}, se si
+specifica \const{O\_SYNC} con una chiamata a \func{fsync} (per i dettagli vedi
+\secref{sec:file_sync}).
+
+Il successo della chiamata assicura la sincronizzazione delle operazioni fino
+allora richieste, niente è garantito riguardo la sincronizzazione dei dati
+relativi ad eventuali operazioni richieste successivamente. Se si è
+specificato un meccanismo di notifica questo sarà innescato una volta che le
+operazioni di sincronizzazione dei dati saranno completate.
+
+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
+permette di cancellare una operazione richiesta in precedenza; il suo
+prototipo è:
+\begin{prototype}{aio.h}
+{int aio\_cancel(int fildes, struct aiocb *aiocbp)} 
+
+Richiede la cancellazione delle operazioni sul file \param{fildes} specificate
+da \param{aiocbp}.
+  
+\bodydesc{La funzione restituisce il risultato dell'operazione con un codice
+  di positivo, e -1 in caso di errore, che avviene qualora si sia specificato
+  un valore non valido di \param{fildes}, imposta \var{errno} al valore
+  \errval{EBADF}.}
+\end{prototype}
+
+La funzione permette di cancellare una operazione specifica sul file
+\param{fildes}, o tutte le operazioni pendenti, specificando \val{NULL} come
+valore di \param{aiocbp}.  Quando una operazione viene cancellata una
+successiva chiamata ad \func{aio\_error} riporterà \errcode{ECANCELED} come
+codice di errore, ed il suo codice di ritorno sarà -1, inoltre il meccanismo
+di notifica non verrà invocato. Se si specifica una operazione relativa ad un
+altro file descriptor il risultato è indeterminato.
+
+In caso di successo, i possibili valori di ritorno per \func{aio\_cancel} sono
+tre (anch'essi definiti in \file{aio.h}):
+\begin{basedescript}{\desclabelwidth{3.0cm}}
+\item[\const{AIO\_ALLDONE}] indica che le operazioni di cui si è richiesta la
+  cancellazione sono state già completate,
+  
+\item[\const{AIO\_CANCELED}] indica che tutte le operazioni richieste sono
+  state cancellate,  
+  
+\item[\const{AIO\_NOTCANCELED}] indica che alcune delle operazioni erano in
+  corso e non sono state cancellate.
+\end{basedescript}
+
+Nel caso si abbia \const{AIO\_NOTCANCELED} occorrerà chiamare
+\func{aio\_error} per determinare quali sono le operazioni effettivamente
+cancellate. Le operazioni che non sono state cancellate proseguiranno il loro
+corso normale, compreso quanto richiesto riguardo al meccanismo di notifica
+del loro avvenuto completamento.
+
+Benché l'I/O asincrono preveda un meccanismo di notifica, l'interfaccia
+fornisce anche una apposita funzione, \funcd{aio\_suspend}, che permette di
+sospendere l'esecuzione del processo chiamante fino al completamento di una
+specifica operazione; il suo prototipo è:
+\begin{prototype}{aio.h}
+{int aio\_suspend(const struct aiocb * const list[], int nent, const struct
+    timespec *timeout)}
+  
+  Attende, per un massimo di \param{timeout}, il completamento di una delle
+  operazioni specificate da \param{list}.
+  
+  \bodydesc{La funzione restituisce 0 se una (o più) operazioni sono state
+    completate, e -1 in caso di errore nel qual caso \var{errno} assumerà uno
+    dei valori:
+    \begin{errlist}
+    \item[\errcode{EAGAIN}] Nessuna operazione è stata completata entro
+      \param{timeout}.
+    \item[\errcode{ENOSYS}] La funzione non è implementata.
+    \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale.
+    \end{errlist}
+  }
+\end{prototype}
+
+La funzione permette di bloccare il processo fintanto che almeno una delle
+\param{nent} operazioni specificate nella lista \param{list} è completata, per
+un tempo massimo specificato da \param{timout}, o fintanto che non arrivi un
+segnale.\footnote{si tenga conto che questo segnale può anche essere quello
+  utilizzato come meccanismo di notifica.} La lista deve essere inizializzata
+con delle strutture \struct{aiocb} relative ad operazioni effettivamente
+richieste, ma può contenere puntatori nulli, che saranno ignorati. In caso si
+siano specificati valori non validi l'effetto è indefinito.  Un valore
+\val{NULL} per \param{timout} comporta l'assenza di timeout.
+
+Lo standard POSIX.1b infine ha previsto pure una funzione, \funcd{lio\_listio},
+che permette di effettuare la richiesta di una intera lista di operazioni di
+lettura o scrittura; il suo prototipo è:
+\begin{prototype}{aio.h}
+  {int lio\_listio(int mode, struct aiocb * const list[], int nent, struct
+    sigevent *sig)}
+  
+  Richiede l'esecuzione delle operazioni di I/O elencata da \param{list},
+  secondo la modalità \param{mode}.
+  
+  \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
+    errore, nel qual caso \var{errno} assumerà uno dei valori:
+    \begin{errlist}
+    \item[\errcode{EAGAIN}] Nessuna operazione è stata completata entro
+      \param{timeout}.
+    \item[\errcode{EINVAL}] Si è passato un valore di \param{mode} non valido
+      o un numero di operazioni \param{nent} maggiore di
+      \const{AIO\_LISTIO\_MAX}.
+    \item[\errcode{ENOSYS}] La funzione non è implementata.
+    \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale.
+    \end{errlist}
+  }
+\end{prototype}
+
+La funzione esegue la richiesta delle \param{nent} operazioni indicate dalla
+lista \param{list}; questa deve contenere gli indirizzi di altrettanti
+\textit{control block}, opportunamente inizializzati; in particolare nel caso
+dovrà essere specificato il tipo di operazione tramite il campo
+\var{aio\_lio\_opcode}, che può prendere i tre valori:
+\begin{basedescript}{\desclabelwidth{2.0cm}}
+\item[\const{LIO\_READ}]  si richiede una operazione di lettura.
+\item[\const{LIO\_WRITE}] si richiede una operazione di scrittura.
+\item[\const{LIO\_NOP}] non si effettua nessuna operazione.
+\end{basedescript}
+l'ultimo valore viene usato quando si ha a che fare con un vettore di
+dimensione fissa, per poter specificare solo alcune operazioni, o quando si è
+dovuto cancellare delle operazioni e si deve ripetere la richiesta per quelle
+non completate.
+
+L'argomento \param{mode} permette di stabilire il comportamento della
+funzione, se viene specificato il valore \const{LIO\_WAIT} la funzione si
+blocca fino al completamento di tutte le operazioni richieste; se invece si
+specifica \const{LIO\_NOWAIT} la funzione ritorna immediatamente dopo aver
+messo in coda tutte le richieste. In questo caso il chiamante può richiedere
+la notifica del completamento di tutte le richieste, impostando l'argomento
+\param{sig} in maniera analoga a come si fa per il campo \var{aio\_sigevent}
+di \struct{aiocb}.
+
+
+\section{Altre modalità di I/O avanzato}
+\label{sec:file_advanced_io}
+
+Oltre alle precedenti modalità di \textit{I/O multiplexing} e \textsl{I/O
+  asincrono}, esistono altre funzioni che implementano delle modalità di
+accesso ai file più evolute rispetto alle normali funzioni di lettura e
+scrittura che abbiamo esaminato in \secref{sec:file_base_func}. In questa
+sezione allora prenderemo in esame le interfacce per l'\textsl{I/O
+  vettorizzato} e per l'\textsl{I/O mappato in memoria}.
+
+
+\subsection{I/O vettorizzato}
 \label{sec:file_multiple_io}
 
-Un caso abbastanza comune è quello in cui ci si trova a dover affrontare una
+Un caso abbastanza comune è quello in cui ci si trova a dover eseguire una
 serie multipla di operazioni di I/O, come una serie di letture o scritture di
-vari buffer. In questo caso 
+vari buffer. Un esempio tipico è quando i dati sono strutturati nei campi di
+una struttura ed essi devono essere caricati o salvati su un file.  Benché
+l'operazione sia facilmente eseguibile attraverso una serie multipla di
+chiamate, ci sono casi in cui si vuole poter contare sulla atomicità delle
+operazioni.
+
+Per questo motivo BSD 4.2\footnote{Le due funzioni sono riprese da BSD4.4 ed
+  integrate anche dallo standard Unix 98. Fino alle libc5, Linux usava
+  \type{size\_t} come tipo dell'argomento \param{count}, una scelta logica,
+  che però è stata dismessa per restare aderenti allo standard.} ha introdotto
+due nuove system call, \funcd{readv} e \funcd{writev}, che permettono di
+effettuare con una sola chiamata una lettura o una scrittura su una serie di
+buffer (quello che viene chiamato \textsl{I/O vettorizzato}. I relativi
+prototipi sono:
+\begin{functions}
+  \headdecl{sys/uio.h}
+  
+  \funcdecl{int readv(int fd, const struct iovec *vector, int count)} Esegue
+  una lettura vettorizzata da \param{fd} nei \param{count} buffer specificati
+  da \param{vector}.
+  
+  \funcdecl{int writev(int fd, const struct iovec *vector, int count)} Esegue
+  una scrittura vettorizzata da \param{fd} nei \param{count} buffer
+  specificati da \param{vector}.
+  
+  \bodydesc{Le funzioni restituiscono il numero di byte letti o scritti in
+    caso di successo, e -1 in caso di errore, nel qual caso \var{errno}
+    assumerà uno dei valori:
+  \begin{errlist}
+  \item[\errcode{EBADF}] si è specificato un file descriptor sbagliato.
+  \item[\errcode{EINVAL}] si è specificato un valore non valido per uno degli
+    argomenti (ad esempio \param{count} è maggiore di \const{MAX\_IOVEC}).
+  \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale prima di
+    di avere eseguito una qualunque lettura o scrittura.
+  \item[\errcode{EAGAIN}] \param{fd} è stato aperto in modalità non bloccante e
+  non ci sono dati in lettura.
+  \item[\errcode{EOPNOTSUPP}] La coda delle richieste è momentaneamente piena.
+  \end{errlist}
+  ed inoltre \errval{EISDIR}, \errval{ENOMEM}, \errval{EFAULT} (se non sono
+  stato allocati correttamente i buffer specificati nei campi
+  \func{iov\_base}), più tutti gli ulteriori errori che potrebbero avere le
+  usuali funzioni di lettura e scrittura eseguite su \param{fd}.}
+\end{functions}
+
+Entrambe le funzioni usano una struttura \struct{iovec}, definita in
+\figref{fig:file_iovec}, che definisce dove i dati devono essere letti o
+scritti. Il primo campo, \var{iov\_base}, contiene l'indirizzo del buffer ed
+il secondo, \var{iov\_len}, la dimensione dello stesso. 
 
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includestruct{listati/iovec.h}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \structd{iovec}, usata dalle operazioni di I/O
+    vettorizzato.} 
+  \label{fig:file_iovec}
+\end{figure}
+
+I buffer da utilizzare sono indicati attraverso l'argomento \param{vector} che
+è un vettore di strutture \struct{iovec}, la cui lunghezza è specificata da
+\param{count}.  Ciascuna struttura dovrà essere inizializzata per
+opportunamente per indicare i vari buffer da/verso i quali verrà eseguito il
+trasferimento dei dati. Essi verranno letti (o scritti) nell'ordine in cui li
+si sono specificati nel vettore \param{vector}.
 
 
 \subsection{File mappati in memoria}
 \label{sec:file_memory_map}
 
 Una modalità alternativa di I/O, che usa una interfaccia completamente diversa
-rispetto a quella classica, è quella dei file \textsl{mappati in memoria}. In
-sostanza quello che si fa è usare il meccanismo della
-\textsl{paginazione}\index{paginazione} usato per la memoria virtuale (vedi
-\secref{sec:proc_mem_gen}) per trasformare vedere il file in una sezione dello
-spazio di indirizzi del processo, in modo che l'accesso a quest'ultimo con le
-normali operazioni di lettura e scrittura delle variabili in memoria, si
-trasformi in I/O sul file stesso.
+rispetto a quella classica vista in \capref{cha:file_unix_interface}, è il
+cosiddetto \textit{memory-mapped I/O}, che, attraverso il meccanismo della
+\textsl{paginazione}\index{paginazione} usato dalla memoria virtuale (vedi
+\secref{sec:proc_mem_gen}), permette di \textsl{mappare} il contenuto di un
+file in una sezione dello spazio di indirizzi del processo. Il meccanismo è
+illustrato in \figref{fig:file_mmap_layout}, una sezione del file viene
+riportata direttamente nello spazio degli indirizzi del programma. Tutte le
+operazioni su questa zona verranno riportate indietro sul file dal meccanismo
+della memoria virtuale\index{memoria virtuale} che trasferirà il contenuto di
+quel segmento sul file invece che nella swap, per cui si può parlare tanto di
+file mappato in memoria, quanto di memoria mappata su file.
+
+\begin{figure}[htb]
+  \centering
+  \includegraphics[width=7.cm]{img/mmap_layout}
+  \caption{Disposizione della memoria di un processo quando si esegue la
+  mappatura in memoria di un file.}
+  \label{fig:file_mmap_layout}
+\end{figure}
+
+Tutto questo comporta una notevole semplificazione delle operazioni di I/O, in
+quanto non sarà più necessario utilizzare dei buffer intermedi su cui
+appoggiare i dati da traferire, ma questi potranno essere acceduti
+direttamente nella sezione di memoria mappata; inoltre questa interfaccia è
+più efficiente delle usuali funzioni di I/O, in quanto permette di caricare in
+memoria solo le parti del file che sono effettivamente usate ad un dato
+istante.
+
+Infatti, dato che l'accesso è fatto direttamente attraverso la memoria
+virtuale,\index{memoria virtuale} la sezione di memoria mappata su cui si
+opera sarà a sua volta letta o scritta sul file una pagina alla volta e solo
+per le parti effettivamente usate, il tutto in maniera completamente
+trasparente al processo; l'accesso alle pagine non ancora caricate avverrà
+allo stesso modo con cui vengono caricate in memoria le pagine che sono state
+salvate sullo swap.  Infine in situazioni in cui la memoria è scarsa, le
+pagine che mappano un file vengono salvate automaticamente, così come le
+pagine dei programmi vengono scritte sulla swap; questo consente di accedere
+ai file su dimensioni il cui solo limite è quello dello spazio di indirizzi
+disponibile, e non della memoria su cui possono esserne lette delle porzioni.
+
+L'interfaccia prevede varie funzioni per la gestione del \textit{memory mapped
+  I/O}, la prima di queste è \funcd{mmap}, che serve ad eseguire la mappatura
+in memoria di un file; il suo prototipo è:
+\begin{functions}
+  
+  \headdecl{unistd.h}
+  \headdecl{sys/mman.h} 
+
+  \funcdecl{void * mmap(void * start, size\_t length, int prot, int flags, int
+    fd, off\_t offset)}
+  
+  Esegue la mappatura in memoria del file \param{fd}.
+  
+  \bodydesc{La funzione restituisce il puntatore alla zona di memoria mappata
+    in caso di successo, e \const{MAP\_FAILED} (-1) in caso di errore, nel
+    qual caso \var{errno} assumerà uno dei valori:
+    \begin{errlist}
+    \item[\errcode{EBADF}] Il file descriptor non è valido, e non si è usato
+      \const{MAP\_ANONYMOUS}.
+    \item[\errcode{EACCES}] o \param{fd} non si riferisce ad un file regolare,
+      o si è usato \const{MAP\_PRIVATE} ma \param{fd} non è aperto in lettura,
+      o si è usato \const{MAP\_SHARED} e impostato \const{PROT\_WRITE} ed
+      \param{fd} non è aperto in lettura/scrittura, o si è impostato
+      \const{PROT\_WRITE} ed \param{fd} è in \textit{append-only}.
+    \item[\errcode{EINVAL}] I valori di \param{start}, \param{length} o
+      \param{offset} non sono validi (o troppo grandi o non allineati sulla
+      dimensione delle pagine).
+    \item[\errcode{ETXTBSY}] Si è impostato \const{MAP\_DENYWRITE} ma
+      \param{fd} è aperto in scrittura.
+    \item[\errcode{EAGAIN}] Il file è bloccato, o si è bloccata troppa memoria.
+    \item[\errcode{ENOMEM}] Non c'è memoria o si è superato il limite sul
+      numero di mappature possibili.
+    \item[\errcode{ENODEV}] Il filesystem di \param{fd} non supporta il memory
+      mapping.
+    \end{errlist}
+  }
+\end{functions}
 
+La funzione richiede di mappare in memoria la sezione del file \param{fd} a
+partire da \param{offset} per \param{lenght} byte, preferibilmente
+all'indirizzo \param{start}. Il valore di \param{offset} deve essere un
+multiplo della dimensione di una pagina di memoria. 
+
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|l|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{PROT\_EXEC}  & Le pagine possono essere eseguite.\\
+    \const{PROT\_READ}  & Le pagine possono essere lette.\\
+    \const{PROT\_WRITE} & Le pagine possono essere scritte.\\
+    \const{PROT\_NONE}  & L'accesso alle pagine è vietato.\\
+    \hline    
+  \end{tabular}
+  \caption{Valori dell'argomento \param{prot} di \func{mmap}, relativi alla
+    protezione applicate alle pagine del file mappate in memoria.}
+  \label{tab:file_mmap_prot}
+\end{table}
+
+
+Il valore dell'argomento \param{prot} indica la protezione\footnote{in Linux
+  la memoria reale è divisa in pagine: ogni processo vede la sua memoria
+  attraverso uno o più segmenti lineari di memoria virtuale.  Per ciascuno di
+  questi segmenti il kernel mantiene nella \textit{page table} la mappatura
+  sulle pagine di memoria reale, ed le modalità di accesso (lettura,
+  esecuzione, scrittura); una loro violazione causa quella che si chiama una
+  \textit{segment violation}, e la relativa emissione del segnale
+  \const{SIGSEGV}.} da applicare al segmento di memoria e deve essere
+specificato come maschera binaria ottenuta dall'OR di uno o più dei valori
+riportati in \tabref{tab:file_mmap_flag}; il valore specificato deve essere
+compatibile con la modalità di accesso con cui si è aperto il file.
+
+L'argomento \param{flags} specifica infine qual'è il tipo di oggetto mappato,
+le opzioni relative alle modalità con cui è effettuata la mappatura e alle
+modalità con cui le modifiche alla memoria mappata vengono condivise o
+mantenute private al processo che le ha effettuate. Deve essere specificato
+come maschera binaria ottenuta dall'OR di uno o più dei valori riportati in
+\tabref{tab:file_mmap_flag}.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{10cm}|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{MAP\_FIXED}     & Non permette di restituire un indirizzo diverso
+                             da \param{start}, se questo non può essere usato
+                             \func{mmap} fallisce. Se si imposta questo flag il
+                             valore di \param{start} deve essere allineato
+                             alle dimensioni di una pagina. \\
+    \const{MAP\_SHARED}    & I cambiamenti sulla memoria mappata vengono
+                             riportati sul file e saranno immediatamente
+                             visibili agli altri processi che mappano lo stesso
+                             file.\footnotemark Il file su disco però non sarà
+                             aggiornato fino alla chiamata di \func{msync} o
+                             \func{unmap}), e solo allora le modifiche saranno
+                             visibili per l'I/O convenzionale. Incompatibile
+                             con \const{MAP\_PRIVATE}. \\ 
+    \const{MAP\_PRIVATE}   & I cambiamenti sulla memoria mappata non vengono
+                             riportati sul file. Ne viene fatta una copia
+                             privata cui solo il processo chiamante ha
+                             accesso.  Le modifiche sono mantenute attraverso
+                             il meccanismo del 
+                             \textit{copy on write}\index{copy on write} e
+                             salvate su swap in caso di necessità. Non è
+                             specificato se i cambiamenti sul file originale
+                             vengano riportati sulla regione
+                             mappata. Incompatibile con \const{MAP\_SHARED}. \\
+    \const{MAP\_DENYWRITE} & In Linux viene ignorato per evitare
+                             \textit{DoS}\index{DoS} (veniva usato per
+                             segnalare che tentativi di scrittura sul file
+                             dovevano fallire con \errcode{ETXTBSY}).\\
+    \const{MAP\_EXECUTABLE}& Ignorato. \\
+    \const{MAP\_NORESERVE} & Si usa con \const{MAP\_PRIVATE}. Non riserva
+                             delle pagine di swap ad uso del meccanismo di
+                             \textit{copy on write}\index{copy on write}
+                             per mantenere le
+                             modifiche fatte alla regione mappata, in
+                             questo caso dopo una scrittura, se non c'è più
+                             memoria disponibile, si ha l'emissione di
+                             un \const{SIGSEGV}. \\
+    \const{MAP\_LOCKED}    & Se impostato impedisce lo swapping delle pagine
+                             mappate. \\
+    \const{MAP\_GROWSDOWN} & Usato per gli stack. Indica 
+                             che la mappatura deve essere effettuata con gli
+                             indirizzi crescenti verso il basso.\\
+    \const{MAP\_ANONYMOUS} & La mappatura non è associata a nessun file. Gli
+                             argomenti \param{fd} e \param{offset} sono
+                             ignorati.\footnotemark\\
+    \const{MAP\_ANON}      & Sinonimo di \const{MAP\_ANONYMOUS}, deprecato.\\
+    \const{MAP\_FILE}      & Valore di compatibilità, deprecato.\\
+    \hline
+  \end{tabular}
+  \caption{Valori possibili dell'argomento \param{flag} di \func{mmap}.}
+  \label{tab:file_mmap_flag}
+\end{table}
+
+\footnotetext{Dato che tutti faranno riferimento alle stesse pagine di
+  memoria.}  
+\footnotetext{L'uso di questo flag con \const{MAP\_SHARED} è
+  stato implementato in Linux a partire dai kernel della serie 2.4.x.}
+
+Gli effetti dell'accesso ad una zona di memoria mappata su file possono essere
+piuttosto complessi, essi si possono comprendere solo tenendo presente che
+tutto quanto è comunque basato sul basato sul meccanismo della memoria
+virtuale.\index{memoria virtuale} Questo comporta allora una serie di
+conseguenze. La più ovvia è che se si cerca di scrivere su una zona mappata in
+sola lettura si avrà l'emissione di un segnale di violazione di accesso
+(\const{SIGSEGV}), dato che i permessi sul segmento di memoria relativo non
+consentono questo tipo di accesso.
+
+\begin{figure}[!htb]
+  \centering
+  \includegraphics[width=10cm]{img/mmap_boundary}
+  \caption{Schema della mappatura in memoria di una sezione di file di
+    dimensioni non corrispondenti al bordo di una pagina.}
+  \label{fig:file_mmap_boundary}
+\end{figure}
+
+È invece assai diversa la questione relativa agli accessi al di fuori della
+regione di cui si è richiesta la mappatura. A prima vista infatti si potrebbe
+ritenere che anch'essi debbano generare un segnale di violazione di accesso;
+questo però non tiene conto del fatto che, essendo basata sul meccanismo della
+paginazione\index{paginazione}, la mappatura in memoria non può che essere
+eseguita su un segmento di dimensioni rigorosamente multiple di quelle di una
+pagina, ed in generale queste potranno non corrispondere alle dimensioni
+effettive del file o della sezione che si vuole mappare. Il caso più comune è
+quello illustrato in \figref{fig:file_mmap_boundary}, in cui la sezione di
+file non rientra nei confini di una pagina: in tal caso verrà il file sarà
+mappato su un segmento di memoria che si estende fino al bordo della pagina
+successiva.
+
+In questo caso è possibile accedere a quella zona di memoria che eccede le
+dimensioni specificate da \param{lenght}, senza ottenere un \const{SIGSEGV}
+poiché essa è presente nello spazio di indirizzi del processo, anche se non è
+mappata sul file. Il comportamento del sistema è quello di restituire un
+valore nullo per quanto viene letto, e di non riportare su file quanto viene
+scritto.
+
+Un caso più complesso è quello che si viene a creare quando le dimensioni del
+file mappato sono più corte delle dimensioni della mappatura, oppure quando il
+file è stato troncato, dopo che è stato mappato, ad una dimensione inferiore a
+quella della mappatura in memoria.
+
+\begin{figure}[htb]
+  \centering
+  \includegraphics[width=10cm]{img/mmap_exceed}
+  \caption{Schema della mappatura in memoria di file di dimensioni inferiori
+    alla lunghezza richiesta.}
+  \label{fig:file_mmap_exceed}
+\end{figure}
+
+In questa situazione, per la sezione di pagina parzialmente coperta dal
+contenuto del file, vale esattamente quanto visto in precedenza; invece per la
+parte che eccede, fino alle dimensioni date da \param{length}, l'accesso non
+sarà più possibile, ma il segnale emesso non sarà \const{SIGSEGV}, ma
+\const{SIGBUS}, come illustrato in \figref{fig:file_mmap_exceed}.
+
+Non tutti i file possono venire mappati in memoria, dato che, come illustrato
+in \figref{fig:file_mmap_layout}, la mappatura introduce una corrispondenza
+biunivoca fra una sezione di un file ed una sezione di memoria. Questo
+comporta che ad esempio non è possibile mappare in memoria file descriptor
+relativi a pipe, socket e fifo, per i quali non ha senso parlare di
+\textsl{sezione}. Lo stesso vale anche per alcuni file di dispositivo, che non
+dispongono della relativa operazione \func{mmap} (si ricordi quanto esposto in
+\secref{sec:file_vfs_work}). Si tenga presente però che esistono anche casi di
+dispositivi (un esempio è l'interfaccia al ponte PCI-VME del chip Universe)
+che sono utilizzabili solo con questa interfaccia.
+
+Dato che passando attraverso una \func{fork} lo spazio di indirizzi viene
+copiato integralmente, i file mappati in memoria verranno ereditati in maniera
+trasparente dal processo figlio, mantenendo gli stessi attributi avuti nel
+padre; così se si è usato \const{MAP\_SHARED} padre e figlio accederanno allo
+stesso file in maniera condivisa, mentre se si è usato \const{MAP\_PRIVATE}
+ciascuno di essi manterrà una sua versione privata indipendente. Non c'è
+invece nessun passaggio attraverso una \func{exec}, dato che quest'ultima
+sostituisce tutto lo spazio degli indirizzi di un processo con quello di un
+nuovo programma.
+
+Quando si effettua la mappatura di un file vengono pure modificati i tempi ad
+esso associati (di cui si è trattato in \secref{sec:file_file_times}). Il
+valore di \var{st\_atime} può venir cambiato in qualunque istante a partire
+dal momento in cui la mappatura è stata effettuata: il primo riferimento ad
+una pagina mappata su un file aggiorna questo tempo.  I valori di
+\var{st\_ctime} e \var{st\_mtime} possono venir cambiati solo quando si è
+consentita la scrittura sul file (cioè per un file mappato con
+\const{PROT\_WRITE} e \const{MAP\_SHARED}) e sono aggiornati dopo la scrittura
+o in corrispondenza di una eventuale \func{msync}.
+
+Dato per i file mappati in memoria le operazioni di I/O sono gestite
+direttamente dalla memoria virtuale, occorre essere consapevoli delle
+interazioni che possono esserci con operazioni effettuate con l'interfaccia
+standard dei file di \capref{cha:file_unix_interface}. Il problema è che una
+volta che si è mappato un file, le operazioni di lettura e scrittura saranno
+eseguite sulla memoria, e riportate su disco in maniera autonoma dal sistema
+della memoria virtuale.
+
+Pertanto se si modifica un file con l'interfaccia standard queste modifiche
+potranno essere visibili o meno a seconda del momento in cui la memoria
+virtuale trasporterà dal disco in memoria quella sezione del file, perciò è
+del tutto imprevedibile il risultato della modifica di un file nei confronti
+del contenuto della memoria su cui è mappato.
+
+Per questo, è sempre sconsigliabile eseguire scritture su file attraverso
+l'interfaccia standard, quando lo si è mappato in memoria, è invece possibile
+usare l'interfaccia standard per leggere un file mappato in memoria, purché si
+abbia una certa cura; infatti l'interfaccia dell'I/O mappato in memoria mette
+a disposizione la funzione \funcd{msync} per sincronizzare il contenuto della
+memoria mappata con il file su disco; il suo prototipo è:
+\begin{functions}  
+  \headdecl{unistd.h}
+  \headdecl{sys/mman.h} 
+
+  \funcdecl{int msync(const void *start, size\_t length, int flags)}
+  
+  Sincronizza i contenuti di una sezione di un file mappato in memoria.
+  
+  \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
+    errore nel qual caso \var{errno} assumerà uno dei valori:
+    \begin{errlist}
+    \item[\errcode{EINVAL}] O \param{start} non è multiplo di \const{PAGESIZE},
+    o si è specificato un valore non valido per \param{flags}.
+    \item[\errcode{EFAULT}] L'intervallo specificato non ricade in una zona
+      precedentemente mappata.
+    \end{errlist}
+  }
+\end{functions}
+
+La funzione esegue la sincronizzazione di quanto scritto nella sezione di
+memoria indicata da \param{start} e \param{offset}, scrivendo le modifiche sul
+file (qualora questo non sia già stato fatto).  Provvede anche ad aggiornare i
+relativi tempi di modifica. In questo modo si è sicuri che dopo l'esecuzione
+di \func{msync} le funzioni dell'interfaccia standard troveranno un contenuto
+del file aggiornato.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|l|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{MS\_ASYNC}     & Richiede la sincronizzazione.\\
+    \const{MS\_SYNC}      & Attende che la sincronizzazione si eseguita.\\
+    \const{MS\_INVALIDATE}& Richiede che le altre mappature dello stesso file
+                            siano invalidate.\\
+    \hline    
+  \end{tabular}
+  \caption{Valori dell'argomento \param{flag} di \func{msync}.}
+  \label{tab:file_mmap_rsync}
+\end{table}
+
+L'argomento \param{flag} è specificato come maschera binaria composta da un OR
+dei valori riportati in \tabref{tab:file_mmap_rsync}, di questi però
+\const{MS\_ASYNC} e \const{MS\_SYNC} sono incompatibili; con il primo valore
+infatti la funzione si limita ad inoltrare la richiesta di sincronizzazione al
+meccanismo della memoria virtuale, ritornando subito, mentre con il secondo
+attende che la sincronizzazione sia stata effettivamente eseguita. Il terzo
+flag fa invalidare le pagine di cui si richiede la sincronizzazione per tutte
+le mappature dello stesso file, così che esse possano essere immediatamente
+aggiornate ai nuovi valori.
+
+Una volta che si sono completate le operazioni di I/O si può eliminare la
+mappatura della memoria usando la funzione \funcd{munmap}, il suo prototipo è:
+\begin{functions}  
+  \headdecl{unistd.h}
+  \headdecl{sys/mman.h} 
+
+  \funcdecl{int munmap(void *start, size\_t length)}
+  
+  Rilascia la mappatura sulla sezione di memoria specificata.
+
+  \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
+    errore nel qual caso \var{errno} assumerà uno dei valori:
+    \begin{errlist}
+    \item[\errcode{EINVAL}] L'intervallo specificato non ricade in una zona
+      precedentemente mappata.
+    \end{errlist}
+  }
+\end{functions}
+
+La funzione cancella la mappatura per l'intervallo specificato attraverso
+\param{start} e \param{length}, ed ogni successivo accesso a tale regione
+causerà un errore di accesso in memoria. L'argomento \param{start} deve essere
+allineato alle dimensioni di una pagina di memoria, e la mappatura di tutte le
+pagine contenute (anche parzialmente) nell'intervallo indicato, verrà rimossa.
+Indicare un intervallo che non contiene pagine mappate non è un errore.
+
+Alla conclusione del processo, ogni pagina mappata verrà automaticamente
+rilasciata, mentre la chiusura del file descriptor usato per effettuare la
+mappatura in memoria non ha alcun effetto sulla stessa.
 
 
 \section{Il file locking}
 \label{sec:file_locking}
 
+\index{file!locking|(}
 In \secref{sec:file_sharing} abbiamo preso in esame le modalità in cui un
 sistema unix-like gestisce la condivisione dei file da parte di processi
 diversi. In quell'occasione si è visto come, con l'eccezione dei file aperti
@@ -438,28 +1362,820 @@ processi scrivono, mescolando in maniera imprevedibile il loro output sul
 file.
 
 In tutti questi casi il \textit{file locking} è la tecnica che permette di
-evitare le race condition, attraverso una serie di funzioni che permettono di
-bloccare l'accesso al file da parte di altri processi, così da evitare le
-sovrapposizioni, e garantire la atomicità delle operazioni di scrittura.
+evitare le race condition\index{race condition}, attraverso una serie di
+funzioni che permettono di bloccare l'accesso al file da parte di altri
+processi, così da evitare le sovrapposizioni, e garantire la atomicità delle
+operazioni di scrittura.
+
 
 
 \subsection{L'\textit{advisory locking}}
 \label{sec:file_record_locking}
 
-La prima modalità di file locking che è stata implementata nei sistemi
-unix-like è quella che viene usualmente chiamata \textit{advisory locking}, in
-quanto è il processo, e non il sistema, che si incarica di verificare se
-esiste una condizione di blocco per l'accesso ai file.
+La prima modalità di \textit{file locking} che è stata implementata nei
+sistemi unix-like è quella che viene usualmente chiamata \textit{advisory
+  locking},\footnote{Stevens in \cite{APUE} fa riferimento a questo argomento
+  come al \textit{record locking}, dizione utilizzata anche dal manuale delle
+  \acr{glibc}; nelle pagine di manuale si parla di \textit{discretionary file
+    lock} per \func{fcntl} e di \textit{advisory locking} per \func{flock},
+  mentre questo nome viene usato da Stevens per riferirsi al \textit{file
+    locking} POSIX. Dato che la dizione \textit{record locking} è quantomeno
+  ambigua, in quanto in un sistema Unix non esiste niente che possa fare
+  riferimento al concetto di \textit{record}, alla fine si è scelto di
+  mantenere il nome \textit{advisory locking}.} in quanto sono i singoli
+processi, e non il sistema, che si incaricano di asserire e verificare se
+esistono delle condizioni di blocco per l'accesso ai file.  Questo significa
+che le funzioni \func{read} o \func{write} vengono eseguite comunque e non
+risentono affatto della presenza di un eventuale \textit{lock}; pertanto è
+sempre compito dei vari processi che intendono usare il file locking,
+controllare esplicitamente lo stato dei file condivisi prima di accedervi,
+utilizzando le relative funzioni.
+
+In generale si distinguono due tipologie di \textit{file lock}:\footnote{di
+  seguito ci riferiremo sempre ai blocchi di accesso ai file con la
+  nomenclatura inglese di \textit{file lock}, o più brevemente con
+  \textit{lock}, per evitare confusioni linguistiche con il blocco di un
+  processo (cioè la condizione in cui il processo viene posto in stato di
+  \textit{sleep}).} la prima è il cosiddetto \textit{shared lock}, detto anche
+\textit{read lock} in quanto serve a bloccare l'accesso in scrittura su un
+file affinché il suo contenuto non venga modificato mentre lo si legge. Si
+parla appunto di \textsl{blocco condiviso} in quanto più processi possono
+richiedere contemporaneamente uno \textit{shared lock} su un file per
+proteggere il loro accesso in lettura.
+
+La seconda tipologia è il cosiddetto \textit{exclusive lock}, detto anche
+\textit{write lock} in quanto serve a bloccare l'accesso su un file (sia in
+lettura che in scrittura) da parte di altri processi mentre lo si sta
+scrivendo. Si parla di \textsl{blocco esclusivo} appunto perché un solo
+processo alla volta può richiedere un \textit{exclusive lock} su un file per
+proteggere il suo accesso in scrittura.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|c|c|c|}
+    \hline
+    \textbf{Richiesta} & \multicolumn{3}{|c|}{\textbf{Stato del file}}\\
+    \cline{2-4}
+                       &Nessun lock&\textit{Read lock}&\textit{Write lock}\\
+    \hline
+    \hline
+    \textit{Read lock} & SI & SI & NO \\
+    \textit{Write lock}& SI & NO & NO \\
+    \hline    
+  \end{tabular}
+  \caption{Tipologie di file locking.}
+  \label{tab:file_file_lock}
+\end{table}
+
+In Linux sono disponibili due interfacce per utilizzare l'\textit{advisory
+  locking}, la prima è quella derivata da BSD, che è basata sulla funzione
+\func{flock}, la seconda è quella standardizzata da POSIX.1 (derivata da
+System V), che è basata sulla funzione \func{fcntl}.  I \textit{file lock}
+sono implementati in maniera completamente indipendente nelle due interfacce,
+che pertanto possono coesistere senza interferenze.
+
+Entrambe le interfacce prevedono la stessa procedura di funzionamento: si
+inizia sempre con il richiedere l'opportuno \textit{file lock} (un
+\textit{exclusive lock} per una scrittura, uno \textit{shared lock} per una
+lettura) prima di eseguire l'accesso ad un file.  Se il lock viene acquisito
+il processo prosegue l'esecuzione, altrimenti (a meno di non aver richiesto un
+comportamento non bloccante) viene posto in stato di sleep. Una volta finite
+le operazioni sul file si deve provvedere a rimuovere il lock. La situazione
+delle varie possibilità è riassunta in \tabref{tab:file_file_lock}, dove si
+sono riportati, per le varie tipologie di lock presenti su un file, il
+risultato che si ha in corrispondenza alle due tipologie di \textit{file lock}
+menzionate, nel successo della richiesta.
+
+Si tenga presente infine che il controllo di accesso e la gestione dei
+permessi viene effettuata quando si apre un file, l'unico controllo residuo
+che si può avere riguardo il \textit{file locking} è che il tipo di lock che
+si vuole ottenere su un file deve essere compatibile con le modalità di
+apertura dello stesso (in lettura per un read lock e in scrittura per un write
+lock).
+
+%%  Si ricordi che
+%% la condizione per acquisire uno \textit{shared lock} è che il file non abbia
+%% già un \textit{exclusive lock} attivo, mentre per acquisire un
+%% \textit{exclusive lock} non deve essere presente nessun tipo di blocco.
+
+
+\subsection{La funzione \func{flock}} 
+\label{sec:file_flock}
+
+La prima interfaccia per il file locking, quella derivata da BSD, permette di
+eseguire un blocco solo su un intero file; la funzione usata per richiedere e
+rimuovere un \textit{file lock} è \funcd{flock}, ed il suo prototipo è:
+\begin{prototype}{sys/file.h}{int flock(int fd, int operation)}
+  
+  Applica o rimuove un \textit{file lock} sul file \param{fd}.
+  
+  \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
+    errore, nel qual caso \var{errno} assumerà uno dei valori:
+    \begin{errlist}
+    \item[\errcode{EWOULDBLOCK}] Il file ha già un blocco attivo, e si è
+      specificato \const{LOCK\_NB}.
+    \end{errlist}
+  }
+\end{prototype}
+
+La funzione può essere usata per acquisire o rilasciare un \textit{file lock}
+a seconda di quanto specificato tramite il valore dell'argomento
+\param{operation}, questo viene interpretato come maschera binaria, e deve
+essere passato utilizzando le costanti riportate in
+\tabref{tab:file_flock_operation}.
 
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|l|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{LOCK\_SH} & Asserisce uno \textit{shared lock} sul file.\\ 
+    \const{LOCK\_EX} & Asserisce un \textit{esclusive lock} sul file.\\
+    \const{LOCK\_UN} & Rilascia il \textit{file lock}.\\
+    \const{LOCK\_NB} & Impedisce che la funzione si blocchi nella
+                       richiesta di un \textit{file lock}.\\
+    \hline    
+  \end{tabular}
+  \caption{Valori dell'argomento \param{operation} di \func{flock}.}
+  \label{tab:file_flock_operation}
+\end{table}
 
+I primi due valori, \const{LOCK\_SH} e \const{LOCK\_EX} permettono di
+richiedere un \textit{file lock}, ed ovviamente devono essere usati in maniera
+alternativa. Se si specifica anche \const{LOCK\_NB} la funzione non si
+bloccherà qualora il lock non possa essere acquisito, ma ritornerà subito con
+un errore di \errcode{EWOULDBLOCK}. Per rilasciare un lock si dovrà invece
+usare \const{LOCK\_UN}.
+
+La semantica del file locking di BSD è diversa da quella del file locking
+POSIX, in particolare per quanto riguarda il comportamento dei lock nei
+confronti delle due funzioni \func{dup} e \func{fork}.  Per capire queste
+differenze occorre descrivere con maggiore dettaglio come viene realizzato il
+file locking nel kernel in entrambe le interfacce.
+
+In \figref{fig:file_flock_struct} si è riportato uno schema essenziale
+dell'implementazione del file locking in stile BSD in Linux; il punto
+fondamentale da capire è che un lock, qualunque sia l'interfaccia che si usa,
+anche se richiesto attraverso un file descriptor, agisce sempre su un file;
+perciò le informazioni relative agli eventuali \textit{file lock} sono
+mantenute a livello di inode\index{inode},\footnote{in particolare, come
+  accennato in \figref{fig:file_flock_struct}, i \textit{file lock} sono
+  mantenuti un una \textit{linked list}\index{linked list} di strutture
+  \struct{file\_lock}. La lista è referenziata dall'indirizzo di partenza
+  mantenuto dal campo \var{i\_flock} della struttura \struct{inode} (per le
+  definizioni esatte si faccia riferimento al file \file{fs.h} nei sorgenti
+  del kernel).  Un bit del campo \var{fl\_flags} di specifica se si tratta di
+  un lock in semantica BSD (\const{FL\_FLOCK}) o POSIX (\const{FL\_POSIX}).}
+dato che questo è l'unico riferimento in comune che possono avere due processi
+diversi che aprono lo stesso file.
+
+\begin{figure}[htb]
+  \centering
+  \includegraphics[width=14cm]{img/file_flock}
+  \caption{Schema dell'architettura del file locking, nel caso particolare  
+    del suo utilizzo da parte dalla funzione \func{flock}.}
+  \label{fig:file_flock_struct}
+\end{figure}
 
+La richiesta di un file lock prevede una scansione della lista per determinare
+se l'acquisizione è possibile, ed in caso positivo l'aggiunta di un nuovo
+elemento.\footnote{cioè una nuova struttura \struct{file\_lock}.}  Nel caso
+dei lock creati con \func{flock} la semantica della funzione prevede che sia
+\func{dup} che \func{fork} non creino ulteriori istanze di un file lock quanto
+piuttosto degli ulteriori riferimenti allo stesso. Questo viene realizzato dal
+kernel secondo lo schema di \figref{fig:file_flock_struct}, associando ad ogni
+nuovo \textit{file lock} un puntatore\footnote{il puntatore è mantenuto nel
+  campo \var{fl\_file} di \struct{file\_lock}, e viene utilizzato solo per i
+  lock creati con la semantica BSD.} alla voce nella \textit{file table} da
+cui si è richiesto il lock, che così ne identifica il titolare.
+
+Questa struttura prevede che, quando si richiede la rimozione di un file lock,
+il kernel acconsenta solo se la richiesta proviene da un file descriptor che
+fa riferimento ad una voce nella file table corrispondente a quella registrata
+nel lock.  Allora se ricordiamo quanto visto in \secref{sec:file_dup} e
+\secref{sec:file_sharing}, e cioè che i file descriptor duplicati e quelli
+ereditati in un processo figlio puntano sempre alla stessa voce nella file
+table, si può capire immediatamente quali sono le conseguenze nei confronti
+delle funzioni \func{dup} e \func{fork}.
+
+Sarà così possibile rimuovere un file lock attraverso uno qualunque dei file
+descriptor che fanno riferimento alla stessa voce nella file table, anche se
+questo è diverso da quello con cui lo si è creato,\footnote{attenzione, questo
+  non vale se il file descriptor fa riferimento allo stesso file, ma
+  attraverso una voce diversa della file table, come accade tutte le volte che
+  si apre più volte lo stesso file.} o se si esegue la rimozione in un
+processo figlio; inoltre una volta tolto un file lock, la rimozione avrà
+effetto su tutti i file descriptor che condividono la stessa voce nella file
+table, e quindi, nel caso di file descriptor ereditati attraverso una
+\func{fork}, anche su processi diversi.
+
+Infine, per evitare che la terminazione imprevista di un processo lasci attivi
+dei file lock, quando un file viene chiuso il kernel provveda anche a
+rimuovere tutti i lock ad esso associati. Anche in questo caso occorre tenere
+presente cosa succede quando si hanno file descriptor duplicati; in tal caso
+infatti il file non verrà effettivamente chiuso (ed il lock rimosso) fintanto
+che non viene rilasciata la relativa voce nella file table; e questo avverrà
+solo quando tutti i file descriptor che fanno riferimento alla stessa voce
+sono stati chiusi.  Quindi, nel caso ci siano duplicati o processi figli che
+mantengono ancora aperto un file descriptor, il lock non viene rilasciato.
+
+Si tenga presente infine che \func{flock} non è in grado di funzionare per i
+file mantenuti su NFS, in questo caso, se si ha la necessità di eseguire il
+\textit{file locking}, occorre usare l'interfaccia basata su \func{fcntl} che
+può funzionare anche attraverso NFS, a condizione che sia il client che il
+server supportino questa funzionalità.
+
+\subsection{Il file locking POSIX}
+\label{sec:file_posix_lock}
+
+La seconda interfaccia per l'\textit{advisory locking} disponibile in Linux è
+quella standardizzata da POSIX, basata sulla funzione \func{fcntl}. Abbiamo
+già trattato questa funzione nelle sue molteplici possibilità di utilizzo in
+\secref{sec:file_fcntl}. Quando la si impiega per il \textit{file locking}
+essa viene usata solo secondo il prototipo:
+\begin{prototype}{fcntl.h}{int fcntl(int fd, int cmd, struct flock *lock)}
+  
+  Applica o rimuove un \textit{file lock} sul file \param{fd}.
+  
+  \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
+    errore, nel qual caso \var{errno} assumerà uno dei valori:
+    \begin{errlist}
+    \item[\errcode{EACCES}] L'operazione è proibita per la presenza di
+      \textit{file lock} da parte di altri processi.
+    \item[\errcode{ENOLCK}] Il sistema non ha le risorse per il locking: ci
+      sono troppi segmenti di lock aperti, si è esaurita la tabella dei lock,
+      o il protocollo per il locking remoto è fallito.
+    \item[\errcode{EDEADLK}] Si è richiesto un lock su una regione bloccata da
+      un altro processo che è a sua volta in attesa dello sblocco di un lock
+      mantenuto dal processo corrente; si avrebbe pertanto un
+      \textit{deadlock}\index{deadlock}. Non è garantito che il sistema
+      riconosca sempre questa situazione.
+    \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale prima
+      di poter acquisire un lock.
+    \end{errlist}
+    ed inoltre \errval{EBADF}, \errval{EFAULT}.
+  }
+\end{prototype}
+
+Al contrario di quanto avviene con l'interfaccia basata su \func{flock} con
+\func{fcntl} è possibile bloccare anche delle singole sezioni di un file, fino
+al singolo byte. Inoltre la funzione permette di ottenere alcune informazioni
+relative agli eventuali lock preesistenti.  Per poter fare tutto questo la
+funzione utilizza come terzo argomento una apposita struttura \struct{flock}
+(la cui definizione è riportata in \figref{fig:struct_flock}) nella quale
+inserire tutti i dati relativi ad un determinato lock. Si tenga presente poi
+che un lock fa sempre riferimento ad una regione, per cui si potrà avere un
+conflitto anche se c'è soltanto una sovrapposizione parziale con un'altra
+regione bloccata.
+
+\begin{figure}[!bht]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includestruct{listati/flock.h}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \structd{flock}, usata da \func{fcntl} per il file
+    locking.} 
+  \label{fig:struct_flock}
+\end{figure}
 
-\subsection{Il \textit{mandatory locking}}
-\label{sec:file_mand_locking}
 
-Il \textit{mandatory locking} è una opzione introdotta inizialmente in SVr4, 
+I primi tre campi della struttura, \var{l\_whence}, \var{l\_start} e
+\var{l\_len}, servono a specificare la sezione del file a cui fa riferimento
+il lock: \var{l\_start} specifica il byte di partenza, \var{l\_len} la
+lunghezza della sezione e infine \var{l\_whence} imposta il riferimento da cui
+contare \var{l\_start}. Il valore di \var{l\_whence} segue la stessa semantica
+dell'omonimo argomento di \func{lseek}, coi tre possibili valori
+\const{SEEK\_SET}, \const{SEEK\_CUR} e \const{SEEK\_END}, (si vedano le
+relative descrizioni in \secref{sec:file_lseek}). 
 
+Si tenga presente che un lock può essere richiesto anche per una regione al di
+là della corrente fine del file, così che una eventuale estensione dello
+stesso resti coperta dal blocco. Inoltre se si specifica un valore nullo per
+\var{l\_len} il blocco si considera esteso fino alla dimensione massima del
+file; in questo modo è possibile bloccare una qualunque regione a partire da
+un certo punto fino alla fine del file, coprendo automaticamente quanto
+eventualmente aggiunto in coda allo stesso.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|l|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{F\_RDLCK} & Richiede un blocco condiviso (\textit{read lock}).\\
+    \const{F\_WRLCK} & Richiede un blocco esclusivo (\textit{write lock}).\\
+    \const{F\_UNLCK} & Richiede l'eliminazione di un file lock.\\
+    \hline    
+  \end{tabular}
+  \caption{Valori possibili per il campo \var{l\_type} di \struct{flock}.}
+  \label{tab:file_flock_type}
+\end{table}
+
+Il tipo di file lock richiesto viene specificato dal campo \var{l\_type}, esso
+può assumere i tre valori definiti dalle costanti riportate in
+\tabref{tab:file_flock_type}, che permettono di richiedere rispettivamente uno
+\textit{shared lock}, un \textit{esclusive lock}, e la rimozione di un lock
+precedentemente acquisito. Infine il campo \var{l\_pid} viene usato solo in
+caso di lettura, quando si chiama \func{fcntl} con \const{F\_GETLK}, e riporta
+il \acr{pid} del processo che detiene il lock.
+
+Oltre a quanto richiesto tramite i campi di \struct{flock}, l'operazione
+effettivamente svolta dalla funzione è stabilita dal valore dall'argomento
+\param{cmd} che, come già riportato in \secref{sec:file_fcntl}, specifica
+l'azione da compiere; i valori relativi al file locking sono tre:
+\begin{basedescript}{\desclabelwidth{2.0cm}}
+\item[\const{F\_GETLK}] verifica se il file lock specificato dalla struttura
+  puntata da \param{lock} può essere acquisito: in caso negativo sovrascrive
+  la struttura \param{flock} con i valori relativi al lock già esistente che
+  ne blocca l'acquisizione, altrimenti si limita a impostarne il campo
+  \var{l\_type} con il valore \const{F\_UNLCK}. 
+\item[\const{F\_SETLK}] se il campo \var{l\_type} della struttura puntata da
+  \param{lock} è \const{F\_RDLCK} o \const{F\_WRLCK} richiede il
+  corrispondente file lock, se è \const{F\_UNLCK} lo rilascia. Nel caso la
+  richiesta non possa essere soddisfatta a causa di un lock preesistente la
+  funzione ritorna immediatamente con un errore di \errcode{EACCES} o di
+  \errcode{EAGAIN}.
+\item[\const{F\_SETLKW}] è identica a \const{F\_SETLK}, ma se la richiesta di
+  non può essere soddisfatta per la presenza di un altro lock, mette il
+  processo in stato di attesa fintanto che il lock precedente non viene
+  rilasciato. Se l'attesa viene interrotta da un segnale la funzione ritorna
+  con un errore di \errcode{EINTR}.
+\end{basedescript}
+
+Si noti che per quanto detto il comando \const{F\_GETLK} non serve a rilevare
+una presenza generica di lock su un file, perché se ne esistono altri
+compatibili con quello richiesto, la funzione ritorna comunque impostando
+\var{l\_type} a \const{F\_UNLCK}.  Inoltre a seconda del valore di
+\var{l\_type} si potrà controllare o l'esistenza di un qualunque tipo di lock
+(se è \const{F\_WRLCK}) o di write lock (se è \const{F\_RDLCK}). Si consideri
+poi che può esserci più di un lock che impedisce l'acquisizione di quello
+richiesto (basta che le regioni si sovrappongano), ma la funzione ne riporterà
+sempre soltanto uno, impostando \var{l\_whence} a \const{SEEK\_SET} ed i
+valori \var{l\_start} e \var{l\_len} per indicare quale è la regione bloccata.
+
+Infine si tenga presente che effettuare un controllo con il comando
+\const{F\_GETLK} e poi tentare l'acquisizione con \const{F\_SETLK} non è una
+operazione atomica (un altro processo potrebbe acquisire un lock fra le due
+chiamate) per cui si deve sempre verificare il codice di ritorno di
+\func{fcntl}\footnote{controllare il codice di ritorno delle funzioni invocate
+  è comunque una buona norma di programmazione, che permette di evitare un
+  sacco di errori difficili da tracciare proprio perché non vengono rilevati.}
+quando la si invoca con \const{F\_SETLK}, per controllare che il lock sia
+stato effettivamente acquisito.
+
+\begin{figure}[htb]
+  \centering \includegraphics[width=9cm]{img/file_lock_dead}
+  \caption{Schema di una situazione di \textit{deadlock}\index{deadlock}.}
+  \label{fig:file_flock_dead}
+\end{figure}
+
+Non operando a livello di interi file, il file locking POSIX introduce
+un'ulteriore complicazione; consideriamo la situazione illustrata in
+\figref{fig:file_flock_dead}, in cui il processo A blocca la regione 1 e il
+processo B la regione 2. Supponiamo che successivamente il processo A richieda
+un lock sulla regione 2 che non può essere acquisito per il preesistente lock
+del processo 2; il processo 1 si bloccherà fintanto che il processo 2 non
+rilasci il blocco. Ma cosa accade se il processo 2 nel frattempo tenta a sua
+volta di ottenere un lock sulla regione A? Questa è una tipica situazione che
+porta ad un \textit{deadlock}\index{deadlock}, dato che a quel punto anche il
+processo 2 si bloccherebbe, e niente potrebbe sbloccare l'altro processo. Per
+questo motivo il kernel si incarica di rilevare situazioni di questo tipo, ed
+impedirle restituendo un errore di \errcode{EDEADLK} alla funzione che cerca
+di acquisire un lock che porterebbe ad un \textit{deadlock}.
+
+\begin{figure}[!bht]
+  \centering \includegraphics[width=13cm]{img/file_posix_lock}
+  \caption{Schema dell'architettura del file locking, nel caso particolare  
+    del suo utilizzo secondo l'interfaccia standard POSIX.}
+  \label{fig:file_posix_lock}
+\end{figure}
+
+
+Per capire meglio il funzionamento del file locking in semantica POSIX (che
+differisce alquanto rispetto da quello di BSD, visto \secref{sec:file_flock})
+esaminiamo più in dettaglio come viene gestito dal kernel. Lo schema delle
+strutture utilizzate è riportato in \figref{fig:file_posix_lock}; come si vede
+esso è molto simile all'analogo di \figref{fig:file_flock_struct}:\footnote{in
+  questo caso nella figura si sono evidenziati solo i campi di
+  \struct{file\_lock} significativi per la semantica POSIX, in particolare
+  adesso ciascuna struttura contiene, oltre al \acr{pid} del processo in
+  \var{fl\_pid}, la sezione di file che viene bloccata grazie ai campi
+  \var{fl\_start} e \var{fl\_end}.  La struttura è comunque la stessa, solo
+  che in questo caso nel campo \var{fl\_flags} è impostato il bit
+  \const{FL\_POSIX} ed il campo \var{fl\_file} non viene usato.} il lock è
+sempre associato all'inode\index{inode}, solo che in questo caso la titolarità
+non viene identificata con il riferimento ad una voce nella file table, ma con
+il valore del \acr{pid} del processo.
+
+Quando si richiede un lock il kernel effettua una scansione di tutti i lock
+presenti sul file\footnote{scandisce cioè la linked list delle strutture
+  \struct{file\_lock}, scartando automaticamente quelle per cui
+  \var{fl\_flags} non è \const{FL\_POSIX}, così che le due interfacce restano
+  ben separate.}  per verificare se la regione richiesta non si sovrappone ad
+una già bloccata, in caso affermativo decide in base al tipo di lock, in caso
+negativo il nuovo lock viene comunque acquisito ed aggiunto alla lista.
+
+Nel caso di rimozione invece questa viene effettuata controllando che il
+\acr{pid} del processo richiedente corrisponda a quello contenuto nel lock.
+Questa diversa modalità ha delle conseguenze precise riguardo il comportamento
+dei lock POSIX. La prima conseguenza è che un lock POSIX non viene mai
+ereditato attraverso una \func{fork}, dato che il processo figlio avrà un
+\acr{pid} diverso, mentre passa indenne attraverso una \func{exec} in quanto
+il \acr{pid} resta lo stesso.  Questo comporta che, al contrario di quanto
+avveniva con la semantica BSD, quando processo termina tutti i file lock da
+esso detenuti vengono immediatamente rilasciati.
+
+La seconda conseguenza è che qualunque file descriptor che faccia riferimento
+allo stesso file (che sia stato ottenuto con una \func{dup} o con una
+\func{open} in questo caso non fa differenza) può essere usato per rimuovere
+un lock, dato che quello che conta è solo il \acr{pid} del processo. Da questo
+deriva una ulteriore sottile differenza di comportamento: dato che alla
+chiusura di un file i lock ad esso associati vengono rimossi, nella semantica
+POSIX basterà chiudere un file descriptor qualunque per cancellare tutti i
+lock relativi al file cui esso faceva riferimento, anche se questi fossero
+stati creati usando altri file descriptor che restano aperti.
+
+Dato che il controllo sull'accesso ai lock viene eseguito sulla base del
+\acr{pid} del processo, possiamo anche prendere in considerazione un'altro
+degli aspetti meno chiari di questa interfaccia e cioè cosa succede quando si
+richiedono dei lock su regioni che si sovrappongono fra loro all'interno
+stesso processo. Siccome il controllo, come nel caso della rimozione, si basa
+solo sul \acr{pid} del processo che chiama la funzione, queste richieste
+avranno sempre successo.
+
+Nel caso della semantica BSD, essendo i lock relativi a tutto un file e non
+accumulandosi,\footnote{questa ultima caratteristica è vera in generale, se
+  cioè si richiede più volte lo stesso file lock, o più lock sulla stessa
+  sezione di file, le richieste non si cumulano e basta una sola richiesta di
+  rilascio per cancellare il lock.}  la cosa non ha alcun effetto; la funzione
+ritorna con successo, senza che il kernel debba modificare la lista dei lock.
+In questo caso invece si possono avere una serie di situazioni diverse: ad
+esempio è possibile rimuovere con una sola chiamata più lock distinti
+(indicando in una regione che si sovrapponga completamente a quelle di questi
+ultimi), o rimuovere solo una parte di un lock preesistente (indicando una
+regione contenuta in quella di un altro lock), creando un buco, o coprire con
+un nuovo lock altri lock già ottenuti, e così via, a secondo di come si
+sovrappongono le regioni richieste e del tipo di operazione richiesta.  Il
+comportamento seguito in questo caso che la funzione ha successo ed esegue
+l'operazione richiesta sulla regione indicata; è compito del kernel
+preoccuparsi di accorpare o dividere le voci nella lista dei lock per far si
+che le regioni bloccate da essa risultanti siano coerenti con quanto
+necessario a soddisfare l'operazione richiesta.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/Flock.c}
+  \end{minipage} 
+  \normalsize 
+  \caption{Sezione principale del codice del programma \file{Flock.c}.}
+  \label{fig:file_flock_code}
+\end{figure}
+
+Per fare qualche esempio sul file locking si è scritto un programma che
+permette di bloccare una sezione di un file usando la semantica POSIX, o un
+intero file usando la semantica BSD; in \figref{fig:file_flock_code} è
+riportata il corpo principale del codice del programma, (il testo completo è
+allegato nella directory dei sorgenti).
+
+La sezione relativa alla gestione delle opzioni al solito si è omessa, come la
+funzione che stampa le istruzioni per l'uso del programma, essa si cura di
+impostare le variabili \var{type}, \var{start} e \var{len}; queste ultime due
+vengono inizializzate al valore numerico fornito rispettivamente tramite gli
+switch \code{-s} e \cmd{-l}, mentre il valore della prima viene impostato con
+le opzioni \cmd{-w} e \cmd{-r} si richiede rispettivamente o un write lock o
+read lock (i due valori sono esclusivi, la variabile assumerà quello che si è
+specificato per ultimo). Oltre a queste tre vengono pure impostate la
+variabile \var{bsd}, che abilita la semantica omonima quando si invoca
+l'opzione \cmd{-f} (il valore preimpostato è nullo, ad indicare la semantica
+POSIX), e la variabile \var{cmd} che specifica la modalità di richiesta del
+lock (bloccante o meno), a seconda dell'opzione \cmd{-b}.
+
+Il programma inizia col controllare (\texttt{\small 11--14}) che venga passato
+un parametro (il file da bloccare), che sia stato scelto (\texttt{\small
+  15--18}) il tipo di lock, dopo di che apre (\texttt{\small 19}) il file,
+uscendo (\texttt{\small 20--23}) in caso di errore. A questo punto il
+comportamento dipende dalla semantica scelta; nel caso sia BSD occorre
+reimpostare il valore di \var{cmd} per l'uso con \func{flock}; infatti il
+valore preimpostato fa riferimento alla semantica POSIX e vale rispettivamente
+\const{F\_SETLKW} o \const{F\_SETLK} a seconda che si sia impostato o meno la
+modalità bloccante.
+
+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 lock al valore viene
+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}).
+
+In entrambi i casi dopo aver richiesto il lock viene controllato il risultato
+uscendo (\texttt{\small 44--46}) in caso di errore, o stampando un messaggio
+(\texttt{\small 47--49}) in caso di successo. Infine il programma si pone in
+attesa (\texttt{\small 50}) finché un segnale (ad esempio un \cmd{C-c} dato da
+tastiera) non lo interrompa; in questo caso il programma termina, e tutti i
+lock vengono rilasciati.
+
+Con il programma possiamo fare varie verifiche sul funzionamento del file
+locking; cominciamo con l'eseguire un read lock su un file, ad esempio usando
+all'interno di un terminale il seguente comando:
+
+\vspace{1mm}
+\begin{minipage}[c]{12cm}
+\begin{verbatim}
+[piccardi@gont sources]$ ./flock -r Flock.c
+Lock acquired
+\end{verbatim}%$
+\end{minipage}\vspace{1mm}
+\par\noindent
+il programma segnalerà di aver acquisito un lock e si bloccherà; in questo
+caso si è usato il file locking POSIX e non avendo specificato niente riguardo
+alla sezione che si vuole bloccare sono stati usati i valori preimpostati che
+bloccano tutto il file. A questo punto se proviamo ad eseguire lo stesso
+comando in un altro terminale, e avremo lo stesso risultato. Se invece
+proviamo ad eseguire un write lock avremo:
+
+\vspace{1mm}
+\begin{minipage}[c]{12cm}
+\begin{verbatim}
+[piccardi@gont sources]$ ./flock -w Flock.c
+Failed lock: Resource temporarily unavailable
+\end{verbatim}%$
+\end{minipage}\vspace{1mm}
+\par\noindent
+come ci aspettiamo il programma terminerà segnalando l'indisponibilità del
+lock, dato che il file è bloccato dal precedente read lock. Si noti che il
+risultato è lo stesso anche se si richiede il blocco su una sola parte del
+file con il comando:
+
+\vspace{1mm}
+\begin{minipage}[c]{12cm}
+\begin{verbatim}
+[piccardi@gont sources]$ ./flock -w -s0 -l10 Flock.c
+Failed lock: Resource temporarily unavailable
+\end{verbatim}%$
+\end{minipage}\vspace{1mm}
+\par\noindent
+se invece blocchiamo una regione con: 
+
+\vspace{1mm}
+\begin{minipage}[c]{12cm}
+\begin{verbatim}
+[piccardi@gont sources]$ ./flock -r -s0 -l10 Flock.c
+Lock acquired
+\end{verbatim}%$
+\end{minipage}\vspace{1mm}
+\par\noindent
+una volta che riproviamo ad acquisire il write lock i risultati dipenderanno
+dalla regione richiesta; ad esempio nel caso in cui le due regioni si
+sovrappongono avremo che:
+
+\vspace{1mm}
+\begin{minipage}[c]{12cm}
+\begin{verbatim}
+[piccardi@gont sources]$ ./flock -w -s5 -l15  Flock.c
+Failed lock: Resource temporarily unavailable
+\end{verbatim}%$
+\end{minipage}\vspace{1mm}
+\par\noindent
+ed il lock viene rifiutato, ma se invece si richiede una regione distinta
+avremo che:
+
+\vspace{1mm}
+\begin{minipage}[c]{12cm}
+\begin{verbatim}
+[piccardi@gont sources]$ ./flock -w -s11 -l15  Flock.c
+Lock acquired
+\end{verbatim}%$
+\end{minipage}\vspace{1mm}
+\par\noindent
+ed il lock viene acquisito. Se a questo punto si prova ad eseguire un read
+lock che comprende la nuova regione bloccata in scrittura:
+
+\vspace{1mm}
+\begin{minipage}[c]{12cm}
+\begin{verbatim}
+[piccardi@gont sources]$ ./flock -r -s10 -l20 Flock.c
+Failed lock: Resource temporarily unavailable
+\end{verbatim}%$
+\end{minipage}\vspace{1mm}
+\par\noindent
+come ci aspettiamo questo non sarà consentito.
+
+Il programma di norma esegue il tentativo di acquisire il lock in modalità non
+bloccante, se però usiamo l'opzione \cmd{-b} possiamo impostare la modalità
+bloccante, riproviamo allora a ripetere le prove precedenti con questa
+opzione:
+
+\vspace{1mm}
+\begin{minipage}[c]{12cm}
+\begin{verbatim}
+[piccardi@gont sources]$ ./flock -r -b -s0 -l10 Flock.c Lock acquired
+\end{verbatim}%$
+\end{minipage}\vspace{1mm}
+\par\noindent
+il primo comando acquisisce subito un read lock, e quindi non cambia nulla, ma
+se proviamo adesso a richiedere un write lock che non potrà essere acquisito
+otterremo:
+
+\vspace{1mm}
+\begin{minipage}[c]{12cm}
+\begin{verbatim}
+[piccardi@gont sources]$ ./flock -w -s0 -l10 Flock.c
+\end{verbatim}%$
+\end{minipage}\vspace{1mm}
+\par\noindent
+il programma cioè si bloccherà nella chiamata a \func{fcntl}; se a questo
+punto rilasciamo il precedente lock (terminando il primo comando un
+\texttt{C-c} sul terminale) potremo verificare che sull'altro terminale il
+lock viene acquisito, con la comparsa di una nuova riga:
+
+\vspace{1mm}
+\begin{minipage}[c]{12cm}
+\begin{verbatim}
+[piccardi@gont sources]$ ./flock -w -s0 -l10 Flock.c
+Lock acquired
+\end{verbatim}%$
+\end{minipage}\vspace{3mm}
+\par\noindent
+
+Un'altra cosa che si può controllare con il nostro programma è l'interazione
+fra i due tipi di lock; se ripartiamo dal primo comando con cui si è ottenuto
+un lock in lettura sull'intero file, possiamo verificare cosa succede quando
+si cerca di ottenere un lock in scrittura con la semantica BSD:
+
+\vspace{1mm}
+\begin{minipage}[c]{12cm}
+\begin{verbatim}
+[root@gont sources]# ./flock -f -w Flock.c
+Lock acquired
+\end{verbatim}
+\end{minipage}\vspace{1mm}
+\par\noindent
+che ci mostra come i due tipi di lock 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 lock
+applicati con l'altra non avrebbero nessun effetto.
+
+
+
+\subsection{La funzione \func{lockf}}
+\label{sec:file_lockf}
+
+Abbiamo visto come l'interfaccia POSIX per il file locking sia molto più
+potente e flessibile di quella di BSD, questo comporta anche una maggiore
+complessità per via delle varie opzioni da passare a \func{fcntl}. Per questo
+motivo è disponibile anche una interfaccia semplificata (ripresa da System V)
+che utilizza la funzione \funcd{lockf}, il cui prototipo è:
+\begin{prototype}{sys/file.h}{int lockf(int fd, int cmd, off\_t len)}
+  
+  Applica, controlla o rimuove un \textit{file lock} sul file \param{fd}.
+  
+  \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
+    errore, nel qual caso \var{errno} assumerà uno dei valori:
+    \begin{errlist}
+    \item[\errcode{EWOULDBLOCK}] Non è possibile acquisire il lock, e si è
+      selezionato \const{LOCK\_NB}, oppure l'operazione è proibita perché il
+      file è mappato in memoria.
+    \item[\errcode{ENOLCK}] Il sistema non ha le risorse per il locking: ci
+      sono troppi segmenti di lock aperti, si è esaurita la tabella dei lock.
+    \end{errlist}
+    ed inoltre \errval{EBADF}, \errval{EINVAL}.
+  }
+\end{prototype}
+
+Il comportamento della funzione dipende dal valore dell'argomento \param{cmd},
+che specifica quale azione eseguire; i valori possibili sono riportati in
+\tabref{tab:file_lockf_type}.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{7cm}|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{LOCK\_SH}& Richiede uno \textit{shared lock}. Più processi possono
+                      mantenere un lock condiviso sullo stesso file.\\
+    \const{LOCK\_EX}& Richiede un \textit{exclusive lock}. Un solo processo
+                      alla volta può mantenere un lock esclusivo su un file. \\
+    \const{LOCK\_UN}& Sblocca il file.\\
+    \const{LOCK\_NB}& Non blocca la funzione quando il lock non è disponibile,
+                      si specifica sempre insieme ad una delle altre operazioni
+                      con un OR aritmetico dei valori.\\ 
+    \hline    
+  \end{tabular}
+  \caption{Valori possibili per l'argomento \param{cmd} di \func{lockf}.}
+  \label{tab:file_lockf_type}
+\end{table}
+
+Qualora il lock non possa essere acquisito, a meno di non aver specificato
+\const{LOCK\_NB}, la funzione si blocca fino alla disponibilità dello stesso.
+Dato che la funzione è implementata utilizzando \func{fcntl} la semantica
+delle operazioni è la stessa di quest'ultima (pertanto la funzione non è
+affatto equivalente a \func{flock}).
+
+
+
+\subsection{Il \textit{mandatory locking}}
+\label{sec:file_mand_locking}
 
+Il \textit{mandatory locking} è una opzione introdotta inizialmente in SVr4,
+per introdurre un file locking che, come dice il nome, fosse effettivo
+indipendentemente dai controlli eseguiti da un processo. Con il
+\textit{mandatory locking} infatti è possibile far eseguire il blocco del file
+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 \acr{sgid}. Se si ricorda quanto esposto in
+\secref{sec:file_suid_sgid}), esso viene di norma utilizzato per cambiare il
+group-ID 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
+  \secref{sec:file_chmod} 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 root può passare sopra ad un lock; pertanto un processo che blocchi un
+file cruciale può renderlo completamente inaccessibile, rendendo completamente
+inutilizzabile il sistema\footnote{il problema si potrebbe risolvere
+  rimuovendo il bit \acr{sgid}, ma non è detto che sia così facile fare questa
+  operazione con un sistema bloccato.} inoltre con il \textit{mandatory
+  locking} si può bloccare completamente un server NFS richiedendo una lettura
+su un file su cui è attivo un lock. Per questo motivo l'abilitazione del
+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 \tabref{tab:sys_mount_flags}, o con l'opzione
+\cmd{mand} per il comando).
+
+Si tenga presente inoltre che il \textit{mandatory locking} funziona solo
+sull'interfaccia POSIX di \func{fcntl}. Questo ha due conseguenze: che non si
+ha nessun effetto sui lock richiesti con l'interfaccia di \func{flock}, e che
+la granularità del lock è quella del singolo byte, come per \func{fcntl}.
+
+La sintassi di acquisizione dei lock è esattamente la stessa vista in
+precedenza per \func{fcntl} e \func{lockf}, la differenza è che in caso di
+mandatory lock attivato non è più necessario controllare la disponibilità di
+accesso al file, ma si potranno usare direttamente le ordinarie funzioni di
+lettura e scrittura e sarà compito del kernel gestire direttamente il file
+locking.
+
+Questo significa che in caso di read lock la lettura dal file potrà avvenire
+normalmente con \func{read}, mentre una \func{write} si bloccherà fino al
+rilascio del lock, a meno di non aver aperto il file con \const{O\_NONBLOCK},
+nel qual caso essa ritornerà immediatamente con un errore di \errcode{EAGAIN}.
+
+Se invece si è acquisito un write lock tutti i tentativi di leggere o scrivere
+sulla regione del file bloccata fermeranno il processo fino al rilascio del
+lock, a meno che il file non sia stato aperto con \const{O\_NONBLOCK}, nel
+qual caso di nuovo si otterrà un ritorno immediato con l'errore di
+\errcode{EAGAIN}.
+
+Infine occorre ricordare che le funzioni di lettura e scrittura non sono le
+sole ad operare sui contenuti di un file, e che sia \func{creat} che
+\func{open} (quando chiamata con \const{O\_TRUNC}) effettuano dei cambiamenti,
+così come \func{truncate}, riducendone le dimensioni (a zero nei primi due
+casi, a quanto specificato nel secondo). Queste operazioni sono assimilate a
+degli accessi in scrittura e pertanto non potranno essere eseguite (fallendo
+con un errore di \errcode{EAGAIN}) su un file su cui sia presente un qualunque
+lock (le prime due sempre, la terza solo nel caso che la riduzione delle
+dimensioni del file vada a sovrapporsi ad una regione bloccata).
+
+L'ultimo aspetto della interazione del \textit{mandatory locking} con le
+funzioni di accesso ai file è quello relativo ai file mappati in memoria (che
+abbiamo trattato in \secref{sec:file_memory_map}); anche in tal caso infatti,
+quando si esegue la mappatura con l'opzione \const{MAP\_SHARED}, si ha un
+accesso al contenuto del file. Lo standard SVID prevede che sia impossibile
+eseguire il memory mapping di un file su cui sono presenti dei
+lock\footnote{alcuni sistemi, come HP-UX, sono ancora più restrittivi e lo
+  impediscono anche in caso di \textit{advisory locking}, anche se questo
+  comportamento non ha molto senso, dato che comunque qualunque accesso
+  diretto al file è consentito.} in Linux è stata però fatta la scelta
+implementativa\footnote{per i dettagli si possono leggere le note relative
+  all'implementazione, mantenute insieme ai sorgenti del kernel nel file
+  \file{Documentation/mandatory.txt}.}  di seguire questo comportamento
+soltanto quando si chiama \func{mmap} con l'opzione \const{MAP\_SHARED} (nel
+qual caso la funzione fallisce con il solito \errcode{EAGAIN}) che comporta la
+possibilità di modificare il file.
+\index{file!locking|)}