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}.
+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 è
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}''.
+\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
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
\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
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
\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 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=4cm]{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}
\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
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