\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 ottenere informazioni relative ai lock
-esistenti. Per realizzare 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.
+\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
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
\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
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}
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
-(con \macro{F\_WRLCK}) o di write lock (con \macro{F\_RDLCK}). Si consideri
+(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, 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.
+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
quando la si invoca con \macro{F\_SETLK}, per controllare che il lock sia
stato effettivamente acquisito.
-Occorre infine considerare come interagiscono operazioni su lock che si
-estendono su regioni che si sovrappongono fra loro (ovviamente si fa
-riferimento ai lock detenuti dallo stesso processo); ad esempio è 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), 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, a seconda di quanto
-necessario per soddisfare l'operazione richiesta, aggiornando opportunamente
-le strutture interne usate per il file locking.
-
\begin{figure}[htb]
\centering \includegraphics[width=9cm]{img/file_lock_dead}
\caption{Schema di una situazione di \textit{deadlock}.}
\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\footnoote{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
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.
+
+Come esempio dell'uso di questa funzione si è scritto un programma che
+permette di bloccare una sezione a piacere di un qualunque file; in
+\figref{fig:file_flock_code} è riportata la sezione principale del codice del
+programma, (il testo completo è allegato nella directory dei sorgenti).
+
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+int main(int argc, char *argv[])
+{
+/*
+ * Variables definition
+ */
+ int type = F_UNLCK;
+ off_t start;
+ off_t len;
+ int fd, res, i;
+ int cmd = F_SETLK ;
+ struct flock lock;
+ ...
+ if ((argc - optind) != 1) { /* There must be remaing parameters */
+ printf("Wrong number of arguments %d\n", argc - optind);
+ usage();
+ }
+ if (type == F_UNLCK) { /* Just lock */
+ printf("You should set a read or a write lock\n");
+ usage();
+ }
+ fd = open(argv[optind], O_RDWR);
+ if (fd < 0) {
+ perror("Wrong filename");
+ exit(1);
+ }
+ /* setting lock structure */
+ lock.l_type = type;
+ lock.l_whence = SEEK_SET;
+ lock.l_start = start;
+ lock.l_len = len;
+ /* do lock */
+ res = fcntl(fd, cmd, &lock);
+ if (res) {
+ perror("Failed lock");
+ exit(1);
+ }
+ pause();
+ return 0;
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Sezione principale del codice del programma \file{Flock.c}.}
+ \label{fig:file_flock_code}
+\end{figure}
+
+La parte più complessa del programma è in realtà la logica della gestione
+delle opzioni (che qui si è omessa), che 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 con \cmd{-w} e \cmd{-r} si richiede rispettivamente un write
+lock o read lock.
+
\subsection{La funzione \func{lockf}}
\label{sec:file_lockf}
}
\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}.