X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileadv.tex;h=10c95887f221e68aaa456595f306210a9c945888;hp=206fb8e8aa38898aadf059a99b7f1dc09d0bb79c;hb=85e7b3ed7aafdb66a7feda150f68649915a5e85d;hpb=fc2954a94ffab07871f49e2432d5223f55840fbf diff --git a/fileadv.tex b/fileadv.tex index 206fb8e..10c9588 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -1,6 +1,6 @@ %% fileadv.tex %% -%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to +%% Copyright (C) 2000-2009 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", @@ -107,10 +107,10 @@ Il primo kernel unix-like ad introdurre una interfaccia per l'\textit{I/O descriptor (anche nullo) che sono attivi, 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 in uno + \item[\errcode{EBADF}] si è specificato un file descriptor sbagliato in uno degli insiemi. - \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale. - \item[\errcode{EINVAL}] Si è specificato per \param{ndfs} un valore negativo + \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale. + \item[\errcode{EINVAL}] si è specificato per \param{ndfs} un valore negativo o un valore non valido per \param{timeout}. \end{errlist} ed inoltre \errval{ENOMEM}. @@ -267,10 +267,10 @@ precedenti, ed inoltre aggiunge a \func{select} una nuova funzione descriptor (anche nullo) che sono attivi, 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 in uno + \item[\errcode{EBADF}] si è specificato un file descriptor sbagliato in uno degli insiemi. - \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale. - \item[\errcode{EINVAL}] Si è specificato per \param{ndfs} un valore negativo + \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale. + \item[\errcode{EINVAL}] si è specificato per \param{ndfs} un valore negativo o un valore non valido per \param{timeout}. \end{errlist} ed inoltre \errval{ENOMEM}.} @@ -350,10 +350,10 @@ cui prototipo in caso di successo, o 0 se c'è stato un timeout e -1 in caso di errore, ed in quest'ultimo caso \var{errno} assumerà uno dei valori: \begin{errlist} - \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato in uno + \item[\errcode{EBADF}] si è specificato un file descriptor sbagliato in uno degli insiemi. - \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale. - \item[\errcode{EINVAL}] Il valore di \param{nfds} eccede il limite + \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale. + \item[\errcode{EINVAL}] il valore di \param{nfds} eccede il limite \macro{RLIMIT\_NOFILE}. \end{errlist} ed inoltre \errval{EFAULT} e \errval{ENOMEM}.} @@ -496,10 +496,10 @@ prototipo in caso di successo, o 0 se c'è stato un timeout e -1 in caso di errore, ed in quest'ultimo caso \var{errno} assumerà uno dei valori: \begin{errlist} - \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato in uno + \item[\errcode{EBADF}] si è specificato un file descriptor sbagliato in uno degli insiemi. - \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale. - \item[\errcode{EINVAL}] Il valore di \param{nfds} eccede il limite + \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale. + \item[\errcode{EINVAL}] il valore di \param{nfds} eccede il limite \macro{RLIMIT\_NOFILE}. \end{errlist} ed inoltre \errval{EFAULT} e \errval{ENOMEM}.} @@ -699,7 +699,7 @@ indicare quale tipo di evento relativo ad \param{fd} si vuole che sia tenuto sotto controllo. L'argomento viene ignorato con l'operazione \const{EPOLL\_CTL\_DEL}.\footnote{fino al kernel 2.6.9 era comunque richiesto che questo fosse un puntatore valido, anche se poi veniva ignorato, a - partire dal 2.6.9 si può specificare anche anche un valore \texttt{NULL}.} + partire dal 2.6.9 si può specificare anche un valore \texttt{NULL}.} @@ -741,7 +741,7 @@ si usa come valore lo stesso \param{fd}. (analogo di \const{POLLIN}).\\ \const{EPOLLOUT} & Il file è pronto per le operazioni di scrittura (analogo di \const{POLLOUT}).\\ - \const{EPOLLRDHUP} & l'altro capo di un socket di tipo + \const{EPOLLRDHUP} & L'altro capo di un socket di tipo \const{SOCK\_STREAM} (vedi sez.~\ref{sec:sock_type}) ha chiuso la connessione o il capo in scrittura della stessa (vedi sez.~\ref{sec:TCP_shutdown}).\\ @@ -913,6 +913,8 @@ operazioni di I/O volute. \subsection{Il \textit{Signal driven I/O}} \label{sec:file_asyncronous_operation} +\itindbeg{signal~driven~I/O} + Abbiamo accennato in sez.~\ref{sec:file_open} che è possibile, attraverso l'uso del flag \const{O\_ASYNC},\footnote{l'uso del flag di \const{O\_ASYNC} e dei comandi \const{F\_SETOWN} e \const{F\_GETOWN} per \func{fcntl} è @@ -1001,6 +1003,9 @@ utilizzabili.\footnote{vale a dire impostare il contenuto di % TODO fare esempio che usa O_ASYNC +\itindend{signal~driven~I/O} + + \subsection{I meccanismi di notifica asincrona.} \label{sec:file_asyncronous_lease} @@ -1054,7 +1059,6 @@ questo \textit{lease breaker}, cerca di eseguire una \func{open} o una \func{truncate} sul file del quale l'\textit{holder} detiene il \textit{lease}. - La notifica avviene in maniera analoga a come illustrato in precedenza per l'uso di \const{O\_ASYNC}: di default viene inviato al \textit{lease holder} il segnale \const{SIGIO}, ma questo segnale può essere modificato usando il @@ -1248,7 +1252,7 @@ viene segnalata, ma poi (operazione che può essere molto onerosa quando una directory contiene un gran numero di file). Infine l'uso dei segnali come interfaccia di notifica comporta tutti i problemi di gestione visti in sez.~\ref{sec:sig_management} e -sez.~\ref{sec:sig_control}. Per tutta questa serie di motivi in generale +sez.~\ref{sec:sig_adv_control}. Per tutta questa serie di motivi in generale quella di \textit{dnotify} viene considerata una interfaccia di usabilità problematica. @@ -1300,9 +1304,12 @@ eliminato.\footnote{anzi, una delle capacit Inoltre trattandosi di un file descriptor a tutti gli effetti, esso potrà essere utilizzato come argomento per le funzioni \func{select} e \func{poll} e -con l'interfaccia di \textit{epoll}; siccome gli eventi vengono notificati -come dati disponibili in lettura, dette funzioni ritorneranno tutte le volte -che si avrà un evento di notifica. Così, invece di dover utilizzare i +con l'interfaccia di \textit{epoll};\footnote{ed a partire dal kernel 2.6.25 è + stato introdotto anche il supporto per il \itindex{signal~driven~I/O} + \texttt{signal-driven I/O} trattato in + sez.~\ref{sec:file_asyncronous_operation}.} siccome gli eventi vengono +notificati come dati disponibili in lettura, dette funzioni ritorneranno tutte +le volte che si avrà un evento di notifica. Così, invece di dover utilizzare i segnali,\footnote{considerati una pessima scelta dal punto di vista dell'interfaccia utente.} si potrà gestire l'osservazione degli eventi con una qualunque delle modalità di \textit{I/O multiplexing} illustrate in @@ -1734,11 +1741,6 @@ raggruppati in un solo evento. \index{file!inotify|)} -% TODO inserire anche eventfd (vedi http://lwn.net/Articles/233462/) -% e le restanti signalfd e timerfd introdotte con il 2.6.22 -% o trovargli un posto migliore - - \subsection{L'interfaccia POSIX per l'I/O asincrono} \label{sec:file_asyncronous_io} @@ -1762,11 +1764,12 @@ normalmente. In generale questa interfaccia è completamente astratta e può essere implementata sia direttamente nel kernel, che in user space attraverso l'uso -di thread. Per le versioni del kernel meno recenti esiste una implementazione -di questa interfaccia fornita delle \acr{glibc}, 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 direttamente nel kernel un nuovo layer per l'I/O asincrono. +di \itindex{thread} \textit{thread}. Per le versioni del kernel meno recenti +esiste una implementazione di questa interfaccia fornita delle \acr{glibc}, +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 direttamente nel kernel 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 @@ -1837,9 +1840,9 @@ quello che indica le modalit fig.~\ref{fig:sig_sigval}) come valore del campo \var{si\_value} di \struct{siginfo\_t}. \item[\const{SIGEV\_THREAD}] La notifica viene effettuata creando un nuovo - thread che esegue la funzione specificata da \var{sigev\_notify\_function} - con argomento \var{sigev\_value}, e con gli attributi specificati da - \var{sigev\_notify\_attribute}. + \itindex{thread} \textit{thread} che esegue la funzione specificata da + \var{sigev\_notify\_function} con argomento \var{sigev\_value}, e con gli + attributi specificati da \var{sigev\_notify\_attribute}. \end{basedescript} Le due funzioni base dell'interfaccia per l'I/O asincrono sono @@ -2230,14 +2233,15 @@ multiplo della dimensione di una pagina di 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 \itindex{page~table} \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 \const{SIGSEGV}.} da applicare al segmento di memoria e deve essere +Il valore dell'argomento \param{prot} indica la protezione\footnote{come + accennato in sez.~\ref{sec:proc_memory} 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 \itindex{page~table} \textit{page table} la mappatura sulle + pagine di memoria reale, ed le modalità di accesso (lettura, esecuzione, + scrittura); una loro violazione causa quella una \itindex{segment~violation} + \textit{segment violation}, e la relativa emissione del segnale + \const{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 tab.~\ref{tab:file_mmap_prot}; il valore specificato deve essere compatibile con la modalità di accesso con cui si è aperto il file. @@ -2296,9 +2300,9 @@ tab.~\ref{tab:file_mmap_flag}. un \const{SIGSEGV}.\\ \const{MAP\_LOCKED} & Se impostato impedisce lo swapping delle pagine mappate.\\ - \const{MAP\_GROWSDOWN} & Usato per gli \itindex{stack} stack. Indica - che la mappatura deve essere effettuata con gli - indirizzi crescenti verso il basso.\\ + \const{MAP\_GROWSDOWN} & Usato per gli \itindex{stack} \textit{stack}. + Indica che la mappatura deve essere effettuata + con gli indirizzi crescenti verso il basso.\\ \const{MAP\_ANONYMOUS} & La mappatura non è associata a nessun file. Gli argomenti \param{fd} e \param{offset} sono ignorati.\footnotemark\\ @@ -2356,7 +2360,7 @@ effettive del file o della sezione che si vuole mappare. \begin{figure}[!htb] \centering - \includegraphics[width=13cm]{img/mmap_boundary} + \includegraphics[height=6cm]{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} @@ -2399,7 +2403,7 @@ che sono utilizzabili solo con questa interfaccia. \begin{figure}[htb] \centering - \includegraphics[width=13cm]{img/mmap_exceed} + \includegraphics[height=6cm]{img/mmap_exceed} \caption{Schema della mappatura in memoria di file di dimensioni inferiori alla lunghezza richiesta.} \label{fig:file_mmap_exceed} @@ -2730,6 +2734,8 @@ mappatura che gi \itindend{memory~mapping} +% TODO documentare \func{madvise} + \subsection{I/O vettorizzato: \func{readv} e \func{writev}} \label{sec:file_multiple_io} @@ -2819,6 +2825,7 @@ ma si perder % TODO verificare cosa succederà a preadv e pwritev o alla nuova niovec % vedi http://lwn.net/Articles/164887/ +% inserite nel kernel 2.6.30, vedi http://lwn.net/Articles/326818/ \subsection{L'I/O diretto fra file descriptor: \func{sendfile} e \func{splice}} @@ -2915,7 +2922,7 @@ che anzi in certi casi si potevano avere anche dei peggioramenti. Questo ha portato, per i kernel della serie 2.6,\footnote{per alcune motivazioni di questa scelta si può fare riferimento a quanto illustrato da Linus Torvalds in \href{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html} - {\texttt{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}}.} + {\textsf{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}}.} alla decisione di consentire l'uso della funzione soltanto quando il file da cui si legge supporta le operazioni di \textit{memory mapping} (vale a dire non è un socket) e quello su cui si scrive è un socket; in tutti gli altri @@ -2942,13 +2949,15 @@ semplicemente un ``\textsl{dimezzamento}'' di \func{sendfile}.\footnote{nel sarebbe altro che la lettura degli stessi su un buffer seguita dalla relativa scrittura, cosa che in questo caso si dovrebbe eseguire con due chiamate a \func{splice}.} In realtà le due system call sono profondamente -diverse nel loro meccanismo di funzionamento; \func{sendfile} infatti, come -accennato, non necessita affatto di avere a disposizione un buffer interno, -perché esegue un trasferimento diretto di dati; questo la rende in generale -molto più efficiente, ma anche limitata nelle sue applicazioni, dato che -questo tipo di trasferimento è possibile solo in casi specifici.\footnote{e - nel caso di Linux questi sono anche solo quelli in cui essa può essere - effettivamente utilizzata.} +diverse nel loro meccanismo di funzionamento;\footnote{questo fino al kernel + 2.6.23, dove \func{sendfile} è stata reimplementata in termini di + \func{splice}, pur mantenendo disponibile la stessa interfaccia verso l'user + space.} \func{sendfile} infatti, come accennato, non necessita di avere a +disposizione un buffer interno, perché esegue un trasferimento diretto di +dati; questo la rende in generale più efficiente, ma anche limitata nelle sue +applicazioni, dato che questo tipo di trasferimento è possibile solo in casi +specifici.\footnote{e nel caso di Linux questi sono anche solo quelli in cui + essa può essere effettivamente utilizzata.} Il concetto che sta dietro a \func{splice} invece è diverso,\footnote{in realtà la proposta originale di Larry Mc Voy non differisce poi tanto negli @@ -2956,7 +2965,7 @@ Il concetto che sta dietro a \func{splice} invece stata la reinterpretazione che ne è stata fatta nell'implementazione su Linux realizzata da Jens Anxboe, concetti che sono esposti sinteticamente dallo stesso Linus Torvalds in \href{http://kerneltrap.org/node/6505} - {\texttt{http://kerneltrap.org/node/6505}}.} si tratta semplicemente di una + {\textsf{http://kerneltrap.org/node/6505}}.} si tratta semplicemente di una funzione che consente di fare in maniera del tutto generica delle operazioni di trasferimento di dati fra un file e un buffer gestito interamente in kernel space. In questo caso il cuore della funzione (e delle affini \func{vmsplice} @@ -3098,7 +3107,7 @@ descrizioni complete di tutti i valori possibili anche quando, come per meccanismi della memoria virtuale per eseguire i trasferimenti di dati (in maniera analoga a \func{mmap}), qualora le pagine non possano essere spostate dalla pipe o il buffer non corrisponda a pagine intere esse saranno - comunque comunque copiate.} + comunque copiate.} \footnotetext{questa opzione consente di utilizzare delle opzioni di gestione dei socket che permettono di ottimizzare le trasmissioni via rete, si veda @@ -3136,7 +3145,7 @@ file destinazione. Il passo successivo (\texttt{\small 18--22}), quello di destinazione (\texttt{\small 23--27}) ed infine (\texttt{\small 28--31}) la \textit{pipe} che verrà usata come buffer. -\begin{figure}[!htbp] +\begin{figure}[!phtb] \footnotesize \centering \begin{minipage}[c]{15cm} \includecodesample{listati/splicecp.c} @@ -3204,7 +3213,7 @@ Come accennato con l'introduzione di \func{splice} sono state realizzate altre due system call, \func{vmsplice} e \func{tee}, che utilizzano la stessa infrastruttura e si basano sullo stesso concetto di manipolazione e trasferimento di dati attraverso un buffer in kernel space; benché queste non -attengono strettamente ad operazioni di trasferiemento dati fra file +attengono strettamente ad operazioni di trasferimento dati fra file descriptor, le tratteremo qui. La prima funzione, \funcd{vmsplice}, è la più simile a \func{splice} e come @@ -3238,7 +3247,7 @@ corrispondente al suo capo aperto in scrittura (di nuovo si faccia riferimento a sez.~\ref{sec:ipc_unix}), mentre per indicare quali zone di memoria devono essere trasferita si deve utilizzare un vettore di strutture \struct{iovec} (vedi fig.~\ref{fig:file_iovec}), con le stesse con cui le si usano per l'I/O -vettorizzato; le dimensioni del sudetto vettore devono essere passate +vettorizzato; le dimensioni del suddetto vettore devono essere passate nell'argomento \param{nr\_segs} che indica il numero di segmenti di memoria da trasferire. Sia per il vettore che per il valore massimo di \param{nr\_segs} valgono le stesse limitazioni illustrate in sez.~\ref{sec:file_multiple_io}. @@ -3246,7 +3255,7 @@ valgono le stesse limitazioni illustrate in sez.~\ref{sec:file_multiple_io}. In caso di successo la funzione ritorna il numero di byte trasferiti sulla pipe, in generale (se i dati una volta creati non devono essere riutilizzati) è opportuno utilizzare il flag \const{SPLICE\_F\_GIFT}; questo fa si che il -kernel possa rimuovere le relative pagine dallo spazio degli indifizzi del +kernel possa rimuovere le relative pagine dallo spazio degli indirizzi del processo, e scaricarle nella cache, così che queste possono essere utilizzate immediatamente senza necessità di eseguire una copia dei dati che contengono. @@ -3287,16 +3296,16 @@ comportamento delle \textit{pipe} si veda sez.~\ref{sec:ipc_unix}). La funzione restituisce il numero di byte copiati da una \textit{pipe} all'altra (o $-1$ in caso di errore), un valore nullo indica che non ci sono -byte disponibili da copiare (la funzione in questo caso non si blocca, a -differenza di quanto avverrebbe per una normale lettura). Un esempio di -realizzazione del comando \texttt{tee} usando questa funzione, ripreso da -quello fornito nella pagina di manuale e dall'esempio allegato al pacth -originale, è riportato in fig.~\ref{fig:tee_example}. Il programma consente di -copiare il contenuto dello standard input sullo standard output e su un file -specificato come argomento, il codice completo si trova nel file -\texttt{tee.c} dei sorgenti allegati alla guida. - -% TODO verificare funzionamento, su Ubuntu Feisty non va... +byte disponibili da copiare e che il capo in scrittura della pipe è stato +chiuso.\footnote{si tenga presente però che questo non avviene se si è + impostato il flag \const{SPLICE\_F\_NONBLOCK}, in tal caso infatti si + avrebbe un errore di \errcode{EAGAIN}.} Un esempio di realizzazione del +comando \texttt{tee} usando questa funzione, ripreso da quello fornito nella +pagina di manuale e dall'esempio allegato al patch originale, è riportato in +fig.~\ref{fig:tee_example}. Il programma consente di copiare il contenuto +dello standard input sullo standard output e su un file specificato come +argomento, il codice completo si trova nel file \texttt{tee.c} dei sorgenti +allegati alla guida. \begin{figure}[!htbp] \footnotesize \centering @@ -3313,7 +3322,7 @@ La prima parte del programma (\texttt{\small 10--35}) si cura semplicemente di controllare (\texttt{\small 11--14}) che sia stato fornito almeno un argomento (il nome del file su cui scrivere), di aprirlo ({\small 15--19}) e che sia lo standard input (\texttt{\small 20--27}) che lo standard output (\texttt{\small - 28--35}) corripondano ad una \textit{pipe}. + 28--35}) corrispondano ad una \textit{pipe}. Il ciclo principale (\texttt{\small 37--58}) inizia con la chiamata a \func{tee} che duplica il contenuto dello standard input sullo standard output @@ -3340,12 +3349,13 @@ detto che i dati vengono effettivamente spostati o copiati, il kernel infatti realizza le \textit{pipe} come un insieme di puntatori\footnote{per essere precisi si tratta di un semplice buffer circolare, un buon articolo sul tema si trova su \href{http://lwn.net/Articles/118750/} - {\texttt{http://lwn.net/Articles/118750/}}.} alle pagine di memoria interna + {\textsf{http://lwn.net/Articles/118750/}}.} alle pagine di memoria interna che contengono i dati, per questo una volta che i dati sono presenti nella memoria del kernel tutto quello che viene fatto è creare i suddetti puntatori ed aumentare il numero di referenze; questo significa che anche con \func{tee} non viene mai copiato nessun byte, vengono semplicemente copiati i puntatori. +% TODO?? dal 2.6.25 splice ha ottenuto il supporto per la ricezione su rete \subsection{Gestione avanzata dell'accesso ai dati dei file} @@ -3367,15 +3377,205 @@ questa sezione una serie funzioni che consentono ai programmi di ottimizzare il loro accesso ai dati dei file e controllare la gestione del relativo \textit{caching}. +Una prima funzione che può essere utilizzata per modificare la gestione +ordinaria dell'I/O su un file è \funcd{readahead},\footnote{questa è una + funzione specifica di Linux, introdotta con il kernel 2.4.13, e non deve + essere usata se si vogliono scrivere programmi portabili.} che consente di +richiedere una lettura anticipata del contenuto dello stesso in cache, così +che le seguenti operazioni di lettura non debbano subire il ritardo dovuto +all'accesso al disco; il suo prototipo è: +\begin{functions} + \headdecl{fcntl.h} + + \funcdecl{ssize\_t readahead(int fd, off64\_t *offset, size\_t count)} + + Esegue una lettura preventiva del contenuto di un file in cache. + + \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[\errcode{EBADF}] l'argomento \param{fd} non è un file descriptor + valido o non è aperto in lettura. + \item[\errcode{EINVAL}] l'argomento \param{fd} si riferisce ad un tipo di + file che non supporta l'operazione (come una pipe o un socket). + \end{errlist} + } +\end{functions} + +La funzione richiede che venga letto in anticipo il contenuto del file +\param{fd} a partire dalla posizione \param{offset} e per un ammontare di +\param{count} byte, in modo da portarlo in cache. La funzione usa la +\index{memoria~virtuale} memoria virtuale ed il meccanismo della +\index{paginazione} paginazione per cui la lettura viene eseguita in blocchi +corrispondenti alle dimensioni delle pagine di memoria, ed i valori di +\param{offset} e \param{count} arrotondati di conseguenza. + +La funzione estende quello che è un comportamento normale del +kernel\footnote{per ottimizzare gli accessi al disco il kernel quando si legge + un file, aspettandosi che l'accesso prosegua, esegue sempre una lettura + anticipata di una certa quantità di dati; questo meccanismo viene chiamato + \textit{readahead}, da cui deriva il nome della funzione.} effettuando la +lettura in cache della sezione richiesta e bloccandosi fintanto che questa non +viene completata. La posizione corrente sul file non viene modificata ed +indipendentemente da quanto indicato con \param{count} la lettura dei dati si +interrompe una volta raggiunta la fine del file. + +Si può utilizzare questa funzione per velocizzare le operazioni di lettura +all'interno del programma tutte le volte che si conosce in anticipo quanti +dati saranno necessari in seguito. Si potrà così concentrare in un unico +momento (ad esempio in fase di inizializzazione) la lettura, così da ottenere +una migliore risposta nelle operazioni successive. + +Il concetto di \func{readahead} viene generalizzato nello standard +POSIX.1-2001 dalla funzione \funcd{posix\_fadvise},\footnote{anche se + l'argomento \param{len} è stato modificato da \ctyp{size\_t} a \ctyp{off\_t} + nella revisione POSIX.1-2003 TC5.} che consente di ``\textsl{avvisare}'' il +kernel sulle modalità con cui si intende accedere nel futuro ad una certa +porzione di un file,\footnote{la funzione però è stata introdotta su Linux + solo a partire dal kernel 2.5.60.} così che esso possa provvedere le +opportune ottimizzazioni; il suo prototipo, che può è disponibile solo se si +definisce la macro \macro{\_XOPEN\_SOURCE} ad almeno 600, è: +\begin{functions} + \headdecl{fcntl.h} + + \funcdecl{int posix\_fadvise(int fd, off\_t offset, off\_t len, int advice)} + + Dichiara al kernel le future modalità di accesso ad un file. + + \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[\errcode{EBADF}] l'argomento \param{fd} non è un file descriptor + valido. + \item[\errcode{EINVAL}] il valore di \param{advice} non è valido o + \param{fd} si riferisce ad un tipo di file che non supporta l'operazione + (come una pipe o un socket). + \item[\errcode{ESPIPE}] previsto dallo standard se \param{fd} è una pipe o + un socket (ma su Linux viene restituito \errcode{EINVAL}). + \end{errlist} + } +\end{functions} + +La funzione dichiara al kernel le modalità con cui intende accedere alla +regione del file indicato da \param{fd} che inizia alla posizione +\param{offset} e si estende per \param{len} byte. Se per \param{len} si usa un +valore nullo la regione coperta sarà da \param{offset} alla fine del +file.\footnote{questo è vero solo per le versioni più recenti, fino al kernel + 2.6.6 il valore nullo veniva interpretato letteralmente.} Le modalità sono +indicate dall'argomento \param{advice} che è una maschera binaria dei valori +illustrati in tab.~\ref{tab:posix_fadvise_flag}. Si tenga presente comunque +che la funzione dà soltanto un avvertimento, non esiste nessun vincolo per il +kernel, che utilizza semplicemente l'informazione. + +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{10cm}|} + \hline + \textbf{Valore} & \textbf{Significato} \\ + \hline + \hline + \const{POSIX\_FADV\_NORMAL} & Non ci sono avvisi specifici da fare + riguardo le modalità di accesso, il + comportamento sarà identico a quello che si + avrebbe senza nessun avviso.\\ + \const{POSIX\_FADV\_SEQUENTIAL}& L'applicazione si aspetta di accedere di + accedere ai dati specificati in maniera + sequenziale, a partire dalle posizioni più + basse.\\ + \const{POSIX\_FADV\_RANDOM} & I dati saranno letti in maniera + completamente causale.\\ + \const{POSIX\_FADV\_NOREUSE} & I dati saranno acceduti una sola volta.\\ + \const{POSIX\_FADV\_WILLNEED}& I dati saranno acceduti a breve.\\ + \const{POSIX\_FADV\_DONTNEED}& I dati non saranno acceduti a breve.\\ + \hline + \end{tabular} + \caption{Valori dei bit dell'argomento \param{advice} di + \func{posix\_fadvise} che indicano la modalità con cui si intende accedere + ad un file.} + \label{tab:posix_fadvise_flag} +\end{table} + +Anche \func{posix\_fadvise} si appoggia al sistema della memoria virtuale ed +al meccanismo standard del \textit{readahead} utilizzato dal kernel; in +particolare con \const{POSIX\_FADV\_SEQUENTIAL} si raddoppia la dimensione +dell'ammontare di dati letti preventivamente rispetto al default, aspettandosi +appunto una lettura sequenziale che li utilizzerà, mentre con +\const{POSIX\_FADV\_RANDOM} si disabilita del tutto il suddetto meccanismo, +dato che con un accesso del tutto casuale è inutile mettersi a leggere i dati +immediatamente successivi gli attuali; infine l'uso di +\const{POSIX\_FADV\_NORMAL} consente di riportarsi al comportamento di +default. + +Le due modalità \const{POSIX\_FADV\_NOREUSE} e \const{POSIX\_FADV\_WILLNEED} +danno invece inizio ad una lettura in cache della regione del file indicata. +La quantità di dati che verranno letti è ovviamente limitata in base al carico +che si viene a creare sul sistema della memoria virtuale, ma in genere una +lettura di qualche megabyte viene sempre soddisfatta (ed un valore superiore è +solo raramente di qualche utilità). In particolare l'uso di +\const{POSIX\_FADV\_WILLNEED} si può considerare l'equivalente POSIX di +\func{readahead}. + +Infine con \const{POSIX\_FADV\_DONTNEED} si dice al kernel di liberare le +pagine di cache occupate dai dati presenti nella regione di file indicata. +Questa è una indicazione utile che permette di alleggerire il carico sulla +cache, ed un programma può utilizzare periodicamente questa funzione per +liberare pagine di memoria da dati che non sono più utilizzati per far posto a +nuovi dati utili.\footnote{la pagina di manuale riporta l'esempio dello + streaming di file di grosse dimensioni, dove le pagine occupate dai dati già + inviati possono essere tranquillamente scartate.} + +Sia \func{posix\_fadvise} che \func{readahead} attengono alla ottimizzazione +dell'accesso in lettura; lo standard POSIX.1-2001 prevede anche una funzione +specifica per le operazioni di scrittura, \func{posix\_fallocate},\footnote{la + funzione è stata introdotta a partire dalle glibc 2.1.94.} che consente di +preallocare dello spazio disco per assicurarsi che una seguente scrittura non +fallisca, il suo prototipo, anch'esso disponibile solo se si definisce la +macro \macro{\_XOPEN\_SOURCE} ad almeno 600, è: +\begin{functions} + \headdecl{fcntl.h} + + \funcdecl{int posix\_fallocate(int fd, off\_t offset, off\_t len)} + + Richiede la allocazione di spazio disco per un file. + + \bodydesc{La funzione restituisce 0 in caso di successo e direttamente un + codice di errore, in caso di fallimento, in questo caso \var{errno} non + viene impostata, ma sarà restituito direttamente uno dei valori: + \begin{errlist} + \item[\errcode{EBADF}] l'argomento \param{fd} non è un file descriptor + valido o non è aperto in scrittura. + \item[\errcode{EINVAL}] o \param{offset} o \param{len} sono minori di + zero. + \item[\errcode{EFBIG}] il valore di (\param{offset} + \param{len}) eccede + la dimensione massima consentita per un file. + \item[\errcode{ENODEV}] l'argomento \param{fd} non fa riferimento ad un + file regolare. + \item[\errcode{ENOSPC}] non c'è sufficiente spazio disco per eseguire + l'operazione. + \item[\errcode{ESPIPE}] l'argomento \param{fd} è una pipe. + \end{errlist} + } +\end{functions} + +La funzione si assicura che venga allocato sufficiente spazio disco perché sia +possibile scrivere sul file indicato dall'argomento \param{fd} nella regione +che inizia dalla posizione \param{offset} e si estende per \param{len} byte; +se questa si estende oltre la fine del file le dimensioni di quest'ultimo +saranno incrementate di conseguenza. Dopo aver eseguito con successo la +funzione è garantito che una scrittura nella regione indicata non fallirà per +mancanza di spazio disco. +% TODO controllare la trattazione della nuova funzionalità di preallocazione % TODO documentare \func{posix\_fadvise} -% TODO documentare \func{readahead} % vedi http://insights.oetiker.ch/linux/fadvise.html % questo tread? http://www.ussg.iu.edu/hypermail/linux/kernel/0703.1/0032.html % TODO documentare \func{fallocate}, introdotta con il 2.6.23 % vedi http://lwn.net/Articles/226710/ e http://lwn.net/Articles/240571/ +% http://kernelnewbies.org/Linux_2_6_23 +% \func{fallocate} con il 2.6.25 supporta pure XFS %\subsection{L'utilizzo delle porte di I/O} @@ -4281,12 +4481,14 @@ possibilit % LocalWords: EPOLLHUP EPOLLET EPOLLONESHOT shot maxevents ctlv ALL DONT HPUX % LocalWords: FOLLOW ONESHOT ONLYDIR FreeBSD EIO caching sysctl instances name % LocalWords: watches IGNORED ISDIR OVERFLOW overflow UNMOUNT queued cookie ls -% LocalWords: NUL sizeof casting printevent nread limits sysconf SC wrapper +% LocalWords: NUL sizeof casting printevent nread limits sysconf SC wrapper Di % LocalWords: splice result argument DMA controller zerocopy Linus Larry Voy -% LocalWords: Jens Anxboe vmsplice seek ESPIPE GIFT TCP CORK MSG splicecp +% LocalWords: Jens Anxboe vmsplice seek ESPIPE GIFT TCP CORK MSG splicecp nr +% LocalWords: nwrite segs patch readahead posix fadvise TC advice FADV NORMAL %%% Local Variables: %%% mode: latex %%% TeX-master: "gapil" %%% End: +% LocalWords: SEQUENTIAL NOREUSE WILLNEED DONTNEED streaming fallocate EFBIG