Inserito programma di esempio
[gapil.git] / fileadv.tex
index e8948b9dd2b83b0607930fc5312940cd02c1773d..c43243c20963c286aba552b696658891a3be2935 100644 (file)
@@ -1476,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 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
@@ -1510,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
@@ -1545,9 +1548,10 @@ il \acr{pid} del processo che detiene il lock.
   \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
@@ -1561,8 +1565,8 @@ 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}
@@ -1572,11 +1576,11 @@ una presenza generica di lock su un file, perch
 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
@@ -1588,17 +1592,6 @@ chiamate) per cui si deve sempre verificare il codice di ritorno di
 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}.}
@@ -1626,30 +1619,40 @@ acquisire un lock che porterebbe ad un \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
@@ -1661,6 +1664,96 @@ 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.
+
+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}
@@ -1687,7 +1780,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}.