Aggiunte spiegazioni sull'esempio, e riscritto lo stesso per usare anche la
[gapil.git] / fileadv.tex
index 8b7246259fcc4b3176c252dde95c0206bab25d83..43451b723e6ebceac561ef2cd0ac7c9a85e91a6e 100644 (file)
@@ -1236,30 +1236,35 @@ sovrapposizioni, e garantire la atomicit
 \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
+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 anche da Stevens per riferirsi al
-  \textit{file locking} di POSIX. Dato che la dizione \textit{record locking}
-  è quantomeno ambigua in quanto 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} non risentono affatto della presenza di un
-eventuale blocco, e che sta ai vari processi controllare esplicitamente lo
-stato dei file condivisi prima di accedervi, implementando un opportuno
-protocollo.
-
-In generale si distinguono due tipologie di blocco per un file: 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é non venga
-modificato mentre lo si legge. Si parla 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.
+  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} non risentono affatto della
+presenza di un eventuale \textit{lock}, e che sta ai vari processi controllare
+esplicitamente lo stato dei file condivisi prima di accedervi, implementando
+un opportuno protocollo.
+
+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 confuzioni 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é 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
@@ -1268,7 +1273,6 @@ scrivendo. Si parla di \textsl{blocco esclusivo} appunto perch
 processo alla volta può richiedere un \textit{exclusive lock} su un file per
 proteggere il suo accesso in scrittura. 
 
-
 \begin{table}[htb]
   \centering
   \footnotesize
@@ -1287,8 +1291,6 @@ proteggere il suo accesso in scrittura.
   \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
@@ -1330,10 +1332,11 @@ rimuovere un \textit{file lock} 
   }
 \end{prototype}
 
-La funzione può essere usata per acquisire o rilasciare un blocco 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}.
+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
@@ -1345,7 +1348,7 @@ costanti riportate in \tabref{tab:file_flock_operation}.
     \hline
     \macro{LOCK\_SH} & Asserisce uno \textit{shared lock} sul file.\\ 
     \macro{LOCK\_EX} & Asserisce un \textit{esclusive lock} sul file.\\
-    \macro{LOCK\_UN} & Sblocca il file.\\
+    \macro{LOCK\_UN} & Rilascia il \textit{file lock}.\\
     \macro{LOCK\_NB} & Impedisce che la funzione si blocchi nella
                        richiesta di un \textit{file lock}.\\
     \hline    
@@ -1395,18 +1398,18 @@ 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 \var{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 \textit{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 \var{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 blocco, che così ne identifica il titolare.
+\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 \var{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 blocco.  Allora se ricordiamo quanto visto in \secref{sec:file_dup} e
+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
@@ -1473,12 +1476,15 @@ essa viene usata solo secondo il prototipo:
 \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;
-inoltre la funzione permette di leggere le informazioni relative ai blocchi
-esistenti.  Per questo la funzione utilizza come terzo argomento una apposita
-struttura \var{flock} (la cui definizione è riportata in
-\figref{fig:struct_flock}) che contiene tutte le specifiche di un dato file
-lock.
+\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 \var{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
@@ -1507,7 +1513,7 @@ 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
 \macro{SEEK\_SET}, \macro{SEEK\_CUR} e \macro{SEEK\_END}, (si vedano le
-relative descrizioni in \secref{sec:file_lseek}).
+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
@@ -1525,7 +1531,6 @@ precedentemente acquisito. Infine il campo \var{l\_pid} viene usato solo in
 caso di lettura, quando si chiama \func{fcntl} con \macro{F\_GETLK}, e riporta
 il \acr{pid} del processo che detiene il lock.
 
-
 \begin{table}[htb]
   \centering
   \footnotesize
@@ -1536,16 +1541,17 @@ il \acr{pid} del processo che detiene il lock.
     \hline
     \macro{F\_RDLCK} & Richiede un blocco condiviso (\textit{read lock}).\\
     \macro{F\_WRLCK} & Richiede un blocco esclusivo (\textit{write lock}).\\
-    \macro{F\_UNLCK} & Richiede l'eliminazione di un lock.\\
+    \macro{F\_UNLCK} & Richiede l'eliminazione di un file lock.\\
     \hline    
   \end{tabular}
   \caption{Valori possibili per il campo \var{l\_type} di \func{flock}.}
   \label{tab:file_flock_type}
 \end{table}
 
-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:
+Oltre a quanto richiesto tramite i campi di \var{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[\macro{F\_GETLK}] verifica se il file lock specificato dalla struttura
   puntata da \param{lock} può essere acquisito: in caso negativo sovrascrive
@@ -1559,22 +1565,22 @@ specifica l'azione da compiere; i valori relativi al file locking sono tre:
   funzione ritorna immediatamente con un errore di \macro{EACCES} o di
   \macro{EAGAIN}.
 \item[\macro{F\_SETLKW}] è identica a \macro{F\_SETLK}, ma se la richiesta di
-  un lock non può essere soddisfatta per la presenza di un altro blocco, mette
-  il processo in stato di attesa fintanto che il lock precedente non viene
+  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 \macro{EINTR}.
 \end{basedescript}
 
-Si noti che il comando \macro{F\_GETLK} non serve a rilevare una presenza
-generica di lock su un file, perché se ne esistono di compatibili con quello
-richiesto, la funzione ritorna comunque impostando \var{l\_type} a
-\macro{F\_UNLCK}. Inoltre a seconda del valore di \var{l\_type} si potrà
-controllare l'esistenza di un qualunque tipo di lock (con \macro{F\_WRLCK}) o
-dei soli lock esclusivi (con \macro{F\_RDLCK}). Si consideri poi che può
-esserci più di un lock che impedisce l'acquisizione di quello richiesto, ma la
-funzione ne riporterà sempre soltanto uno, impostando opportunamente
-\var{l\_whence} a \macro{SEEK\_SET} ed i valori \var{l\_start} e \var{l\_len}
-per indicare quale è la regione effettivamente bloccata.
+Si noti che per quanto detto il comando \macro{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 \macro{F\_UNLCK}.  Inoltre a seconda del valore di
+\var{l\_type} si potrà controllare o l'esistenza di un qualunque tipo di lock
+(se è \macro{F\_WRLCK}) o di write lock (se è \macro{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 \macro{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
 \macro{F\_GETLK} e poi tentare l'acquisizione con \macro{F\_SETLK} non è una
@@ -1583,17 +1589,28 @@ 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 \macro{F\_SETLK} per controllare che il lock sia stato
-effettivamente acquisito.
-
-Un'ultima considerazione riguardo il funzionamento del file locking POSIX
-riguarda la loro caratteristica di operare su delle sezioni di file: è
-possibile con una sola chiamata rimuovere più lock separati (indicando in
-\var{flock} una regione che li copra tutti), o rimuovere solo una parte di un
-lock preesistente (indicando una sezione contenuta in un altro lock), o di
-coprire con un nuovo lock altri lock già ottenuti. In tutti questi casi il
-kernel si preoccupa di accorpare o suddividere le regioni bloccate,
-aggiornando opportunamente le strutture interne usate per il file locking.
+quando la si invoca con \macro{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}.}
+  \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 \macro{EDEADLK} alla funzione che cerca di
+acquisire un lock che porterebbe ad un \textit{deadlock}.
 
 \begin{figure}[htb]
   \centering \includegraphics[width=13cm]{img/file_posix_lock}
@@ -1602,30 +1619,40 @@ aggiornando opportunamente le strutture interne usate per il file locking.
   \label{fig:file_posix_lock}
 \end{figure}
 
-Come accennato nella semantica POSIX si ha un comportamento del file locking
-diverso rispetto a quanto visto in \secref{sec:file_flock}.  Lo schema della
-struttura usata dal kernel in questo caso è riportato in
-\figref{fig:file_posix_lock}; come si vede essa è molto simile a quanto visto
-in \figref{fig:file_flock_struct} per \func{flock}:\footnote{in questo caso
-  nella figura si sono evidenziati solo i campi di \var{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 \macro{FL\_POSIX} ed il campo
-  \var{fl\_file} non viene usato.} il lock è sempre associato all'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.
-
-Tutto ciò significa che la rimozione di un lock 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.
+
+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
+  \var{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
+  \macro{FL\_POSIX} ed il campo \var{fl\_file} non viene usato.} il lock è
+sempre associato all'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
+  \var{file\_lock}, scartando automaticamente quelle per cui \var{fl\_flags}
+  non è \macro{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
@@ -1637,6 +1664,143 @@ POSIX baster
 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 cosiderazione 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 sula 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}
+    \begin{lstlisting}{}
+int main(int argc, char *argv[])
+{
+    int type = F_UNLCK;            /* lock type: default to unlock (invalid) */
+    off_t start = 0;             /* start of the locked region: default to 0 */
+    off_t len = 0;              /* length of the locked region: default to 0 */
+    int fd, res, i;                                    /* internal variables */
+    int bsd = 0;                          /* semantic type: default to POSIX */
+    int cmd = F_SETLK;              /* lock command: default to non-blocking */
+    struct flock lock;                                /* file lock structure */
+    ...
+    if ((argc - optind) != 1) {          /* There must be remaing parameters */
+        printf("Wrong number of arguments %d\n", argc - optind);
+        usage();
+    }
+    if (type == F_UNLCK) {            /* There must be a -w or -r option set */
+        printf("You should set a read or a write lock\n");
+        usage();
+    }
+    fd = open(argv[optind], O_RDWR);           /* open the file to be locked */
+    if (fd < 0) {                                           /* on error exit */
+        perror("Wrong filename");
+        exit(1);
+    }
+    /* do lock */
+    if (bsd) {                                             /* if BSD locking */
+        /* rewrite cmd for suitables flock operation values */ 
+        if (cmd == F_SETLKW) {                             /* if no-blocking */
+            cmd = LOCK_NB;              /* set the value for flock operation */
+        } else {                                                     /* else */
+            cmd = 0;                                      /* default is null */
+        }
+        if (type == F_RDLCK) cmd |= LOCK_SH;          /* set for shared lock */
+        if (type == F_WRLCK) cmd |= LOCK_EX;       /* set for exclusive lock */
+        res = flock(fd, cmd);                                /* esecute lock */
+    } else {                                             /* if POSIX locking */
+        /* setting flock structure */
+        lock.l_type = type;                       /* set type: read or write */
+        lock.l_whence = SEEK_SET;    /* start from the beginning of the file */
+        lock.l_start = start;          /* set the start of the locked region */
+        lock.l_len = len;             /* set the length of the locked region */
+        res = fcntl(fd, cmd, &lock);                              /* do lock */
+    }
+    /* check lock results */
+    if (res) {                                              /* on error exit */
+        perror("Failed lock");
+        exit(1);
+    } else {                                           /* else write message */
+        printf("Lock acquired\n");
+    }
+    pause();                       /* stop the process, use a signal to exit */
+    return 0;
+}
+    \end{lstlisting}
+  \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
+\macro{F\_SETLKW} o \macro{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.
+
 
 \subsection{La funzione \func{lockf}}
 \label{sec:file_lockf}
@@ -1663,7 +1827,7 @@ utilizza la funzione \func{lockf}, il cui prototipo 
   }
 \end{prototype}
 
-Il comportamento della funzione dipende dal valore dell'argomento \param{cmd}
+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}.