X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileadv.tex;h=c3be626d21908e1b90ee2b69b2771e306f369b50;hp=9437fdbf8b8e40634c2ddbe9aca840bf3b80de3e;hb=0c4a9ed958f4797e1cf4dc90e0c0358e302956f5;hpb=ff82508f36245b117cc70a41204264942cca9288 diff --git a/fileadv.tex b/fileadv.tex index 9437fdb..c3be626 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -2762,8 +2762,8 @@ funzionalità che serve soltanto in alcuni casi particolari. Dato che all'origine di Unix i soli programmi che potevano avere una tale esigenza erano i demoni, attenendosi a uno dei criteri base della progettazione, che era di far fare al kernel solo le operazioni strettamente necessarie e -lasciare tutto il resto a processi in user space, non era stata prevista -nessuna funzionalità di notifica. +lasciare tutto il resto a processi in \textit{user space}, non era stata +prevista nessuna funzionalità di notifica. Visto però il crescente interesse nei confronti di una funzionalità di questo tipo, che è molto richiesta specialmente nello sviluppo dei programmi ad @@ -3513,11 +3513,11 @@ dedicate per la lettura e la scrittura dei file, completamente separate 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 -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 +implementata sia direttamente nel kernel che in \textit{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 \textit{user space}, ed è accessibile linkando i programmi con la libreria \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. @@ -4596,12 +4596,12 @@ L'indicazione viene espressa dall'argomento \param{advice} che deve essere specificato con uno dei valori riportati in tab.~\ref{tab:madvise_advice_values}; si tenga presente che i valori indicati nella seconda parte della tabella sono specifici di Linux e non sono previsti -dallo standard POSIX.1b. -La funzione non ha, tranne il caso di \const{MADV\_DONTFORK}, nessun effetto -sul comportamento di un programma, ma può influenzarne le prestazioni fornendo -al kernel indicazioni sulle esigenze dello stesso, così che sia possibile -scegliere le opportune strategie per la gestione del \itindex{read-ahead} -\textit{read-ahead} e del caching dei dati. +dallo standard POSIX.1b. La funzione non ha, tranne il caso di +\const{MADV\_DONTFORK}, nessun effetto sul comportamento di un programma, ma +può influenzarne le prestazioni fornendo al kernel indicazioni sulle esigenze +dello stesso, così che sia possibile scegliere le opportune strategie per la +gestione del \textit{read-ahead} (vedi sez.~\ref{sec:file_fadvise}) e del +caching dei dati. \begin{table}[!htb] \centering @@ -4979,16 +4979,16 @@ Fino ai kernel della serie 2.4 la funzione era utilizzabile su un qualunque file descriptor, e permetteva di sostituire la invocazione successiva di una \func{read} e una \func{write} (e l'allocazione del relativo buffer) con una sola chiamata a \funcd{sendfile}. In questo modo si poteva diminuire il numero -di chiamate al sistema e risparmiare in trasferimenti di dati da kernel space -a user space e viceversa. La massima utilità della funzione si ottiene -comunque per il trasferimento di dati da un file su disco ad un socket di -rete,\footnote{questo è il caso classico del lavoro eseguito da un server web, - ed infatti Apache ha una opzione per il supporto esplicito di questa - funzione.} dato che in questo caso diventa possibile effettuare il -trasferimento diretto via DMA dal controller del disco alla scheda di rete, -senza neanche allocare un buffer nel kernel (il meccanismo è detto -\textit{zerocopy} in quanto i dati non vengono mai copiati dal kernel, che si -limita a programmare solo le operazioni di lettura e scrittura via DMA) +di chiamate al sistema e risparmiare in trasferimenti di dati da +\textit{kernel space} a \textit{user space} e viceversa. La massima utilità +della funzione si ottiene comunque per il trasferimento di dati da un file su +disco ad un socket di rete,\footnote{questo è il caso classico del lavoro + eseguito da un server web, ed infatti Apache ha una opzione per il supporto + esplicito di questa funzione.} dato che in questo caso diventa possibile +effettuare il trasferimento diretto via DMA dal controller del disco alla +scheda di rete, senza neanche allocare un buffer nel kernel (il meccanismo è +detto \textit{zerocopy} in quanto i dati non vengono mai copiati dal kernel, +che si limita a programmare solo le operazioni di lettura e scrittura via DMA) ottenendo la massima efficienza possibile senza pesare neanche sul processore. In seguito però ci si accorse che, fatta eccezione per il trasferimento @@ -4997,19 +4997,27 @@ significativi delle prestazioni rispetto all'uso in sequenza di \func{read} e \func{write}. Nel caso generico infatti il kernel deve comunque allocare un buffer ed effettuare la copia dei dati, e in tal caso spesso il guadagno ottenibile nel ridurre il numero di chiamate al sistema non compensa le -ottimizzazioni che possono essere fatte da una applicazione in user space che -ha una conoscenza diretta su come questi sono strutturati, per cui 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 - \url{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 casi l'uso -di \func{sendfile} da luogo ad un errore di \errcode{EINVAL}. A partire dal -kernel 2.6.33 però la restrizione su \param{out\_fd} è stata rimossa e questo -può essere un file qualunque, rimane però quella di non poter usare un socket -per \param{in\_fd}. +ottimizzazioni che possono essere fatte da una applicazione in \textit{user + space} che ha una conoscenza diretta su come questi sono strutturati, per +cui 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 \url{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 +casi l'uso di \func{sendfile} da luogo ad un errore di \errcode{EINVAL}. + +Nonostante ci possano essere casi in cui \func{sendfile} non migliora le +prestazioni, resta il dubbio se la scelta di disabilitarla sempre per il +trasferimento fra file di dati sia davvero corretta. Se ci sono peggioramenti +di prestazioni infatti si può sempre fare ricorso al metodo ordinario, ma +lasciare a disposizione la funzione consentirebbe se non altro di semplificare +la gestione della copia dei dati fra file, evitando di dover gestire +l'allocazione di un buffer temporaneo per il loro trasferimento. Comunque a +partire dal kernel 2.6.33 la restrizione su \param{out\_fd} è stata rimossa e +questo può essere un file qualunque, rimane però quella di non poter usare un +socket per \param{in\_fd}. A partire dal kernel 2.6.17 come alternativa a \func{sendfile} è disponibile la nuova \textit{system call} \func{splice}. Lo scopo di questa funzione è @@ -5024,7 +5032,7 @@ caso si dovrebbe eseguire con due chiamate a \func{splice}. In realtà le due \textit{system call} sono profondamente 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.} + mantenendo disponibile la stessa interfaccia verso l'\textit{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, @@ -5042,32 +5050,32 @@ 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 \textit{kernel space}. In questo caso il cuore della funzione (e delle affini \func{vmsplice} e \func{tee}, che tratteremo più -avanti) è appunto l'uso di un buffer in kernel space, e questo è anche quello -che ne ha semplificato l'adozione, perché l'infrastruttura per la gestione di -un tale buffer è presente fin dagli albori di Unix per la realizzazione delle -\textit{pipe} (vedi sez.~\ref{sec:ipc_unix}). Dal punto di vista concettuale -allora \func{splice} non è altro che una diversa interfaccia (rispetto alle -\textit{pipe}) con cui utilizzare in user space l'oggetto ``\textsl{buffer in - kernel space}''. +avanti) è appunto l'uso di un buffer in \textit{kernel space}, e questo è +anche quello che ne ha semplificato l'adozione, perché l'infrastruttura per la +gestione di un tale buffer è presente fin dagli albori di Unix per la +realizzazione delle \textit{pipe} (vedi sez.~\ref{sec:ipc_unix}). Dal punto di +vista concettuale allora \func{splice} non è altro che una diversa interfaccia +(rispetto alle \textit{pipe}) con cui utilizzare in \textit{user space} +l'oggetto ``\textsl{buffer in kernel space}''. Così se per una \textit{pipe} o una \textit{fifo} il buffer viene utilizzato come area di memoria (vedi fig.~\ref{fig:ipc_pipe_singular}) dove appoggiare i dati che vengono trasferiti da un capo all'altro della stessa per creare un meccanismo di comunicazione fra processi, nel caso di \func{splice} il buffer viene usato o come fonte dei dati che saranno scritti su un file, o come -destinazione dei dati che vengono letti da un file. La funzione \funcd{splice} -fornisce quindi una interfaccia generica che consente di trasferire dati da un -buffer ad un file o viceversa; il suo prototipo, accessibile solo dopo aver -definito la macro \macro{\_GNU\_SOURCE},\footnote{si ricordi che questa +destinazione dei dati che vengono letti da un file. La funzione fornisce +quindi una interfaccia generica che consente di trasferire dati da un buffer +ad un file o viceversa; il prototipo di \funcd{splice}, accessibile solo dopo +aver definito la macro \macro{\_GNU\_SOURCE},\footnote{si ricordi che questa funzione non è contemplata da nessuno standard, è presente solo su Linux, e pertanto deve essere evitata se si vogliono scrivere programmi portabili.} è il seguente: - \begin{funcproto}{ \fhead{fcntl.h} \fdecl{long splice(int fd\_in, off\_t *off\_in, int fd\_out, off\_t - *off\_out, size\_t len, unsigned int flags)} + *off\_out, size\_t len, \\ +\phantom{long splice(}unsigned int flags)} \fdesc{Trasferisce dati da un file verso una \textit{pipe} o viceversa.} } @@ -5094,12 +5102,12 @@ definito la macro \macro{\_GNU\_SOURCE},\footnote{si ricordi che questa La funzione esegue un trasferimento di \param{len} byte dal file descriptor \param{fd\_in} al file descriptor \param{fd\_out}, uno dei quali deve essere -una \textit{pipe}; l'altro file descriptor può essere -qualunque.\footnote{questo significa che può essere, oltre che un file di - dati, anche un altra \textit{pipe}, o un socket.} Come accennato una -\textit{pipe} non è altro che un buffer in kernel space, per cui a seconda che -essa sia usata per \param{fd\_in} o \param{fd\_out} si avrà rispettivamente la -copia dei dati dal buffer al file o viceversa. +una \textit{pipe}; l'altro file descriptor può essere qualunque, questo +significa che può essere, oltre che un file di dati, anche un altra +\textit{pipe}, o un socket. Come accennato una \textit{pipe} non è altro che +un buffer in \textit{kernel space}, per cui a seconda che essa sia usata +per \param{fd\_in} o \param{fd\_out} si avrà rispettivamente la copia dei dati +dal buffer al file o viceversa. In caso di successo la funzione ritorna il numero di byte trasferiti, che può essere, come per le normali funzioni di lettura e scrittura su file, inferiore @@ -5141,8 +5149,15 @@ descrizioni complete di tutti i valori possibili anche quando, come per \hline \const{SPLICE\_F\_MOVE} & Suggerisce al kernel di spostare le pagine di memoria contenenti i dati invece di - copiarle;\footnotemark viene usato soltanto - da \func{splice}.\\ + copiarle: per una maggiore efficienza + \func{splice} usa quando possibile i + meccanismi della memoria virtuale per + eseguire i trasferimenti di dati. In maniera + analoga a \func{mmap}), qualora le pagine non + possano essere spostate dalla \textit{pipe} o + il buffer non corrisponda a pagine intere + esse saranno comunque copiate. Viene usato + soltanto da \func{splice}.\\ \const{SPLICE\_F\_NONBLOCK}& Richiede di operare in modalità non bloccante; questo flag influisce solo sulle operazioni che riguardano l'I/O da e verso la @@ -5156,13 +5171,24 @@ descrizioni complete di tutti i valori possibili anche quando, come per ulteriori dati in una \func{splice} successiva, questo è un suggerimento utile che viene usato quando \param{fd\_out} è un - socket.\footnotemark Attualmente viene usato - solo da \func{splice}, potrà essere + socket. Questa opzione consente di utilizzare + delle opzioni di gestione dei socket che + permettono di ottimizzare le trasmissioni via + rete (si veda la descrizione di + \const{TCP\_CORK} in + sez.~\ref{sec:sock_tcp_udp_options} e quella + di \const{MSG\_MORE} in + sez.~\ref{sec:net_sendmsg}). Attualmente + viene usato solo da \func{splice}, potrà essere implementato in futuro anche per \func{vmsplice} e \func{tee}.\\ \const{SPLICE\_F\_GIFT} & Le pagine di memoria utente sono - ``\textsl{donate}'' al kernel;\footnotemark - se impostato una seguente \func{splice} che + ``\textsl{donate}'' al kernel; questo + significa che la cache delle pagine e i dati + su disco potranno differire, e che + l'applicazione non potrà modificare + quest'area di memoria. + Se impostato una seguente \func{splice} che usa \const{SPLICE\_F\_MOVE} potrà spostare le pagine con successo, altrimenti esse dovranno essere copiate; per usare questa opzione i @@ -5178,50 +5204,30 @@ descrizioni complete di tutti i valori possibili anche quando, come per \label{tab:splice_flag} \end{table} -\footnotetext[120]{per una maggiore efficienza \func{splice} usa quando - possibile i meccanismi della memoria virtuale per eseguire i trasferimenti - di dati (in maniera analoga a \func{mmap}), qualora le pagine non possano - essere spostate dalla \textit{pipe} o il buffer non corrisponda a pagine - intere esse saranno comunque copiate.} - -\footnotetext[121]{questa opzione consente di utilizzare delle opzioni di - gestione dei socket che permettono di ottimizzare le trasmissioni via rete, - si veda la descrizione di \const{TCP\_CORK} in - sez.~\ref{sec:sock_tcp_udp_options} e quella di \const{MSG\_MORE} in - sez.~\ref{sec:net_sendmsg}.} - -\footnotetext{questo significa che la cache delle pagine e i dati su disco - potranno differire, e che l'applicazione non potrà modificare quest'area di - memoria.} Per capire meglio il funzionamento di \func{splice} vediamo un esempio con un semplice programma che usa questa funzione per effettuare la copia di un file -su un altro senza utilizzare buffer in user space. Il programma si chiama -\texttt{splicecp.c} ed il codice completo è disponibile coi sorgenti allegati -alla guida, il corpo principale del programma, che non contiene la sezione di -gestione delle opzioni e le funzioni di ausilio è riportato in -fig.~\ref{fig:splice_example}. - -Lo scopo del programma è quello di eseguire la copia dei con \func{splice}, -questo significa che si dovrà usare la funzione due volte, prima per leggere i -dati e poi per scriverli, appoggiandosi ad un buffer in kernel space (vale a -dire ad una \textit{pipe}); lo schema del flusso dei dati è illustrato in -fig.~\ref{fig:splicecp_data_flux}. +su un altro senza utilizzare buffer in \textit{user space}. Lo scopo del +programma è quello di eseguire la copia dei dati con \func{splice}, questo +significa che si dovrà usare la funzione due volte, prima per leggere i dati +dal file di ingresso e poi per scriverli su quello di uscita, appoggiandosi ad +una \textit{pipe}: lo schema del flusso dei dati è illustrato in +fig.~\ref{fig:splicecp_data_flux}. \begin{figure}[htb] \centering - \includegraphics[height=6cm]{img/splice_copy} + \includegraphics[height=3.5cm]{img/splice_copy} \caption{Struttura del flusso di dati usato dal programma \texttt{splicecp}.} \label{fig:splicecp_data_flux} \end{figure} -Una volta trattate le opzioni il programma verifica che restino -(\texttt{\small 13-16}) i due argomenti che indicano il file sorgente ed il -file destinazione. Il passo successivo è aprire il file sorgente -(\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. +Il programma si chiama \texttt{splicecp.c} ed il codice completo è disponibile +coi sorgenti allegati alla guida, il corpo principale del programma, che non +contiene la sezione di gestione delle opzioni, le funzioni di ausilio, le +aperture dei file di ingresso e di uscita passati come argomenti e quella +della \textit{pipe} intermedia, è riportato in fig.~\ref{fig:splice_example}. -\begin{figure}[!htbp] +\begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{\codesamplewidth} \includecodesample{listati/splicecp.c} @@ -5232,29 +5238,30 @@ infine (\texttt{\small 28-31}) la \textit{pipe} che verrà usata come buffer. \label{fig:splice_example} \end{figure} -Il ciclo principale (\texttt{\small 33-58}) inizia con la lettura dal file -sorgente tramite la prima \func{splice} (\texttt{\small 34-35}), in questo +Il ciclo principale (\texttt{\small 13-38}) inizia con la lettura dal file +sorgente tramite la prima \func{splice} (\texttt{\small 14-15}), in questo caso si è usato come primo argomento il file descriptor del file sorgente e -come terzo quello del capo in scrittura della \textit{pipe} (il funzionamento +come terzo quello del capo in scrittura della \textit{pipe}. Il funzionamento delle \textit{pipe} e l'uso della coppia di file descriptor ad esse associati è trattato in dettaglio in sez.~\ref{sec:ipc_unix}; non ne parleremo qui dato che nell'ottica dell'uso di \func{splice} questa operazione corrisponde -semplicemente al trasferimento dei dati dal file al buffer). +semplicemente al trasferimento dei dati dal file al buffer in \textit{kernel + space}. La lettura viene eseguita in blocchi pari alla dimensione specificata dall'opzione \texttt{-s} (il default è 4096); essendo in questo caso \func{splice} equivalente ad una \func{read} sul file, se ne controlla il valore di uscita in \var{nread} che indica quanti byte sono stati letti, se -detto valore è nullo (\texttt{\small 36}) questo significa che si è giunti +detto valore è nullo (\texttt{\small 16}) questo significa che si è giunti alla fine del file sorgente e pertanto l'operazione di copia è conclusa e si può uscire dal ciclo arrivando alla conclusione del programma (\texttt{\small - 59}). In caso di valore negativo (\texttt{\small 37-44}) c'è stato un -errore ed allora si ripete la lettura (\texttt{\small 36}) se questo è dovuto + 59}). In caso di valore negativo (\texttt{\small 17-24}) c'è stato un +errore ed allora si ripete la lettura (\texttt{\small 16}) se questo è dovuto ad una interruzione, o altrimenti si esce con un messaggio di errore -(\texttt{\small 41-43}). +(\texttt{\small 21-23}). Una volta completata con successo la lettura si avvia il ciclo di scrittura -(\texttt{\small 45-57}); questo inizia (\texttt{\small 46-47}) con la +(\texttt{\small 25-37}); questo inizia (\texttt{\small 26-27}) con la seconda \func{splice} che cerca di scrivere gli \var{nread} byte letti, si noti come in questo caso il primo argomento faccia di nuovo riferimento alla \textit{pipe} (in questo caso si usa il capo in lettura, per i dettagli si @@ -5264,8 +5271,8 @@ del file di destinazione. Di nuovo si controlla il numero di byte effettivamente scritti restituito in \var{nwrite} e in caso di errore al solito si ripete la scrittura se questo è dovuto a una interruzione o si esce con un messaggio negli altri casi -(\texttt{\small 48-55}). Infine si chiude il ciclo di scrittura sottraendo -(\texttt{\small 57}) il numero di byte scritti a quelli di cui è richiesta la +(\texttt{\small 28-35}). Infine si chiude il ciclo di scrittura sottraendo +(\texttt{\small 37}) il numero di byte scritti a quelli di cui è richiesta la scrittura,\footnote{in questa parte del ciclo \var{nread}, il cui valore iniziale è dato dai byte letti dalla precedente chiamata a \func{splice}, viene ad assumere il significato di byte da scrivere.} così che il ciclo di @@ -5275,49 +5282,47 @@ presenti sul buffer. Si noti come il programma sia concettualmente identico a quello che si sarebbe scritto usando \func{read} al posto della prima \func{splice} e \func{write} -al posto della seconda, utilizzando un buffer in user space per eseguire la -copia dei dati, solo che in questo caso non è stato necessario allocare nessun -buffer e non si è trasferito nessun dato in user space. - -Si noti anche come si sia usata la combinazione \texttt{SPLICE\_F\_MOVE | - SPLICE\_F\_MORE } per l'argomento \param{flags} di \func{splice}, infatti -anche se un valore nullo avrebbe dato gli stessi risultati, l'uso di questi -flag, che si ricordi servono solo a dare suggerimenti al kernel, permette in -genere di migliorare le prestazioni. +al posto della seconda, utilizzando un buffer in \textit{user space} per +eseguire la copia dei dati, solo che in questo caso non è stato necessario +allocare nessun buffer e non si è trasferito nessun dato in \textit{user + space}. Si noti anche come si sia usata la combinazione +\texttt{SPLICE\_F\_MOVE | SPLICE\_F\_MORE } per l'argomento \param{flags} di +\func{splice}, infatti anche se un valore nullo avrebbe dato gli stessi +risultati, l'uso di questi flag, che si ricordi servono solo a dare +suggerimenti al kernel, permette in genere di migliorare le prestazioni. Come accennato con l'introduzione di \func{splice} sono state realizzate anche altre due \textit{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 trasferimento dati fra file +trasferimento di dati attraverso un buffer in \textit{kernel space}; benché +queste non attengono strettamente ad operazioni di trasferimento dati fra file descriptor, le tratteremo qui, essendo strettamente correlate fra loro. La prima funzione, \funcd{vmsplice}, è la più simile a \func{splice} e come indica il suo nome consente di trasferire i dati dalla memoria virtuale di un processo (ad esempio per un file mappato in memoria) verso una \textit{pipe}; il suo prototipo è: -\begin{functions} - \headdecl{fcntl.h} - \headdecl{sys/uio.h} - \funcdecl{long vmsplice(int fd, const struct iovec *iov, unsigned long - nr\_segs, unsigned int flags)} - - Trasferisce dati dalla memoria di un processo verso una \textit{pipe}. +\begin{funcproto}{ +\fhead{fcntl.h} +\fhead{sys/uio.h} +\fdecl{long vmsplice(int fd, const struct iovec *iov, unsigned long nr\_segs,\\ +\phantom{long vmsplice(}unsigned int flags)} +\fdesc{Trasferisce dati dalla memoria di un processo verso una \textit{pipe}.} +} - \bodydesc{La funzione restituisce il numero di byte trasferiti in caso di - successo e $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno - dei valori: - \begin{errlist} +{La funzione ritorna il numero di byte trasferiti in caso di successo e $-1$ + per un errore, nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} \item[\errcode{EBADF}] o \param{fd} non è un file descriptor valido o non fa riferimento ad una \textit{pipe}. \item[\errcode{EINVAL}] si è usato un valore nullo per \param{nr\_segs} oppure si è usato \const{SPLICE\_F\_GIFT} ma la memoria non è allineata. \item[\errcode{ENOMEM}] non c'è memoria sufficiente per l'operazione richiesta. - \end{errlist} - } -\end{functions} + \end{errlist} +} +\end{funcproto} La \textit{pipe} indicata da \param{fd} dovrà essere specificata tramite il file descriptor corrispondente al suo capo aperto in scrittura (di nuovo si @@ -5342,31 +5347,31 @@ che queste possono essere utilizzate immediatamente senza necessità di eseguire una copia dei dati che contengono. La seconda funzione aggiunta insieme a \func{splice} è \func{tee}, che deve il -suo nome all'omonimo comando in user space, perché in analogia con questo -permette di duplicare i dati in ingresso su una \textit{pipe} su un'altra -\textit{pipe}. In sostanza, sempre nell'ottica della manipolazione dei dati su -dei buffer in kernel space, la funzione consente di eseguire una copia del -contenuto del buffer stesso. Il prototipo di \funcd{tee} è il seguente: -\begin{functions} - \headdecl{fcntl.h} +suo nome all'omonimo comando in \textit{user space}, perché in analogia con +questo permette di duplicare i dati in ingresso su una \textit{pipe} su +un'altra \textit{pipe}. In sostanza, sempre nell'ottica della manipolazione +dei dati su dei buffer in \textit{kernel space}, la funzione consente di +eseguire una copia del contenuto del buffer stesso. Il prototipo di +\funcd{tee} è il seguente: - \funcdecl{long tee(int fd\_in, int fd\_out, size\_t len, unsigned int +\begin{funcproto}{ +\fhead{fcntl.h} +\fdecl{long tee(int fd\_in, int fd\_out, size\_t len, unsigned int flags)} - - Duplica \param{len} byte da una \textit{pipe} ad un'altra. +\fdesc{Duplica i dati da una \textit{pipe} ad un'altra.} +} - \bodydesc{La funzione restituisce il numero di byte copiati in caso di - successo e $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno - dei valori: - \begin{errlist} +{La funzione ritorna restituisce il numero di byte copiati in caso di successo + e $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} \item[\errcode{EINVAL}] o uno fra \param{fd\_in} e \param{fd\_out} non fa riferimento ad una \textit{pipe} o entrambi fanno riferimento alla stessa \textit{pipe}. \item[\errcode{ENOMEM}] non c'è memoria sufficiente per l'operazione richiesta. - \end{errlist} - } -\end{functions} + \end{errlist} +} +\end{funcproto} La funzione copia \param{len} byte del contenuto di una \textit{pipe} su di un'altra; \param{fd\_in} deve essere il capo in lettura della \textit{pipe} @@ -5384,17 +5389,17 @@ funzione non bloccante. 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 e che il capo in scrittura della \textit{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 +stato chiuso; 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. +dello \textit{standard input} sullo \textit{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] +\begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{\codesamplewidth} \includecodesample{listati/tee.c} @@ -5405,28 +5410,27 @@ allegati alla guida. \label{fig:tee_example} \end{figure} -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}) corrispondano ad una \textit{pipe}. +La prima parte del programma, che si è omessa per brevità, si cura +semplicemente di controllare che sia stato fornito almeno un argomento (il +nome del file su cui scrivere), di aprirlo e che sia lo standard input che lo +standard output corrispondano ad una \textit{pipe}. -Il ciclo principale (\texttt{\small 37-58}) inizia con la chiamata a +Il ciclo principale (\texttt{\small 11-32}) inizia con la chiamata a \func{tee} che duplica il contenuto dello standard input sullo standard output -(\texttt{\small 39}), questa parte è del tutto analoga ad una lettura ed +(\texttt{\small 13}), questa parte è del tutto analoga ad una lettura ed infatti come nell'esempio di fig.~\ref{fig:splice_example} si controlla il valore di ritorno della funzione in \var{len}; se questo è nullo significa che -non ci sono più dati da leggere e si chiude il ciclo (\texttt{\small 40}), se +non ci sono più dati da leggere e si chiude il ciclo (\texttt{\small 14}), se è negativo c'è stato un errore, ed allora si ripete la chiamata se questo è -dovuto ad una interruzione (\texttt{\small 42-44}) o si stampa un messaggio -di errore e si esce negli altri casi (\texttt{\small 44-47}). - -Una volta completata la copia dei dati sullo standard output si possono -estrarre dalla standard input e scrivere sul file, di nuovo su usa un ciclo di -scrittura (\texttt{\small 50-58}) in cui si ripete una chiamata a -\func{splice} (\texttt{\small 51}) fintanto che non si sono scritti tutti i -\var{len} byte copiati in precedenza con \func{tee} (il funzionamento è -identico all'analogo ciclo di scrittura del precedente esempio di +dovuto ad una interruzione (\texttt{\small 15-48}) o si stampa un messaggio +di errore e si esce negli altri casi (\texttt{\small 18-21}). + +Una volta completata la copia dei dati sullo \textit{standard output} si +possono estrarre dallo \textit{standard input} e scrivere sul file, di nuovo +su usa un ciclo di scrittura (\texttt{\small 24-31}) in cui si ripete una +chiamata a \func{splice} (\texttt{\small 25}) fintanto che non si sono scritti +tutti i \var{len} byte copiati in precedenza con \func{tee} (il funzionamento +è identico all'analogo ciclo di scrittura del precedente esempio di fig.~\ref{fig:splice_example}). Infine una nota finale riguardo \func{splice}, \func{vmsplice} e \func{tee}: @@ -5467,29 +5471,29 @@ il loro accesso ai dati dei file e controllare la gestione del relativo \itindbeg{read-ahead} 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} +ordinaria dell'I/O su un file è \funcd{readahead} (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 è: - \funcdecl{ssize\_t readahead(int fd, off64\_t *offset, size\_t count)} - - Esegue una lettura preventiva del contenuto di un file in cache. +\begin{funcproto}{ +\fhead{fcntl.h} +\fdecl{ssize\_t readahead(int fd, off64\_t *offset, size\_t count)} +\fdesc{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} +{La funzione ritorna $0$ in caso di successo e $-1$ per un 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 \textit{pipe} o un socket). - \end{errlist} - } -\end{functions} + \end{errlist} +} +\end{funcproto} 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 @@ -5498,7 +5502,7 @@ virtuale ed il meccanismo della 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} vengono arrotondati di conseguenza. -La funzione estende quello che è un comportamento normale del kernel che +La funzione estende quello che è un comportamento normale del kernel che, quando si legge un file, aspettandosi che l'accesso prosegua, esegue sempre una lettura preventiva di una certa quantità di dati; questo meccanismo di lettura anticipata viene chiamato \textit{read-ahead}, da cui deriva il nome @@ -5518,35 +5522,38 @@ nelle operazioni successive. \itindend{read-ahead} Il concetto di \func{readahead} viene generalizzato nello standard -POSIX.1-2001 dalla funzione \func{posix\_fadvise},\footnote{anche se - l'argomento \param{len} è stato modificato da \type{size\_t} a \type{off\_t} - nella revisione POSIX.1-2003 TC5.} che consente di ``\textsl{avvisare}'' il +POSIX.1-2001 dalla funzione \func{posix\_fadvise} (anche se +l'argomento \param{len} è stato modificato da \type{size\_t} a \type{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 prototipo di \funcd{posix\_fadvise}, che è -disponibile soltanto se è stata definita la macro \macro{\_XOPEN\_SOURCE} ad -valore di almeno 600, è: -\begin{functions} - \headdecl{fcntl.h} +porzione di un file, così che esso possa provvedere le opportune +ottimizzazioni; il prototipo di \funcd{posix\_fadvise}\footnote{la funzione è + stata introdotta su Linux solo a partire dal kernel 2.5.60, ed è disponibile + soltanto se è stata definita la macro \macro{\_XOPEN\_SOURCE} ad valore di + almeno \texttt{600} o la macro \macro{\_POSIX\_C\_SOURCE} ad valore di + almeno \texttt{200112L}.} è: - \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} +\begin{funcproto}{ +\fhead{fcntl.h} +\fdecl{int posix\_fadvise(int fd, off\_t offset, off\_t len, int advice)} +\fdesc{Dichiara al kernel le future modalità di accesso ad un file.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un 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 \textit{pipe} o un socket). - \item[\errcode{ESPIPE}] previsto dallo standard se \param{fd} è una \textit{pipe} o - un socket (ma su Linux viene restituito \errcode{EINVAL}). - \end{errlist} - } -\end{functions} + \item[\errcode{ESPIPE}] previsto dallo standard se \param{fd} è una + \textit{pipe} o un socket (ma su Linux viene restituito + \errcode{EINVAL}). + \end{errlist} +} +\end{funcproto} La funzione dichiara al kernel le modalità con cui intende accedere alla regione del file indicato da \param{fd} che inizia alla posizione