%% fileadv.tex
%%
-%% Copyright (C) 2000-2014 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2015 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{La gestione avanzata dei file}
\label{cha:file_advanced}
In questo capitolo affronteremo le tematiche relative alla gestione avanzata
rispetto a quelle usate normalmente.
In generale questa interfaccia è completamente astratta e può essere
-implementata sia direttamente nel kernel, che in user space attraverso l'uso
-di \itindex{thread} \textit{thread}. Per le versioni del kernel meno recenti
+implementata sia direttamente nel kernel che in user space attraverso l'uso di
+\itindex{thread} \textit{thread}. Per le versioni del kernel meno recenti
esiste una implementazione di questa interfaccia fornita completamente delle
\acr{glibc} a partire dalla versione 2.1, che è realizzata completamente in
user space, ed è accessibile linkando i programmi con la libreria
-\file{librt}. Nelle versioni più recenti (a partire dalla 2.5.32) è stato
-introdotto nel kernel un nuovo layer per l'I/O asincrono, ma ancora il
-supporto è parziale ed insufficiente ad implementare l'AIO POSIX.
+\file{librt}. A partire dalla versione 2.5.32 è stato introdotto nel kernel
+una nuova infrastruttura per l'I/O asincrono, ma ancora il supporto è parziale
+ed insufficiente ad implementare tutto l'AIO POSIX.
Lo standard POSIX prevede che tutte le operazioni di I/O asincrono siano
controllate attraverso l'uso di una apposita struttura \struct{aiocb} (il cui
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
- piattaforma supporti questa caratteristica, questo viene indicato definendo
- le macro \macro{\_POSIX\_PRIORITIZED\_IO}, e
- \macro{\_POSIX\_PRIORITY\_SCHEDULING}.} La priorità viene impostata a
-partire da quella del processo chiamante (vedi sez.~\ref{sec:proc_priority}),
-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.
+di I/O, in generale perché ciò sia possibile occorre che la piattaforma
+supporti questa caratteristica, questo viene indicato dal fatto che le macro
+\macro{\_POSIX\_PRIORITIZED\_IO}, e \macro{\_POSIX\_PRIORITY\_SCHEDULING} sono
+definite. La priorità viene impostata a partire da quella del processo
+chiamante (vedi sez.~\ref{sec:proc_priority}), 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.
Infine il campo \var{aio\_sigevent} è una struttura di tipo \struct{sigevent}
(illustrata in in fig.~\ref{fig:struct_sigevent}) che serve a specificare il
Le due funzioni base dell'interfaccia per l'I/O asincrono sono
\funcd{aio\_read} ed \funcd{aio\_write}. Esse permettono di richiedere una
-lettura od una scrittura asincrona di dati, usando la struttura \struct{aiocb}
+lettura od una scrittura asincrona di dati usando la struttura \struct{aiocb}
appena descritta; i rispettivi prototipi sono:
\begin{funcproto}{
{Le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, nel qual
caso \var{errno} assumerà uno dei valori:
\begin{errlist}
+ \item[\errcode{EAGAIN}] la coda delle richieste è momentaneamente piena.
\item[\errcode{EBADF}] si è specificato un file descriptor sbagliato.
- \item[\errcode{ENOSYS}] la funzione non è implementata.
\item[\errcode{EINVAL}] si è specificato un valore non valido per i campi
\var{aio\_offset} o \var{aio\_reqprio} di \param{aiocbp}.
- \item[\errcode{EAGAIN}] la coda delle richieste è momentaneamente piena.
+ \item[\errcode{ENOSYS}] la funzione non è implementata.
\end{errlist}
}
\end{funcproto}
\errcode{EINVAL} siano rilevati immediatamente al momento della chiamata,
potrebbero anche emergere nelle fasi successive delle operazioni. Lettura e
scrittura avvengono alla posizione indicata da \var{aio\_offset}, a meno che
-il file non sia stato aperto in \itindex{append~mode} \textit{append mode}
-(vedi sez.~\ref{sec:file_open_close}), nel qual caso le scritture vengono
-effettuate comunque alla fine de file, nell'ordine delle chiamate a
-\func{aio\_write}.
+il file non sia stato aperto in \textit{append mode} (vedi
+sez.~\ref{sec:file_open_close}), nel qual caso le scritture vengono effettuate
+comunque alla fine del file, nell'ordine delle chiamate a \func{aio\_write}.
Si tenga inoltre presente che deallocare la memoria indirizzata da
\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 non si devono usare per \param{aiocbp}
+richiesta. Questo comporta che non si devono usare per \param{aiocbp}
\index{variabili!automatiche} variabili automatiche e che non si deve
riutilizzare la stessa struttura per un'altra operazione fintanto che la
precedente non sia stata ultimata. In generale per ogni operazione si deve
utilizzare una diversa struttura \struct{aiocb}.
-% vedere anche http://davmac.org/davpage/linux/async-io.html e
-% http://www.ibm.com/developerworks/linux/library/l-async/
-
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
eseguite in maniera corretta; per verificarne l'esito l'interfaccia prevede
prima è \funcd{aio\_error}, che serve a determinare un eventuale stato di
errore; il suo prototipo è:
-
\begin{funcproto}{
\fhead{aio.h}
\fdecl{int aio\_error(const struct aiocb *aiocbp)}
\end{funcproto}
La funzione recupera il valore dello stato di ritorno delle operazioni di I/O
-associate a \param{aiocbp} deve essere chiamata una sola volta per ciascuna
+associate a \param{aiocbp} e deve essere chiamata una sola volta per ciascuna
operazione asincrona, essa infatti fa sì che il sistema rilasci le risorse ad
essa associate. É per questo motivo che occorre chiamare la funzione solo dopo
che l'operazione cui \param{aiocbp} fa riferimento si è completata
-verificandolo con \func{aio\_error} ed una sola volta. Una chiamata precedente
-il completamento delle operazioni darebbe risultati indeterminati, così come
-chiamarla più di una volta.
+verificandolo con \func{aio\_error}, ed usarla una sola volta. Una chiamata
+precedente il completamento delle operazioni darebbe risultati indeterminati,
+così come chiamarla più di una volta.
La funzione restituisce il valore di ritorno relativo all'operazione eseguita,
così come ricavato dalla sottostante \textit{system call} (il numero di byte
compiuta dalla funzione \funcd{aio\_fsync}, che ha lo stesso effetto della
analoga \func{fsync}, ma viene eseguita in maniera asincrona; il suo prototipo
è:
-\begin{prototype}{aio.h}
-{int aio\_fsync(int op, struct aiocb *aiocbp)}
-Richiede la sincronizzazione dei dati per il file indicato da \param{aiocbp}.
-
-\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
- errore, che può essere, con le stesse modalità di \func{aio\_read},
- \errval{EAGAIN}, \errval{EBADF} o \errval{EINVAL}.}
-\end{prototype}
+\begin{funcproto}{
+\fhead{aio.h}
+\fdecl{int aio\_fsync(int op, struct aiocb *aiocbp)}
+\fdesc{Richiede la sincronizzazione dei dati su disco.}
+}
-La funzione richiede la sincronizzazione delle operazioni di I/O, ritornando
-immediatamente. L'esecuzione effettiva della sincronizzazione dovrà essere
-verificata con \func{aio\_error} e \func{aio\_return} come per le operazioni
-di lettura e scrittura. L'argomento \param{op} permette di indicare la
-modalità di esecuzione, se si specifica il valore \const{O\_DSYNC} le
-operazioni saranno completate con una chiamata a \func{fdatasync}, se si
-specifica \const{O\_SYNC} con una chiamata a \func{fsync} (per i dettagli vedi
-sez.~\ref{sec:file_sync}).
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà gli stessi valori visti \func{aio\_read} con lo
+ stesso significato.
+}
+\end{funcproto}
-Il successo della chiamata assicura la sincronizzazione delle operazioni fino
-allora richieste, niente è garantito riguardo la sincronizzazione dei dati
-relativi ad eventuali operazioni richieste successivamente. Se si è
-specificato un meccanismo di notifica questo sarà innescato una volta che le
-operazioni di sincronizzazione dei dati saranno completate.
+La funzione richiede la sincronizzazione dei dati delle operazioni di I/O
+relative al file descriptor indicato in \texttt{aiocbp->aio\_fildes},
+ritornando immediatamente. Si tenga presente che la funzione mette
+semplicemente in coda la richiesta, l'esecuzione effettiva della
+sincronizzazione dovrà essere verificata con \func{aio\_error} e
+\func{aio\_return} come per le operazioni di lettura e
+scrittura. L'argomento \param{op} permette di indicare la modalità di
+esecuzione, se si specifica il valore \const{O\_DSYNC} le operazioni saranno
+completate con una chiamata a \func{fdatasync}, se si specifica
+\const{O\_SYNC} con una chiamata a \func{fsync} (per i dettagli vedi
+sez.~\ref{sec:file_sync}).
-In alcuni casi può essere necessario interrompere le operazioni (in genere
-quando viene richiesta un'uscita immediata dal programma), per questo lo
-standard POSIX.1b prevede una funzione apposita, \funcd{aio\_cancel}, che
+Il successo della chiamata assicura la richiesta di sincronizzazione dei dati
+relativi operazioni di I/O asincrono richieste fino a quel momento, niente è
+garantito riguardo la sincronizzazione dei dati relativi ad eventuali
+operazioni richieste successivamente. Se si è specificato un meccanismo di
+notifica questo sarà innescato una volta che le operazioni di sincronizzazione
+dei dati saranno completate (\texttt{aio\_sigevent} è l'unico altro campo
+di \param{aiocbp} che viene usato.
+
+In alcuni casi può essere necessario interrompere le operazioni di I/O (in
+genere quando viene richiesta un'uscita immediata dal programma), per questo
+lo standard POSIX.1b prevede una funzione apposita, \funcd{aio\_cancel}, che
permette di cancellare una operazione richiesta in precedenza; il suo
prototipo è:
-\begin{prototype}{aio.h}
-{int aio\_cancel(int fildes, struct aiocb *aiocbp)}
-Richiede la cancellazione delle operazioni sul file \param{fildes} specificate
-da \param{aiocbp}.
-
-\bodydesc{La funzione restituisce il risultato dell'operazione con un codice
- di positivo, e -1 in caso di errore, che avviene qualora si sia specificato
- un valore non valido di \param{fildes}, imposta \var{errno} al valore
- \errval{EBADF}.}
-\end{prototype}
+
+\begin{funcproto}{
+\fhead{aio.h}
+\fdecl{int aio\_cancel(int fd, struct aiocb *aiocbp)}
+\fdesc{Richiede la cancellazione delle operazioni di I/O asincrono.}
+}
+
+{La funzione ritorna un intero positivo che indica il risultato
+ dell'operazione in caso di successo e $-1$ per un errore, nel qual caso
+ \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EBADF}] \param{fd} non è un file descriptor valido.
+ \item[\errcode{ENOSYS}] la funzione non è implementata.
+ \end{errlist}
+}
+\end{funcproto}
La funzione permette di cancellare una operazione specifica sul file
-\param{fildes}, o tutte le operazioni pendenti, specificando \val{NULL} come
-valore di \param{aiocbp}. Quando una operazione viene cancellata una
-successiva chiamata ad \func{aio\_error} riporterà \errcode{ECANCELED} come
-codice di errore, ed il suo codice di ritorno sarà -1, inoltre il meccanismo
-di notifica non verrà invocato. Se si specifica una operazione relativa ad un
-altro file descriptor il risultato è indeterminato. In caso di successo, i
-possibili valori di ritorno per \func{aio\_cancel} (anch'essi definiti in
-\headfile{aio.h}) sono tre:
+\param{fd}, idicata con \param{aiocbp}, o tutte le operazioni pendenti,
+specificando \val{NULL} come valore di \param{aiocbp}. Quando una operazione
+viene cancellata una successiva chiamata ad \func{aio\_error} riporterà
+\errcode{ECANCELED} come codice di errore, ed mentre il valore di ritorno per
+\func{aio\_return} sarà -1, inoltre il meccanismo di notifica non verrà
+invocato. Se con \param{aiocbp} si specifica una operazione relativa ad un
+file descriptor diverso da \param{fd} il risultato è indeterminato. In caso
+di successo, i possibili valori di ritorno per \func{aio\_cancel} (anch'essi
+definiti in \headfile{aio.h}) sono tre:
\begin{basedescript}{\desclabelwidth{3.0cm}}
\item[\const{AIO\_ALLDONE}] indica che le operazioni di cui si è richiesta la
cancellazione sono state già completate,
fornisce anche una apposita funzione, \funcd{aio\_suspend}, che permette di
sospendere l'esecuzione del processo chiamante fino al completamento di una
specifica operazione; il suo prototipo è:
-\begin{prototype}{aio.h}
-{int aio\_suspend(const struct aiocb * const list[], int nent, const struct
- timespec *timeout)}
-
- Attende, per un massimo di \param{timeout}, il completamento di una delle
- operazioni specificate da \param{list}.
-
- \bodydesc{La funzione restituisce 0 se una (o più) operazioni sono state
- completate, e -1 in caso di errore nel qual caso \var{errno} assumerà uno
- dei valori:
- \begin{errlist}
+
+\begin{funcproto}{
+\fhead{aio.h}
+\fdecl{int aio\_suspend(const struct aiocb * const list[], int nent,
+\phantom{int aio\_suspend(}const struct timespec *timeout)}
+\fdesc{Attende il completamento di una operazione di I/O asincrono.}
+}
+
+{La funzione ritorna $0$ se una (o più) operazioni sono state completate e
+ $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
\item[\errcode{EAGAIN}] nessuna operazione è stata completata entro
\param{timeout}.
- \item[\errcode{ENOSYS}] la funzione non è implementata.
\item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
- \end{errlist}
- }
-\end{prototype}
-
+ \item[\errcode{ENOSYS}] la funzione non è implementata.
+ \end{errlist}
+}
+\end{funcproto}
+
La funzione permette di bloccare il processo fintanto che almeno una delle
\param{nent} operazioni specificate nella lista \param{list} è completata, per
un tempo massimo specificato da \param{timout}, o fintanto che non arrivi un
-segnale.\footnote{si tenga conto che questo segnale può anche essere quello
- utilizzato come meccanismo di notifica.} La lista deve essere inizializzata
+segnale (si tenga conto che questo segnale potrebbe essere anche quello
+utilizzato come meccanismo di notifica). La lista deve essere inizializzata
con delle strutture \struct{aiocb} relative ad operazioni effettivamente
richieste, ma può contenere puntatori nulli, che saranno ignorati. In caso si
siano specificati valori non validi l'effetto è indefinito. Un valore