numero di quelli da tenere sotto controllo; dimenticarsi di aumentare di uno
il valore di \param{n} è un errore comune.}
-Infine l'argomento \param{timeout}, specifica un tempo massimo di
-attesa\footnote{il tempo è valutato come \textit{clock time} (vedi
- \secref{sec:sys_unix_time}).} prima che la funzione ritorni; se impostato a
-\val{NULL} la funzione attende indefinitamente. Si può specificare anche un
-tempo nullo (cioè una struttura \struct{timeval} con i campi impostati a
-zero), qualora si voglia semplicemente controllare lo stato corrente dei file
-descriptor.
-
-La funzione restituisce il totale dei file descriptor pronti nei tre insiemi,
-il valore zero indica sempre che si è raggiunto un timeout. Ciascuno dei tre
-insiemi viene sovrascritto per indicare quale file descriptor è pronto per le
-operazioni ad esso relative, in modo da poterlo controllare con la macro
-\const{FD\_ISSET}. In caso di errore la funzione restituisce -1 e gli insiemi
-non vengono toccati.
+Infine l'argomento \param{timeout}, specifica un tempo massimo di attesa prima
+che la funzione ritorni; se impostato a \val{NULL} la funzione attende
+indefinitamente. Si può specificare anche un tempo nullo (cioè una struttura
+\struct{timeval} con i campi impostati a zero), qualora si voglia
+semplicemente controllare lo stato corrente dei file descriptor.
+
+La funzione restituisce il numero di file descriptor pronti,\footnote{questo è
+ il comportamento previsto dallo standard, ma la standardizzazione della
+ funzione è recente, ed esistono ancora alcune versioni di Unix che non si
+ comportano in questo modo.} e ciascun insieme viene sovrascritto per
+indicare i file descriptor pronti per le operazioni ad esso relative, in modo
+da poterli controllare con \const{FD\_ISSET}. Se invece si ha un timeout
+viene restituito un valore nullo e gli insiemi non vengono modificati. In
+caso di errore la funzione restituisce -1, ed i valori dei tre insiemi sono
+indefiniti e non si può fare nessun affidamento sul loro contenuto.
In Linux \func{select} modifica anche il valore di \param{timeout},
impostandolo al tempo restante in caso di interruzione prematura; questo è
caratteristica è disponibile nei sistemi che derivano da System V e non
disponibile per quelli che derivano da BSD.}
-Come accennato l'interfaccia di \func{select} è una estensione creata nello
-sviluppo di BSD; anche System V ha introdotto una sua interfaccia per gestire
-l'\textit{I/O multiplexing}, basata sulla funzione \funcd{poll},\footnote{la
- funzione è prevista dallo standard XPG4, ed è stata introdotta in Linux come
- system call a partire dal kernel 2.1.23 e dalle \acr{libc} 5.4.28.} il cui
-prototipo è:
+Uno dei problemi che si presentano con l'uso di \func{select} è che il suo
+comportamento dipende dal valore del file descriptor che si vuole tenere sotto
+controllo. Infatti il kernel riceve solo un valore massimo, e dovrà
+effettuare una scansione su tutto l'intervallo, che può essere anche molto
+ampio, per capire quali sono i file descriptor da tenere sotto controllo,
+anche se sono solo poche unità; e questo ha ovviamente un pessimo risultato
+per le prestazioni; il comportamenento viene della funzione viene così a
+dipendere in maniera innaturale dal valore del file decriptor.
+
+Inoltre c'è anche il problema che il numero massimo dei file che si possono
+tenere sotto controllo, la funzione è nata quando il kernel consentiva un
+numero massimo di 1024 file descriptor per processo, adesso che il numero può
+essere arbitario si viene a creare una dipendenza del tutto artificiale dalle
+dimensioni della struttura \type{fd\_set}, che può necessitare di essere
+estesa, con ulteriori perdite di prestazioni.
+Per questo System V, invece di utilizzare l'interfaccia di \func{select}, che
+è una estensione creata nello sviluppo di BSD, ha introdotto una sua
+interfaccia per gestire l'\textit{I/O multiplexing}, basata sulla funzione
+\funcd{poll},\footnote{la funzione è prevista dallo standard XPG4, ed è stata
+ introdotta in Linux come system call a partire dal kernel 2.1.23 e dalle
+ \acr{libc} 5.4.28.} il cui prototipo è:
\begin{prototype}{sys/poll.h}
{int poll(struct pollfd *ufds, unsigned int nfds, int timeout)}
una condizione di errore.
Lo standard POSIX è rimasto a lungo senza primitive per l'\textit{I/O
- multiplexing}, che è stata introdotto con le ultime revisioni dello standard
-(POSIX 1003.1g-2000 e POSIX 1003.1-2001). Esso prevede che tutte le funzioni
-ad esso relative vengano dichiarate nell'header \file{sys/select.h}, che
-sostituisce i precedenti, ed aggiunge a \func{select} una nuova funzione
+ multiplexing}, introdotto solo con le ultime revisioni dello standard (POSIX
+1003.1g-2000 e POSIX 1003.1-2001). Esso prevede che tutte le funzioni ad esso
+relative vengano dichiarate nell'header \file{sys/select.h}, che sostituisce i
+precedenti, ed aggiunge a \func{select} una nuova funzione
\funcd{pselect},\footnote{il supporto per lo standard POSIX 1003.1-2001, ed
l'header \file{sys/select.h}, compaiono in Linux a partire dalle \acr{glibc}
2.1. Le \acr{libc4} e \acr{libc5} non contengono questo header, le
In generale questa interfaccia è completamente astratta e può essere
implementata sia direttamente nel kernel, che in user space attraverso l'uso
-di thread. Al momento\footnote{fino ai kernel della serie 2.4.x, nella serie
- 2.5.x è però iniziato un lavoro completo di riscrittura di tutto il sistema
- di I/O, che prevede anche l'introduzione di un nuovo layer per l'I/O
- asincrono (effettuato a partire dal 2.5.32).} esiste una sola versione
-stabile di questa interfaccia, quella delle \acr{glibc}, che è realizzata
-completamente in user space, ed accessibile linkando i programmi con la
-libreria \file{librt}. Esistono comunque vari progetti sperimentali (come il
-KAIO della SGI, o i patch di Benjamin La Haise) che prevedono un supporto
-diretto da parte del kernel.
+di thread. Al momento esiste una sola versione stabile di questa interfaccia,
+quella delle \acr{glibc}, che è realizzata completamente in user space, ed
+accessibile linkando i programmi con la libreria \file{librt}. Nei kernel
+della nuova serie è stato anche introdotta (a partire dal 2.5.32) un nuovo
+layer per l'I/O asincrono.
Lo standard prevede che tutte le operazioni di I/O asincrono siano controllate
attraverso l'uso di una apposita struttura \struct{aiocb} (il cui nome sta per
\end{figure}
Le operazioni di I/O asincrono possono essere effettuate solo su un file già
-aperto; il file deve inoltre supportare la funzione \func{lseek},
-pertanto terminali e pipe sono esclusi. Non c'è limite al numero di operazioni
-contemporanee effettuabili su un singolo file.
-
-Ogni operazione deve inizializzare opportunamente un \textit{control block}.
-Il file descriptor su cui operare deve essere specificato tramite il campo
-\var{aio\_fildes}; dato che più operazioni possono essere eseguita in maniera
-asincrona, il concetto di posizione corrente sul file viene a mancare;
-pertanto si deve sempre specificare nel campo \var{aio\_offset} la posizione
-sul file da cui i dati saranno letti o scritti. Nel campo \var{aio\_buf} deve
-essere specificato l'indirizzo del buffer usato per l'I/O, ed in
-\var{aio\_nbytes} la lunghezza del blocco di dati da trasferire.
+aperto; il file deve inoltre supportare la funzione \func{lseek}, pertanto
+terminali e pipe sono esclusi. Non c'è limite al numero di operazioni
+contemporanee effettuabili su un singolo file. Ogni operazione deve
+inizializzare opportunamente un \textit{control block}. Il file descriptor su
+cui operare deve essere specificato tramite il campo \var{aio\_fildes}; dato
+che più operazioni possono essere eseguita in maniera asincrona, il concetto
+di posizione corrente sul file viene a mancare; pertanto si deve sempre
+specificare nel campo \var{aio\_offset} la posizione sul file da cui i dati
+saranno letti o scritti. Nel campo \var{aio\_buf} deve essere specificato
+l'indirizzo del buffer usato per l'I/O, ed in \var{aio\_nbytes} la lunghezza
+del blocco di dati da trasferire.
Il campo \var{aio\_reqprio} permette di impostare la priorità delle operazioni
di I/O.\footnote{in generale perché ciò sia possibile occorre che la
le macro \macro{\_POSIX\_PRIORITIZED\_IO}, e
\macro{\_POSIX\_PRIORITY\_SCHEDULING}.} La priorità viene impostata a
partire da quella del processo chiamante (vedi \secref{sec:proc_priority}),
-cui viene sottratto il valore di questo campo.
-
-Il campo \var{aio\_lio\_opcode} è usato soltanto dalla funzione
-\func{lio\_listio}, che, come vedremo più avanti, permette di eseguire con una
-sola chiamata una serie di operazioni, usando un vettore di \textit{control
- block}. Tramite questo campo si specifica quale è la natura di ciascuna di
-esse.
+cui viene sottratto il valore di questo campo. Il campo
+\var{aio\_lio\_opcode} è usato solo dalla funzione \func{lio\_listio}, che,
+come vedremo, permette di eseguire con una sola chiamata una serie di
+operazioni, usando un vettore di \textit{control block}. Tramite questo campo
+si specifica quale è la natura di ciascuna di esse.
\begin{figure}[!htb]
\footnotesize \centering
\param{aiocbp} o modificarne i valori prima della conclusione di una
operazione può dar luogo a risultati impredicibili, perché l'accesso ai vari
campi per eseguire l'operazione può avvenire in un momento qualsiasi dopo la
-richiesta. Questo comporta che occorre evitare di usare per \param{aiocbp}
+richiesta. Questo comporta che non si devono usare per \param{aiocbp}
variabili automatiche e che non si deve riutilizzare la stessa struttura per
-un ulteriore operazione fintanto che la precedente non sia stata ultimata. In
-generale per ogni operazione di I/O asincrono si deve utilizzare una diversa
-struttura \struct{aiocb}.
+un'altra operazione fintanto che la precedente non sia stata ultimata. In
+generale per ogni operazione si deve utilizzare una diversa struttura
+\struct{aiocb}.
Dato che si opera in modalità asincrona, il successo di \func{aio\_read} o
\func{aio\_write} non implica che le operazioni siano state effettivamente
\func{fsync}.
Una volta che si sia certi che le operazioni siano state concluse (cioè dopo
-che una chiamata ad \func{aio\_error} non ha restituito \errcode{EINPROGRESS},
-si potrà usare la seconda funzione dell'interfaccia, \funcd{aio\_return}, che
+che una chiamata ad \func{aio\_error} non ha restituito
+\errcode{EINPROGRESS}), si potrà usare la funzione \funcd{aio\_return}, che
permette di verificare il completamento delle operazioni di I/O asincrono; il
suo prototipo è:
\begin{prototype}{aio.h}
esaurimento.
Oltre alle operazioni di lettura e scrittura l'interfaccia POSIX.1b mette a
-disposizione un'altra operazione, quella di sincronizzazione dell'I/O, essa è
+disposizione un'altra operazione, quella di sincronizzazione dell'I/O,
compiuta dalla funzione \func{aio\_fsync}, che ha lo stesso effetto della
analoga \func{fsync}, ma viene eseguita in maniera asincrona; il suo prototipo
è:
\begin{errlist}
\item[\errcode{EAGAIN}] Nessuna operazione è stata completata entro
\param{timeout}.
+ \item[\errcode{EINVAL}] Si è passato un valore di \param{mode} non valido
+ o un numero di operazioni \param{nent} maggiore di
+ \const{AIO\_LISTIO\_MAX}.
\item[\errcode{ENOSYS}] La funzione non è implementata.
\item[\errcode{EINTR}] La funzione è stata interrotta da un segnale.
\end{errlist}
\begin{figure}[htb]
\centering
- \includegraphics[width=9.5cm]{img/mmap_layout}
+ \includegraphics[width=7.cm]{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}
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.
+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 è \funcd{mmap}, che serve ad eseguire la mappatura
\begin{errlist}
\item[\errcode{EBADF}] Il file descriptor non è valido, e non si è usato
\const{MAP\_ANONYMOUS}.
- \item[\errcode{EACCES}] Il file descriptor non si riferisce ad un file
- regolare, o si è richiesto \const{MAP\_PRIVATE} ma \param{fd} non è
- aperto in lettura, o si è richiesto \const{MAP\_SHARED} e impostato
- \const{PROT\_WRITE} ed \param{fd} non è aperto in lettura/scrittura, o
- si è impostato \const{PROT\_WRITE} ed \param{fd} è in
- \textit{append-only}.
+ \item[\errcode{EACCES}] o \param{fd} non si riferisce ad un file regolare,
+ o si è usato \const{MAP\_PRIVATE} ma \param{fd} non è aperto in lettura,
+ o si è usato \const{MAP\_SHARED} e impostato \const{PROT\_WRITE} ed
+ \param{fd} non è aperto in lettura/scrittura, o si è impostato
+ \const{PROT\_WRITE} ed \param{fd} è in \textit{append-only}.
\item[\errcode{EINVAL}] I valori di \param{start}, \param{length} o
\param{offset} non sono validi (o troppo grandi o non allineati sulla
dimensione delle pagine).
\begin{figure}[htb]
\centering
- \includegraphics[width=13cm]{img/mmap_exceed}
+ \includegraphics[width=10cm]{img/mmap_exceed}
\caption{Schema della mappatura in memoria di file di dimensioni inferiori
alla lunghezza richiesta.}
\label{fig:file_mmap_exceed}
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.
+che le funzioni \func{read} o \func{write} vengono eseguite comunque e non
+risentono affatto della presenza di un eventuale \textit{lock}; pertanto è
+sempre compito dei vari processi che intendono usare il file locking,
+controllare esplicitamente lo stato dei file condivisi prima di accedervi,
+utilizzando le relative funzioni.
In generale si distinguono due tipologie di \textit{file lock}:\footnote{di
seguito ci riferiremo sempre ai blocchi di accesso ai file con la
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.
+file affinché il suo contenuto 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
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.
+proteggere il suo accesso in scrittura.
\begin{table}[htb]
\centering
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. La situazione
-delle varie possibilità è riassunta in \tabref{tab:file_file_lock}.
-
-Si tenga presente infine che il controllo di accesso è effettuato quando si
-apre un file, l'unico controllo residuo è che il tipo di lock che si vuole
-ottenere deve essere compatibile con le modalità di apertura dello stesso (di
-lettura per un read lock e di scrittura per un write lock).
+delle varie possibilità è riassunta in \tabref{tab:file_file_lock}, dove si
+sono riportati, per le varie tipologie di lock presenti su un file, il
+risultato che si ha in corrispondenza alle due tipologie di \textit{file lock}
+menzionate, nel successo della richiesta.
+
+Si tenga presente infine che il controllo di accesso e la gestione dei
+permessi viene effettuata quando si apre un file, l'unico controllo residuo
+che si può avere riguardo il \textit{file locking} è che il tipo di lock che
+si vuole ottenere su un file deve essere compatibile con le modalità di
+apertura dello stesso (in lettura per un read lock e in scrittura per un write
+lock).
%% Si ricordi che
%% la condizione per acquisire uno \textit{shared lock} è che il file non abbia
%% \textit{exclusive lock} non deve essere presente nessun tipo di blocco.
-\subsection{La funzione \func{flock}}
+\subsection{La funzione \func{flock}}
\label{sec:file_flock}
La prima interfaccia per il file locking, quella derivata da BSD, permette di
\begin{figure}[htb]
\centering
- \includegraphics[width=12.5cm]{img/file_flock}
+ \includegraphics[width=14cm]{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}
un certo punto fino alla fine del file, coprendo automaticamente quanto
eventualmente aggiunto in coda allo stesso.
-Il tipo di file lock richiesto viene specificato dal campo \var{l\_type}, esso
-può assumere i tre valori definiti dalle costanti riportate 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. 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.
-
\begin{table}[htb]
\centering
\footnotesize
\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 definiti dalle costanti riportate 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. 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 \secref{sec:file_fcntl}, specifica