Esempio di copia con {{{splice}}} e fine della trattazione della stessa.
[gapil.git] / fileadv.tex
index 14e10b8af985199c54470814e0862c08685d43b9..4761523154cd2904385bb04b0817431e1f6ab982 100644 (file)
@@ -3010,7 +3010,7 @@ definito la macro \macro{\_GNU\_SOURCE},\footnote{si ricordi che questa
   }
 \end{functions}
 
-La funzione esegue un trasferimento di \param{count} byte dal file descriptor
+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
@@ -3041,32 +3041,154 @@ Ovviamente soltanto uno di questi due argomenti, e pi
 fa riferimento al file descriptor non associato alla \textit{pipe}, può essere
 specificato come valore non nullo.
 
-Infine l'argomento \param{flag} consente di controllare alcune caratteristiche
-del funzionamento della funzione; il contenuto è una maschera binaria e deve
-essere specificato come OR aritmetico dei valori riportati in
-tab.~\ref{tab:splice_flag}.
-
+Infine l'argomento \param{flags} consente di controllare alcune
+caratteristiche del funzionamento della funzione; il contenuto è una maschera
+binaria e deve essere specificato come OR aritmetico dei valori riportati in
+tab.~\ref{tab:splice_flag}. Alcuni di questi valori vengono utilizzati anche
+dalle funzioni \func{vmslice} e \func{tee} per cui la tabella riporta le
+descrizioni complete di tutti i valori possibili anche quando, come per
+\const{SPLICE\_F\_GIFT}, questi non hanno effetto su \func{splice}.
 
 \begin{table}[htb]
   \centering
   \footnotesize
-  \begin{tabular}[c]{|l|p{8cm}|}
+  \begin{tabular}[c]{|l|p{10cm}|}
     \hline
     \textbf{Valore} & \textbf{Significato} \\
     \hline
     \hline
-    \const{SPLICE\_F\_MOVE}    & .\\
-    \const{SPLICE\_F\_NONBLOCK}& .\\
-    \const{SPLICE\_F\_MORE}    & .\\
-    \const{SPLICE\_F\_GIFT}    & .\\
+    \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}.\\ 
+    \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
+                                 \textit{pipe}. Nel caso di \func{splice}
+                                 questo significa che la funzione potrà
+                                 comunque bloccarsi nell'accesso agli altri
+                                 file descriptor (a meno che anch'essi non
+                                 siano stati aperti in modalità non
+                                 bloccante).\\
+    \const{SPLICE\_F\_MORE}    & Indica al kernel che ci sarà l'invio di
+                                 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
+                                 implementato in futuro anche per
+                                 \func{vmslice} 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
+                                 usa \const{SPLICE\_F\_MOVE} potrà spostare le 
+                                 pagine con successo, altrimenti esse dovranno
+                                 essere copiate; per usare questa opzione i
+                                 dati dovranno essere opportunamente allineati
+                                 in posizione ed in dimensione alle pagine di
+                                 memoria. Viene usato soltanto da
+                                 \func{vmsplice}.\\
     \hline
   \end{tabular}
   \caption{Le costanti che identificano i bit della maschera binaria
-    dell'argomento \param{flag} di \func{slice}, \func{vmslice} e \func{tee}.}
+    dell'argomento \param{flags} di \func{slice}, \func{vmslice} e \func{tee}.}
   \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 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{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}. 
+
+\begin{figure}[htb]
+  \centering
+  \includegraphics[height=6cm]{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.
+
+
+\begin{figure}[!htbp]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/splicecp.c}
+  \end{minipage}
+  \normalsize
+  \caption{Esempio di codice che usa \func{splice} per effettuare la copia di
+    un file.}
+  \label{fig:splice_example}
+\end{figure}
 
+Il ciclo principale (\texttt{\small 33--59}) inizia con la lettura dal file
+sorgente tramite la prima \func{splice} (\texttt{\small 34--35}), 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
+delle \textit{pipe} è trattato in dettaglio in sez.~\ref{sec:ipc_unix},
+nell'ottica dell'uso di \func{splice} questa operazione corrisponde
+semplicemente alla copia dei dati dal file al buffer).
+
+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
+nullo (\texttt{\small 36}) questo significa che si è giunti alla fine del file
+sorgente e pertanto l'operazione di copia è conclusa e si può uscire dal
+ciclo. In caso di valore negativo c'è stato un errore ed allora si ripete la
+lettura se questo è dovuto ad una interruzione, o si esce altrimenti
+(\texttt{\small 37--44}).
+
+Una volta completata con successo la lettura si avvia il ciclo di scrittura
+(\texttt{\small 45--58}); questo inizia (\texttt{\small 46--47}) con la
+seconda \func{splice} che cerca di scrivere gli \var{nread} byte letti, si
+noti come in questo caso il primo argomento sia il capo in lettura della
+\textit{pipe} ed il terzo il file descriptor del file di destinazione. 
+
+Di nuovo si controlla il numero di byte effettivamente scritti restituito in
+\var{nwrite} e se nullo (\texttt{\small 48}) si ripete la scrittura (in realtà
+questo non avverrà mai), in caso di errore (\texttt{\small 49--56}) al solito
+si ripete la scrittura se questo è dovuto a una interruzione o si esce con un
+messaggio negli altri casi. 
+
+Infine si chiude il ciclo di scrittura sottraendo (\texttt{\small 57}) il
+numero di byte scritti a quelli letti, così che il ciclo di scrittura venga
+ripetuto (\texttt{\small 58}) qualora la chiamata a \func{splice} non abbia
+esaurito tutti i dati 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 file, solo che in questo caso non è stato necessario allocare nessun
+buffer e non si è trasferito nessun dato in user space.
 
 
 % TODO documentare le funzioni tee e splice