-Il tipo di file lock richiesto viene specificato dal campo \var{l\_type}, esso
-può assumere i tre valori definiti dalle costanti riportate in
-tab.~\ref{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 sez.~\ref{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 \itindex{deadlock} \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
-fig.~\ref{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 \itindex{deadlock} \textit{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 \itindex{deadlock}
-\textit{deadlock}.
-
-
-Per capire meglio il funzionamento del file locking in semantica POSIX (che
-differisce alquanto rispetto da quello di BSD, visto
-sez.~\ref{sec:file_flock}) esaminiamo più in dettaglio come viene gestito dal
-kernel. Lo schema delle strutture utilizzate è riportato in
-fig.~\ref{fig:file_posix_lock}; come si vede esso è molto simile all'analogo
-di fig.~\ref{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 \index{inode} all'inode, solo che in
-questo caso la titolarità non viene identificata con il riferimento ad una
-voce nella \itindex{file~table} \textit{file table}, ma con il valore del
-\acr{pid} del processo.
-
-\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}
-
-Quando si richiede un lock il kernel effettua una scansione di tutti i lock
-presenti sul file\footnote{scandisce cioè la \itindex{linked~list}
- \textit{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 fig.~\ref{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 argomento (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: