%% fileadv.tex
%%
-%% Copyright (C) 2000-2006 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 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",
possibile prevedere quando questo può avvenire (il caso più classico è quello
di un server in attesa di dati in ingresso da vari client). Quello che può
accadere è di restare bloccati nell'eseguire una operazione su un file
-descriptor che non è ``\textsl{pronto}'', quando ce ne potrebbe essere
-un altro disponibile. Questo comporta nel migliore dei casi una operazione
+descriptor che non è ``\textsl{pronto}'', quando ce ne potrebbe essere un
+altro disponibile. Questo comporta nel migliore dei casi una operazione
ritardata inutilmente nell'attesa del completamento di quella bloccata, mentre
nel peggiore dei casi (quando la conclusione della operazione bloccata dipende
da quanto si otterrebbe dal file descriptor ``\textsl{disponibile}'') si
-potrebbe addirittura arrivare ad un \textit{deadlock}\itindex{deadlock}.
+potrebbe addirittura arrivare ad un \itindex{deadlock} \textit{deadlock}.
Abbiamo già accennato in sez.~\ref{sec:file_open} che è possibile prevenire
questo tipo di comportamento delle funzioni di I/O aprendo un file in
restituendo l'errore \errcode{EAGAIN}. L'utilizzo di questa modalità di I/O
permette di risolvere il problema controllando a turno i vari file descriptor,
in un ciclo in cui si ripete l'accesso fintanto che esso non viene garantito.
-Ovviamente questa tecnica, detta \textit{polling}\itindex{polling}, è
+Ovviamente questa tecnica, detta \itindex{polling} \textit{polling}, è
estremamente inefficiente: si tiene costantemente impiegata la CPU solo per
eseguire in continuazione delle system call che nella gran parte dei casi
falliranno.
grafica) sono state successivamente introdotte delle estensioni che
permettessero la creazione di meccanismi di notifica più efficienti dell'unica
soluzione disponibile con l'interfaccia tradizionale, che è quella del
-\itindex{polling}\textit{polling}.
+\itindex{polling} \textit{polling}.
Queste nuove funzionalità sono delle estensioni specifiche, non
standardizzate, che sono disponibili soltanto su Linux (anche se altri kernel
Benché la modalità di apertura asincrona di un file possa risultare utile in
varie occasioni (in particolar modo con i socket e gli altri file per i quali
-le funzioni di I/O sono \index{system~call~lente}system call lente), essa è
+le funzioni di I/O sono \index{system~call~lente} system call lente), essa è
comunque limitata alla notifica della disponibilità del file descriptor per le
operazioni di I/O, e non ad uno svolgimento asincrono delle medesime. Lo
standard POSIX.1b definisce una interfaccia apposita per l'I/O asincrono vero
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} sono
-tre (anch'essi definiti in \file{aio.h}):
+altro file descriptor il risultato è indeterminato. In caso di successo, i
+possibili valori di ritorno per \func{aio\_cancel} (anch'essi definiti in
+\file{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,
}
\end{prototype}
-La funzione esegue la richiesta delle \param{nent} operazioni indicate dalla
-lista \param{list}; questa deve contenere gli indirizzi di altrettanti
-\textit{control block}, opportunamente inizializzati; in particolare nel caso
-dovrà essere specificato il tipo di operazione tramite il campo
-\var{aio\_lio\_opcode}, che può prendere i tre valori:
+La funzione esegue la richiesta delle \param{nent} operazioni indicate nella
+lista \param{list} che deve contenere gli indirizzi di altrettanti
+\textit{control block} opportunamente inizializzati; in particolare dovrà
+essere specificato il tipo di operazione con il campo \var{aio\_lio\_opcode},
+che può prendere i valori:
\begin{basedescript}{\desclabelwidth{2.0cm}}
\item[\const{LIO\_READ}] si richiede una operazione di lettura.
\item[\const{LIO\_WRITE}] si richiede una operazione di scrittura.
\item[\const{LIO\_NOP}] non si effettua nessuna operazione.
\end{basedescript}
-l'ultimo valore viene usato quando si ha a che fare con un vettore di
-dimensione fissa, per poter specificare solo alcune operazioni, o quando si è
-dovuto cancellare delle operazioni e si deve ripetere la richiesta per quelle
-non completate.
+dove \const{LIO\_NOP} viene usato quando si ha a che fare con un vettore di
+dimensione fissa, per poter specificare solo alcune operazioni, o quando si
+sono dovute cancellare delle operazioni e si deve ripetere la richiesta per
+quelle non completate.
-L'argomento \param{mode} permette di stabilire il comportamento della
-funzione, se viene specificato il valore \const{LIO\_WAIT} la funzione si
-blocca fino al completamento di tutte le operazioni richieste; se invece si
-specifica \const{LIO\_NOWAIT} la funzione ritorna immediatamente dopo aver
-messo in coda tutte le richieste. In questo caso il chiamante può richiedere
-la notifica del completamento di tutte le richieste, impostando l'argomento
-\param{sig} in maniera analoga a come si fa per il campo \var{aio\_sigevent}
-di \struct{aiocb}.
+L'argomento \param{mode} controlla il comportamento della funzione, se viene
+usato il valore \const{LIO\_WAIT} la funzione si blocca fino al completamento
+di tutte le operazioni richieste; se si usa \const{LIO\_NOWAIT} la funzione
+ritorna immediatamente dopo aver messo in coda tutte le richieste. In tal caso
+il chiamante può richiedere la notifica del completamento di tutte le
+richieste, impostando l'argomento \param{sig} in maniera analoga a come si fa
+per il campo \var{aio\_sigevent} di \struct{aiocb}.
\section{Altre modalità di I/O avanzato}
\begin{functions}
\headdecl{sys/uio.h}
- \funcdecl{int readv(int fd, const struct iovec *vector, int count)} Esegue
- una lettura vettorizzata da \param{fd} nei \param{count} buffer specificati
- da \param{vector}.
-
- \funcdecl{int writev(int fd, const struct iovec *vector, int count)} Esegue
- una scrittura vettorizzata da \param{fd} nei \param{count} buffer
- specificati da \param{vector}.
+ \funcdecl{int readv(int fd, const struct iovec *vector, int count)}
+ \funcdecl{int writev(int fd, const struct iovec *vector, int count)}
+
+ Eseguono rispettivamente una lettura o una scrittura vettorizzata.
\bodydesc{Le funzioni restituiscono il numero di byte letti o scritti in
caso di successo, e -1 in caso di errore, nel qual caso \var{errno}
assumerà uno dei valori:
\begin{errlist}
- \item[\errcode{EBADF}] si è specificato un file descriptor sbagliato.
\item[\errcode{EINVAL}] si è specificato un valore non valido per uno degli
argomenti (ad esempio \param{count} è maggiore di \const{MAX\_IOVEC}).
\item[\errcode{EINTR}] la funzione è stata interrotta da un segnale prima di
di avere eseguito una qualunque lettura o scrittura.
\item[\errcode{EAGAIN}] \param{fd} è stato aperto in modalità non bloccante e
non ci sono dati in lettura.
- \item[\errcode{EOPNOTSUPP}] La coda delle richieste è momentaneamente piena.
+ \item[\errcode{EOPNOTSUPP}] la coda delle richieste è momentaneamente piena.
\end{errlist}
- ed inoltre \errval{EISDIR}, \errval{ENOMEM}, \errval{EFAULT} (se non sono
- stato allocati correttamente i buffer specificati nei campi
- \var{iov\_base}), più tutti gli ulteriori errori che potrebbero avere le
- usuali funzioni di lettura e scrittura eseguite su \param{fd}.}
+ ed anche \errval{EISDIR}, \errval{EBADF}, \errval{ENOMEM}, \errval{EFAULT}
+ (se non sono stati allocati correttamente i buffer specificati nei campi
+ \var{iov\_base}), più gli eventuali errori delle funzioni di lettura e
+ scrittura eseguite su \param{fd}.}
\end{functions}
-Entrambe le funzioni usano una struttura \struct{iovec}, definita in
-fig.~\ref{fig:file_iovec}, che definisce dove i dati devono essere letti o
-scritti. Il primo campo, \var{iov\_base}, contiene l'indirizzo del buffer ed
-il secondo, \var{iov\_len}, la dimensione dello stesso.
+Entrambe le funzioni usano una struttura \struct{iovec}, la cui definizione è
+riportata in fig.~\ref{fig:file_iovec}, che definisce dove i dati devono
+essere letti o scritti ed in che quantità. Il primo campo della struttura,
+\var{iov\_base}, contiene l'indirizzo del buffer ed il secondo,
+\var{iov\_len}, la dimensione dello stesso.
\begin{figure}[!htb]
\footnotesize \centering
\label{fig:file_iovec}
\end{figure}
-I buffer da utilizzare sono indicati attraverso l'argomento \param{vector} che
-è un vettore di strutture \struct{iovec}, la cui lunghezza è specificata da
-\param{count}. Ciascuna struttura dovrà essere inizializzata per
-opportunamente per indicare i vari buffer da/verso i quali verrà eseguito il
-trasferimento dei dati. Essi verranno letti (o scritti) nell'ordine in cui li
-si sono specificati nel vettore \param{vector}.
+La lista dei buffer da utilizzare viene indicata attraverso l'argomento
+\param{vector} che è un vettore di strutture \struct{iovec}, la cui lunghezza
+è specificata dall'argomento \param{count}. Ciascuna struttura dovrà essere
+inizializzata opportunamente per indicare i vari buffer da e verso i quali
+verrà eseguito il trasferimento dei dati. Essi verranno letti (o scritti)
+nell'ordine in cui li si sono specificati nel vettore \param{vector}.
\subsection{File mappati in memoria}
Una modalità alternativa di I/O, che usa una interfaccia completamente diversa
rispetto a quella classica vista in cap.~\ref{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
+\textsl{paginazione} \index{paginazione} usato dalla memoria virtuale (vedi
sez.~\ref{sec:proc_mem_gen}), permette di \textsl{mappare} il contenuto di un
file in una sezione dello spazio di indirizzi del processo.
+\begin{figure}[htb]
+ \centering
+ \includegraphics[width=12cm]{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}
+
Il meccanismo è illustrato in fig.~\ref{fig:file_mmap_layout}, una sezione del
file viene \textsl{mappata} direttamente nello spazio degli indirizzi del
programma. Tutte le operazioni di lettura e scrittura su variabili contenute
in questa zona di memoria verranno eseguite leggendo e scrivendo dal contenuto
-del file attraverso il sistema della memoria virtuale\index{memoria~virtuale}
+del file attraverso il sistema della memoria virtuale \index{memoria~virtuale}
che in maniera analoga a quanto avviene per le pagine che vengono salvate e
rilette nella swap, si incaricherà di sincronizzare il contenuto di quel
segmento di memoria con quello del file mappato su di esso. Per questo motivo
si può parlare tanto di \textsl{file mappato in memoria}, quanto di
\textsl{memoria mappata su file}.
-\begin{figure}[htb]
- \centering
- \includegraphics[width=14cm]{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}
-
L'uso del \textit{memory-mapping} 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, poiché questi potranno essere
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,\index{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
+Infatti, dato che l'accesso è fatto direttamente attraverso la
+\index{memoria~virtuale} 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.
privata cui solo il processo chiamante ha
accesso. Le modifiche sono mantenute attraverso
il meccanismo del \textit{copy on
- write}\itindex{copy~on~write} e
+ write} \itindex{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 \const{MAP\_SHARED}. \\
\const{MAP\_DENYWRITE} & In Linux viene ignorato per evitare
- \textit{DoS}\itindex{Denial~of~Service~(DoS)}
+ \textit{DoS} \itindex{Denial~of~Service~(DoS)}
(veniva usato per segnalare che tentativi di
scrittura sul file dovevano fallire con
\errcode{ETXTBSY}).\\
\const{MAP\_EXECUTABLE}& Ignorato. \\
\const{MAP\_NORESERVE} & Si usa con \const{MAP\_PRIVATE}. Non riserva
delle pagine di swap ad uso del meccanismo del
- \textit{copy on write}\itindex{copy~on~write}
+ \textit{copy on write} \itindex{copy~on~write}
per mantenere le
modifiche fatte alla regione mappata, in
questo caso dopo una scrittura, se non c'è più
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 meccanismo della memoria
-virtuale.\index{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
-(\const{SIGSEGV}), dato che i permessi sul segmento di memoria relativo non
-consentono questo tipo di accesso.
+tutto quanto è comunque basato sul meccanismo della \index{memoria~virtuale}
+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 (\const{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\index{paginazione}, la mappatura in memoria non può che essere
+paginazione \index{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.
+effettive del file o della sezione che si vuole mappare.
\footnotetext[20]{Dato che tutti faranno riferimento alle stesse pagine di
memoria.}
output sul file.
In tutti questi casi il \textit{file locking} è la tecnica che permette di
-evitare le \textit{race condition}\itindex{race~condition}, attraverso una
+evitare le \textit{race condition} \itindex{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.
\item[\errcode{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}\itindex{deadlock}. Non è garantito che il sistema
+ \itindex{deadlock} \textit{deadlock}. Non è garantito che il sistema
riconosca sempre questa situazione.
\item[\errcode{EINTR}] La funzione è stata interrotta da un segnale prima
di poter acquisire un lock.
\begin{figure}[htb]
\centering \includegraphics[width=9cm]{img/file_lock_dead}
- \caption{Schema di una situazione di \textit{deadlock}\itindex{deadlock}.}
+ \caption{Schema di una situazione di \itindex{deadlock} \textit{deadlock}.}
\label{fig:file_flock_dead}
\end{figure}
del processo 2; il processo 1 si bloccherà fintanto che il processo 2 non
rilasci il blocco. Ma cosa accade se il processo 2 nel frattempo tenta a sua
volta di ottenere un lock sulla regione A? Questa è una tipica situazione che
-porta ad un \textit{deadlock}\itindex{deadlock}, dato che a quel punto anche
+porta ad un \itindex{deadlock} \textit{deadlock}, dato che a quel punto anche
il processo 2 si bloccherebbe, e niente potrebbe sbloccare l'altro processo.
Per questo motivo il kernel si incarica di rilevare situazioni di questo tipo,
ed impedirle restituendo un errore di \errcode{EDEADLK} alla funzione che
-cerca di acquisire un lock che porterebbe ad un \textit{deadlock}.
+cerca di acquisire un lock che porterebbe ad un \itindex{deadlock}
+\textit{deadlock}.
\begin{figure}[!bht]
\centering \includegraphics[width=13cm]{img/file_posix_lock}
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 \const{FL\_POSIX} ed il campo \var{fl\_file} non viene
- usato.} il lock è sempre associato all'inode\index{inode}, solo che in
+ usato.} il lock è sempre associato \index{inode} all'inode, solo che in
questo caso la titolarità non viene identificata con il riferimento ad una
voce nella \itindex{file~table} \textit{file table}, ma con il valore del
\acr{pid} del processo.
soltanto quando si chiama \func{mmap} con l'opzione \const{MAP\_SHARED} (nel
qual caso la funzione fallisce con il solito \errcode{EAGAIN}) che comporta la
possibilità di modificare il file.
-\index{file!locking|)}
-\itindend{mandatory~locking|(}
-
+\index{file!locking|)}
+\itindend{mandatory~locking|(}
-%%% Local Variables:
-%%% mode: latex
-%%% TeX-master: "gapil"
-%%% End:
% LocalWords: dell'I locking multiplexing cap dell' sez system call socket BSD
% LocalWords: descriptor client deadlock NONBLOCK EAGAIN polling select kernel
% LocalWords: flock shared exclusive operation dup inode linked NFS cmd ENOLCK
% LocalWords: EDEADLK whence SEEK CUR type pid GETLK SETLK SETLKW all'inode HP
% LocalWords: switch bsd lockf mandatory SVr sgid group root mount mand TRUNC
-% LocalWords: SVID UX Documentation sendfile
+% LocalWords: SVID UX Documentation sendfile dnotify inotify NdA
+
+
+%%% Local Variables:
+%%% mode: latex
+%%% TeX-master: "gapil"
+%%% End: