+Una modalità alternativa di I/O, che usa una interfaccia completamente diversa
+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 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=9.5cm]{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, 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 è \func{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 \macro{MAP\_FAILED} (-1) in caso di errore, nel
+ qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\macro{EBADF}] Il file descriptor non è valido, e non si è usato
+ \macro{MAP\_ANONYMOUS}.
+ \item[\macro{EACCES}] Il file descriptor non si riferisce ad un file
+ regolare, o si è richiesto \macro{MAP\_PRIVATE} ma \param{fd} non è
+ aperto in lettura, o si è richiesto \macro{MAP\_SHARED} e impostato
+ \macro{PROT\_WRITE} ed \param{fd} non è aperto in lettura/scrittura, o
+ si è impostato \macro{PROT\_WRITE} ed \param{fd} è in
+ \textit{append-only}.
+ \item[\macro{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[\macro{ETXTBSY}] Si è impostato \macro{MAP\_DENYWRITE} ma \param{fd}
+ è aperto in scrittura.
+ \item[\macro{EAGAIN}] Il file è bloccato, o si è bloccata troppa memoria.
+ \item[\macro{ENOMEM}] Non c'è memoria o si è superato il limite sul numero
+ di mappature possibili.
+ \item[\macro{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
+ \macro{PROT\_EXEC} & Le pagine possono essere eseguite.\\
+ \macro{PROT\_READ} & Le pagine possono essere lette.\\
+ \macro{PROT\_WRITE} & Le pagine possono essere scritte.\\
+ \macro{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
+ \macro{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
+ \macro{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. \\
+ \macro{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 \macro{MAP\_PRIVATE}. \\
+ \macro{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 \macro{MAP\_SHARED}. \\
+ \macro{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 \macro{ETXTBUSY}).\\
+ \macro{MAP\_EXECUTABLE}& Ignorato. \\
+ \macro{MAP\_NORESERVE} & Si usa con \macro{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 \macro{SIGSEGV}. \\
+ \macro{MAP\_LOCKED} & Se impostato impedisce lo swapping delle pagine
+ mappate. \\
+ \macro{MAP\_GROWSDOWN} & Usato per gli stack. Indica
+ che la mappatura deve essere effettuata con gli
+ indirizzi crecenti verso il basso.\\
+ \macro{MAP\_ANONYMOUS} & La mappatura non è associata a nessun file. Gli
+ argomenti \param{fd} e \param{offset} sono
+ ignorati.\footnotemark\\
+ \macro{MAP\_ANON} & Sinonimo di \macro{MAP\_ANONYMOUS}, deprecato.\\
+ \macro{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 \macro{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. 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 (\macro{SIGSEGV}), dato che
+i permessi sul segmento di memoria relativo non consentono questo tipo di
+accesso.
+
+È 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, 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.
+
+\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}
+
+
+In questo caso è possibile accedere a quella zona di memoria che eccede le
+dimensioni specificate da \param{lenght}, senza ottenere un \macro{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=13cm]{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à \macro{SIGSEGV}, ma
+\macro{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 \var{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 \macro{MAP\_SHARED} padre e figlio accederanno allo
+stesso file in maniera condivisa, mentre se si è usato \macro{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
+\macro{PROT\_WRITE} e \macro{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 mappata su cui è mappato.
+
+Per quanto appena visto, è 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 \func{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[\macro{EINVAL}] O \param{start} non è multiplo di \macro{PAGESIZE},
+ o si è specificato un valore non valido per \param{flags}.
+ \item[\macro{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
+ \macro{MS\_ASYNC} & Richiede la sincronizzazione.\\
+ \macro{MS\_SYNC} & Attende che la sincronizzazione si eseguita.\\
+ \macro{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ò
+\macro{MS\_ASYNC} e \macro{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 \func{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[\macro{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}
+
+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
+in \textit{append mode}, quando più processi scrivono contemporaneamente sullo
+stesso file non è possibile determinare la sequenza in cui essi opereranno.
+
+Questo causa la possibilità di race condition\index{race condition}; in
+generale le situazioni più comuni sono due: l'interazione fra un processo che
+scrive e altri che leggono, in cui questi ultimi possono leggere informazioni
+scritte solo in maniera parziale o incompleta; o quella in cui diversi
+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.
+
+
+
+\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},\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.
+
+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.
+
+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. 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} è \func{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[\macro{EWOULDBLOCK}] Il file ha già un blocco attivo, e si è
+ specificato \macro{LOCK\_NB}.
+ \end{errlist}
+ }
+\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}.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|l|}
+ \hline
+ \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \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\_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, \macro{LOCK\_SH} e \macro{LOCK\_EX} permettono di
+richiedere un \textit{file lock}, ed ovviamente devono essere usati in maniera
+alternativa. Se si specifica anche \macro{LOCK\_NB} la funzione non si
+bloccherà qualora il lock non possa essere acquisito, ma ritornerà subito con
+un errore di \macro{EWOULDBLOCK}. Per rilasciare un lock si dovrà invece usare
+\macro{LOCK\_NB}.
+
+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 prima descrivere con maggiore dettaglio come viene
+realizzato il file locking nel kernel.
+
+In \figref{fig:file_flock_struct} si è riportato uno schema essenziale
+dell'implementazione del file locking 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,\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 \var{file\_lock}. La
+ lista è referenziata dall'indirizzo di partenza mantenuto dal campo
+ \var{i\_flock} della struttura \var{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
+ (\macro{FL\_FLOCK}) o POSIX (\macro{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=13cm]{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 \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 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.
+
+Questa struttura comporta 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 \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à cioè possibile rimuovere un file lock attraverso uno qualunque dei file
+descriptor che fanno riferimento alla stessa voce nella file table, quindi
+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; la rimozione cioè
+avverrà solo quando tutti i file descriptor che fanno riferimento alla stessa
+voce sono stati chiusi, quindi, nel caso ci siano processi figli che
+mantengono ancora aperto un file descriptor, il lock non sarà rilasciato.
+
+Si tenga presente 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 funzionalità in
+\secref{sec:file_fcntl}; quando la si impiega per il \textit{file locking}
+però 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[\macro{EACCES}] L'operazione è proibita per la presenza di
+ \textit{file lock} da parte di altri processi.
+ \item[\macro{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[\macro{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}. Non è garantito che il sistema riconosca sempre
+ questa situazione.
+ \item[\macro{EINTR}] La funzione è stata interrotta da un segnale prima di
+ poter acquisire un lock.
+ \end{errlist}
+ ed inoltre \macro{EBADF}, \macro{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;
+inoltre la funzione permette di leggere le informazioni relative ai blocchi
+esistenti. 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}) che contiene tutte le specifiche di un dato file
+lock.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
+struct flock {
+ short int l_type; /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK. */
+ short int l_whence; /* Where `l_start' is relative to (like `lseek'). */
+ off_t l_start; /* Offset where the lock begins. */
+ off_t l_len; /* Size of the locked area; zero means until EOF. */
+ pid_t l_pid; /* Process holding the lock. */
+};
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \type{flock}, usata da \func{fcntl} per il file
+ locking.}
+ \label{fig:struct_flock}
+\end{figure}
+
+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} non è bloccato da qualche altro lock: in caso
+ affermativo sovrascrive la struttura con i valori relativi a quest'ultimo,
+ altrimenti si limita a impostarne il campo \var{l\_type} con
+ \macro{F\_UNLCK}.
+\item[\macro{F\_SETLK}] se il campo \var{l\_type} della struttura puntata da
+ \param{lock} è \macro{F\_RDLCK} o \macro{F\_WRLCK} richiede il
+ corrispondente file lock, se è \macro{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 \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
+ rilasciato. Se l'attesa viene interrotta da un segnale la funzione ritorna
+ con un errore di \macro{EINTR}.
+\end{basedescript}
+
+Come accennato nell'interfaccia POSIX ogni file lock viene associato ad una
+struttura \func{flock}; i tre campi \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, e \var{l\_len} la
+lunghezza della sezione; \var{l\_whence} infine imposta il riferimento da cui
+contare \var{l\_start} e 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}).
+
+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. 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
+ \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.\\
+ \hline
+ \end{tabular}
+ \caption{Valori possibili per il campo \var{l\_type} di \func{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 riportati 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.
+
+\begin{figure}[htb]
+ \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}
+
+Infine il campo \var{l\_pid} riporta (viene usato solo in lettura, quando si
+chiama \func{fcntl} con \macro{F\_GETLK}) qual'è il processo cui appartiene il
+file lock. Nella semantica POSIX infatti il comportamento dei lock è diverso
+rispetto a quanto visto in precedenza per \func{flock}. Lo schema della
+struttura usata 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 si
+ sono evidenziati nella figura i campi di \var{file\_lock} significativi per
+ la semantica POSIX, in particolare adesso ciascun lock 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 blocco 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} 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 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.
+
+Abbiamo visto come l'interfaccia POSIX per il file locking sia molto più
+potente e flessibile di quella di BSD, ma è anche molto più complicata da
+usare. Per questo motivo è disponibile anche una interfaccia semplificata
+(ripresa da System V) che utilizza la funzione \func{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[\macro{EAGAIN}] Non è possibile acquisire il lock, e si è
+ selezionato \macro{LOCK\_NB}, oppure l'operazione è proibita perché il
+ file è mappato in memoria.
+ \item[\macro{ENOLCK}] Il sistema non ha le risorse per il locking: ci sono
+ troppi segmenti di lock aperti, si è esaurita la tabella dei lock.
+ \item[\macro{EDEADLK}] Si è riconosciuta una situazione di
+ \textit{deadlock}.
+ \end{errlist}
+ ed inoltre \macro{EBADF}, \macro{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
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|l|}
+ \hline
+ \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \macro{F\_LOCK} & Richiede un \textit{exclusive lock}. Se non può essere
+ ottenuto a causa di un lock preesistente la funzione
+ blocca il processo chiamante fino al rilascio di
+ quest'ultimo. \\
+ \macro{F\_TLOCK}& Stesso comportamento di \macro{F\_LOCK} ma la funzione
+ ritorna sempre subito, segnalando un errore quando il
+ lock non può essere acquisito. \\
+ \macro{F\_ULOCK}& Sblocca il file.\\
+ \macro{F\_TEST} & Controlla il lock, la funzione restituisce 0 se il file
+ non ha lock, o i lock appartengono al processo corrente,
+ e -1, con un errore di \macro{EACCES}, se altri processi
+ detengono un lock sul file.\\
+ \hline
+ \end{tabular}
+ \caption{Valori possibili per il campo \var{cmd} di \func{lockf}.}
+ \label{tab:file_lockf_type}
+\end{table}
+
+
+
+
+\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{suid}. Se si ricorda quanto esposto in
+\secref{sec:file_suid_sgid}), esso viene di norma utilizzato per cambiare
+l'userid effettivo con cui viene eseguito un programma, ed è pertanto sempre
+associato alla presenza del permesso di esecuzione. 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}.
+
+