From 840a5e76c710247e4ce8f0fff74acf30dca2425b Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Fri, 1 Jan 2010 22:48:24 +0000 Subject: [PATCH] Aggiunte varie e correzioni --- fileadv.tex | 126 ++++++++++++++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 52 deletions(-) diff --git a/fileadv.tex b/fileadv.tex index 117d9b9..9724919 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -3878,19 +3878,24 @@ ma si perder Si tenga presente infine che queste funzioni operano sui file con l'interfaccia dei file descriptor, e non è consigliabile mescolarle con -l'interfaccia classica dei \textit{file stream}; a causa delle bufferizzazioni -interne di quest'ultima infatti si potrebbero avere risultati indefiniti e non -corrispondenti a quanto aspettato. +l'interfaccia classica dei \textit{file stream} di +cap.~\ref{cha:files_std_interface}; a causa delle bufferizzazioni interne di +quest'ultima infatti si potrebbero avere risultati indefiniti e non +corrispondenti a quanto aspettato. Come per le normali operazioni di lettura e scrittura, anche per l'\textsl{I/O vettorizzato} si pone il problema di poter effettuare le operazioni in -maniera atomica a partire da un certa posizione sul file, così da evitare -eventuali \itindex{race~condition} \textit{race conditions} in caso di -combinazione con l'uso di \func{lseek}. Per questo motivo a partire dal kernel -2.6.30 sono state introdotte anche per l'\textsl{I/O vettorizzato} le analoghe -delle funzioni \func{pread} e \func{pwrite} (vedi sez.~\ref{sec:file_read} e -\ref{sec:file_write}); le due funzioni sono \funcd{preadv} e \func{pwritev} ed -i rispettivi prototipi sono: +maniera atomica a partire da un certa posizione sul file. Per questo motivo a +partire dal kernel 2.6.30 sono state introdotte anche per l'\textsl{I/O + vettorizzato} le analoghe delle funzioni \func{pread} e \func{pwrite} (vedi +sez.~\ref{sec:file_read} e \ref{sec:file_write}); le due funzioni sono +\funcd{preadv} e \func{pwritev} ed i rispettivi prototipi sono:\footnote{le + due funzioni sono analoghe alle omonime presenti in BSD; le \textit{system + call} usate da Linux (introdotte a partire dalla versione 2.6.30) + utilizzano degli argomenti diversi per problemi collegati al formato a 64 + bit dell'argomento \param{offset}, che varia a seconda delle architetture, + ma queste differenze vengono gestite dalle funzioni di librerie di libreria + che mantengono l'interfaccia delle analoghe tratte da BSD.} \begin{functions} \headdecl{sys/uio.h} @@ -3902,8 +3907,10 @@ i rispettivi prototipi sono: Eseguono una lettura o una scrittura vettorizzata a partire da una data posizione sul file. - \bodydesc{Le funzioni hanno gli stessi valori di ritorno e gli stessi errori - delle corrispondenti \func{readv} e \func{writev} a cui si può aggiungere: + \bodydesc{Le funzioni hanno gli stessi valori di ritorno delle + corrispondenti \func{readv} e \func{writev}; anche gli eventuali errori + sono gli stessi già visti in precedenza, ma ad essi si possono aggiungere + per \var{errno} anche i valori: \begin{errlist} \item[\errcode{EOVERFLOW}] \param{offset} ha un valore che non può essere usato come \ctyp{off\_t}. @@ -3912,8 +3919,20 @@ i rispettivi prototipi sono: } \end{functions} -% TODO preadv e pwritev inserite nel kernel 2.6.30, vedi -% http://lwn.net/Articles/326818/ +Le due funzioni eseguono rispettivamente una lettura o una scrittura +vettorizzata a partire dalla posizione \param{offset} sul file indicato +da \param{fd}, la posizione corrente sul file, come vista da eventuali altri +processi che vi facciano riferimento, non viene alterata. A parte la presenza +dell'ulteriore argomento il comportamento delle funzioni è identico alle +precedenti \func{readv} e \func{writev}. + +Con l'uso di queste funzioni si possono evitare eventuali +\itindex{race~condition} \textit{race conditions} quando si deve eseguire la +una operazione di lettura e scrittura vettorizzata a partire da una certa +posizione su un file, mentre al contempo si possono avere in concorrenza +processi che utilizzano lo stesso file descriptor (si ricordi quanto visto in +sez.~\ref{sec:file_adv_func}) con delle chiamate a \func{lseek}. + \subsection{L'I/O diretto fra file descriptor: \func{sendfile} e @@ -3933,15 +3952,15 @@ efficiente mantenere tutto in kernel space. Tratteremo in questa sezione alcune funzioni specialistiche che permettono di ottimizzare le prestazioni in questo tipo di situazioni. -La prima funzione che si pone l'obiettivo di ottimizzare il trasferimento dei -dati fra due file descriptor è \funcd{sendfile};\footnote{la funzione è stata +La prima funzione che è stata ideata per ottimizzare il trasferimento dei dati +fra due file descriptor è \func{sendfile};\footnote{la funzione è stata introdotta con i kernel della serie 2.2, e disponibile dalle \acr{glibc} 2.1.} la funzione è presente in diverse versioni di Unix,\footnote{la si ritrova ad esempio in FreeBSD, HPUX ed altri Unix.} ma non è presente né in POSIX.1-2001 né in altri standard,\footnote{pertanto si eviti di utilizzarla se si devono scrivere programmi portabili.} per cui per essa vengono -utilizzati prototipi e semantiche differenti; nel caso di Linux il suo -prototipo è: +utilizzati prototipi e semantiche differenti; nel caso di Linux il prototipo +di \funcd{sendfile} è: \begin{functions} \headdecl{sys/sendfile.h} @@ -3970,7 +3989,7 @@ prototipo La funzione copia direttamente \param{count} byte dal file descriptor \param{in\_fd} al file descriptor \param{out\_fd}; in caso di successo funzione ritorna il numero di byte effettivamente copiati da \param{in\_fd} a -\param{out\_fd} o $-1$ in caso di errore, come le ordinarie \func{read} e +\param{out\_fd} o $-1$ in caso di errore; come le ordinarie \func{read} e \func{write} questo valore può essere inferiore a quanto richiesto con \param{count}. @@ -4018,19 +4037,16 @@ non casi l'uso di \func{sendfile} darà luogo ad un errore di \errcode{EINVAL}. Nonostante ci possano essere casi in cui \func{sendfile} non migliora le -prestazioni, le motivazioni addotte non convincono del tutto e resta il dubbio -se la scelta di disabilitarla sempre per il trasferimento di dati fra file di -dati sia davvero corretta. Se ci sono peggioramenti di prestazioni infatti si -può sempre fare ricorso all'uso successivo di, ma lasciare a disposizione la -funzione consentirebbe se non altro, anche in assenza di guadagni di -prestazioni, di semplificare la gestione della copia dei dati fra file, -evitando di dover gestire l'allocazione di un buffer temporaneo per il loro -trasferimento; inoltre si avrebbe comunque il vantaggio di evitare inutili -trasferimenti di dati da kernel space a user space e viceversa. - -Questo dubbio si può comunque ritenere superato con l'introduzione, avvenuto a -partire dal kernel 2.6.17, della nuova system call \func{splice}. Lo scopo di -questa funzione è quello di fornire un meccanismo generico per il +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. + +Questo dubbio si può comunque ritenere superato con l'introduzione, avvenuta a +partire dal kernel 2.6.17, della nuova \textit{system call} \func{splice}. Lo +scopo di questa funzione è quello di fornire un meccanismo generico per il trasferimento di dati da o verso un file utilizzando un buffer gestito internamente dal kernel. Descritta in questi termini \func{splice} sembra semplicemente un ``\textsl{dimezzamento}'' di \func{sendfile}.\footnote{nel @@ -4192,16 +4208,17 @@ descrizioni complete di tutti i valori possibili anche quando, come per \label{tab:splice_flag} \end{table} -\footnotetext{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 pipe o il buffer non corrisponda a pagine intere esse saranno - comunque copiate.} +\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 pipe o il buffer non corrisponda a pagine intere esse + saranno comunque copiate.} -\footnotetext{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[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 @@ -4307,7 +4324,8 @@ descriptor, le tratteremo qui. La prima funzione, \funcd{vmsplice}, è la più simile a \func{splice} e come indica il suo nome consente di trasferire i dati dalla memoria di un processo -verso una \textit{pipe}, il suo prototipo è: +(ad esempio per un file mappato in memoria) verso una \textit{pipe}, il suo +prototipo è: \begin{functions} \headdecl{fcntl.h} \headdecl{sys/uio.h} @@ -4331,21 +4349,25 @@ verso una \textit{pipe}, il suo prototipo } \end{functions} -La \textit{pipe} dovrà essere specificata tramite il file descriptor -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 suddetto vettore devono essere passate +La \textit{pipe} indicata da \param{fd} dovrà essere specificata tramite il +file descriptor 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 dovrà utilizzare un vettore di +strutture \struct{iovec} (vedi fig.~\ref{fig:file_iovec}), esattamente con gli +stessi criteri con cui le si usano per l'I/O vettorizzato, indicando gli +indirizzi e le dimensioni di ciascun segmento di memoria su cui si vuole +operare; 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}. 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 indirizzi del -processo, e scaricarle nella cache, così che queste possono essere utilizzate +\textit{pipe}. In generale, se i dati una volta creati non devono essere +riutilizzati (se cioè l'applicazione che chiama \func{vmsplice} non +modificherà più la memoria trasferita), è opportuno utilizzare +per \param{flag} il valore \const{SPLICE\_F\_GIFT}; questo fa sì che il 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. La seconda funzione aggiunta insieme a \func{splice} è \func{tee}, che deve il -- 2.30.2