Materiale su splice, ed esempio non funzionante
authorSimone Piccardi <piccardi@gnulinux.it>
Sat, 11 Aug 2007 19:06:11 +0000 (19:06 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Sat, 11 Aug 2007 19:06:11 +0000 (19:06 +0000)
fileadv.tex
img/pipe.dia
ipc.tex
sources/splicecp.c [new file with mode: 0644]

index 5fa13de21efd25ed84475cd07b761ef62077f965..1581fbb97b146a1b5fb07e75af4549b850fc0b84 100644 (file)
@@ -2732,7 +2732,7 @@ mappatura che gi
 
 
 
 
 
 
-\subsection{I/O vettorizzato}
+\subsection{I/O vettorizzato: \func{readv} e \func{writev}}
 \label{sec:file_multiple_io}
 
 Un caso abbastanza comune è quello in cui ci si trova a dover eseguire una
 \label{sec:file_multiple_io}
 
 Un caso abbastanza comune è quello in cui ci si trova a dover eseguire una
@@ -2913,8 +2913,8 @@ delle prestazioni rispetto all'uso in sequenza di \func{read} e \func{write},
   che possono essere fatte da una applicazione in user space che ha una
   maggiore conoscenza su come questi sono strutturati.} e che anzi in certi
 casi si avevano dei peggioramenti, questo ha portato alla
   che possono essere fatte da una applicazione in user space che ha una
   maggiore conoscenza su come questi sono strutturati.} e che anzi in certi
 casi si avevano dei peggioramenti, questo ha portato alla
-decisione\footnote{per le motivazioni di questa scelta si può fare riferimento
-  a quanto illustrato da Linus Torvalds in
+decisione\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}}.}
 di consentire l'uso della funzione soltanto quando il file da cui si legge
   \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}}.}
 di consentire l'uso della funzione soltanto quando il file da cui si legge
@@ -2924,20 +2924,62 @@ un errore di \errcode{EINVAL}.
 
 Nonostante i limiti illustrati resta comunque il dubbio se la scelta di
 disabilitare \func{sendfile} per il trasferimento di dati fra file di dati sia
 
 Nonostante i limiti illustrati resta comunque il dubbio se la scelta di
 disabilitare \func{sendfile} per il trasferimento di dati fra file di dati sia
-davvero corretta; la funzione infatti se non altro consente di semplificare
-l'interfaccia, evitando di dover gestire l'allocazione di un buffer temporaneo
-per i trasferimenti dei dati in tutti quei casi in cui non c'è necessità
-effettiva di fare controlli sugli stessi. Inoltre essa avrebbe comunque il
-vantaggio di evitare trasferimenti di dati da e verso l'user space.
+davvero corretta; la funzione infatti se non altro consentirebbe di
+semplificare l'interfaccia per la copia dei dati, evitando di dover gestire
+l'allocazione di un buffer temporaneo per il loro trasferimento in tutti quei
+casi in cui non c'è necessità di fare controlli sugli stessi.  Inoltre essa
+avrebbe comunque il vantaggio di evitare trasferimenti di dati da e verso
+l'user space.
+
+Il dubbio è stato rimosso con l'introduzione della system call
+\func{splice},\footnote{avvenuto a partire dal kernel 2.6.17.}  il cui scopo è
+appunto quello di fornire un meccanismo generico per il trasferimento di dati
+da o verso un file utilizzando un buffer intermedio gestito direttamente dal
+kernel. Lo scopo della funzione può sembrare lo stesso di \func{sendfile}, ma
+in realtà esse sono profondamente diverse nel loro meccanismo di
+funzionamento; \func{sendfile} infatti, come accennato, non necessita affatto
+(anzi nel caso di Linux viene sostanzialmente usata solo in questo caso) 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.
+
+Il concetto che sta dietro a \func{splice} invece è diverso,\footnote{in
+  realtà la proposta originale di Larry Mc Voy non ne differisce poi tanto,
+  quello che la rende davvero diversa è stata la reinterpretazione che ne è
+  stata fatta nell'implementazione su Linux realizzata da Jens Anxboe, di cui
+  si può trovare un buon riassunto in \href{http://kerneltrap.org/node/6505}
+  {\texttt{http://kerneltrap.org/node/6505}}.} si tratta semplicemente di una
+funzione che consente di fare delle operazioni di trasferimento dati da e
+verso un buffer interamente gestito in kernel space, in maniera del tutto
+generica. In questo caso il cuore della funzione (e delle affini
+\func{vmsplice} e \func{tee}, che tratteremo più avanti) è appunto il buffer
+in kernel space; questo è anche quello che ne ha semplificato
+l'adozione,\footnote{la funzione infatti non è definita in nessuno standard,
+  e, allo stato attuale è disponibile soltanto su Linux.} perché
+l'infrastruttura per la gestione di un buffer in kernel space è presente fin
+dagli albori di Unix per la realizzazione delle \textit{pipe} (tratteremo
+l'argomento in sez.~\ref{sec:ipc_unix}). Dal punto di vista concettuale allora
+\func{splice} non è che un'altra interfaccia con cui esporre in userspace
+l'oggetto \textsl{buffer in kernel space}.
+
+Così se per una \textit{pipe} o una \textit{fifo} il buffer viene utilizzato
+(come illustrato in fig.~\ref{fig:ipc_pipe_singular}) come area di memoria
+dove appoggiare i dati che vengono trasferiti da un capo all'altro della
+stessa, creando un meccanismo di comunicazione fra processi, nel caso di
+\func{splice} il buffer viene usato o come fonte dei dati che con saranno
+scritti su un file, o come destinazione dei dati che vengono letti da un file.
+
+
+
+
+
 
 
-Fino al 2.6.17 il problema 
 
 
 % TODO documentare le funzioni tee e splice
 % http://kerneltrap.org/node/6505 e http://lwn.net/Articles/178199/ e 
 % http://lwn.net/Articles/179492/
 % e http://en.wikipedia.org/wiki/Splice_(system_call)
 
 
 % TODO documentare le funzioni tee e splice
 % http://kerneltrap.org/node/6505 e http://lwn.net/Articles/178199/ e 
 % http://lwn.net/Articles/179492/
 % e http://en.wikipedia.org/wiki/Splice_(system_call)
-% e http://kerneltrap.org/node/6505
 
 
 
 
 
 
index 8be4c57d318eb0fbcb5b4427b36ce39d05bf3d9c..801cbc600211517c89f44a62641c6a71bb511673 100644 (file)
Binary files a/img/pipe.dia and b/img/pipe.dia differ
diff --git a/ipc.tex b/ipc.tex
index 6587147be3d2080830361b0e6ee7510b73441b71..75e8849f83943f159015a8e36e96d35968f7249b 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -66,8 +66,9 @@ La funzione restituisce la coppia di file descriptor nel vettore
 accennato concetto di funzionamento di una pipe è semplice: quello che si
 scrive nel file descriptor aperto in scrittura viene ripresentato tale e quale
 nel file descriptor aperto in lettura. I file descriptor infatti non sono
 accennato concetto di funzionamento di una pipe è semplice: quello che si
 scrive nel file descriptor aperto in scrittura viene ripresentato tale e quale
 nel file descriptor aperto in lettura. I file descriptor infatti non sono
-connessi a nessun file reale, ma ad un buffer nel kernel, la cui dimensione è
-specificata dal parametro di sistema \const{PIPE\_BUF}, (vedi
+connessi a nessun file reale, ma, come accennato in
+sez.~\ref{sec:file_sendfile_splice}, ad un buffer nel kernel, la cui
+dimensione è specificata dal parametro di sistema \const{PIPE\_BUF}, (vedi
 sez.~\ref{sec:sys_file_limits}). Lo schema di funzionamento di una pipe è
 illustrato in fig.~\ref{fig:ipc_pipe_singular}, in cui sono illustrati i due
 capi della pipe, associati a ciascun file descriptor, con le frecce che
 sez.~\ref{sec:sys_file_limits}). Lo schema di funzionamento di una pipe è
 illustrato in fig.~\ref{fig:ipc_pipe_singular}, in cui sono illustrati i due
 capi della pipe, associati a ciascun file descriptor, con le frecce che
diff --git a/sources/splicecp.c b/sources/splicecp.c
new file mode 100644 (file)
index 0000000..feda8e6
--- /dev/null
@@ -0,0 +1,150 @@
+/* splicecp.c
+ * 
+ * Copyright (C) 2007 Simone Piccardi
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/****************************************************************
+ *
+ * Program splicecp.c: 
+ * A sample program that copy a file using splice
+ *
+ * Author: Simone Piccardi
+ * Aug. 2007
+ *
+ ****************************************************************/
+/* 
+ * Include needed headers
+ */
+#define _GNU_SOURCE
+#include <fcntl.h>       /* file control functions */
+#include <unistd.h>      /* unix standard library */
+#include <stdlib.h>      /* C standard library */
+#include <errno.h>       /* error definitions and routines */
+#include <stdio.h>       /* standard I/O library */
+#include <string.h>      /* C strings library */
+#include <sys/stat.h>
+#include <sys/types.h>
+
+/* 
+ * Function and globals definitions
+ */
+void usage(void);  /* Help printing routine */
+
+/*
+ * Main program
+ */
+int main(int argc, char *argv[])
+{
+   /*
+    * Variables definition
+    */
+    int i;
+    int size = 4096;
+    int pipefd[2];
+    int in_fd, out_fd;
+    int nread, nwrite;
+    /*
+     * Input section: decode command line parameters 
+     * Use getopt function
+     */
+    opterr = 0;  /* don't want writing to stderr */
+    while ( (i = getopt(argc, argv, "hs:")) != -1) {
+        switch (i) {
+        /* 
+         * Handling options 
+         */ 
+        case 'h':      /* help option */
+            printf("Wrong -h option use\n");
+            usage();
+            return -1;
+            break;
+        case 's':      /* take wait time for childen */
+            size = strtol(optarg, NULL, 10);    /* convert input */
+            break;
+       case '?':      /* unrecognized options */
+            printf("Unrecognized options -%c\n", optopt);
+            usage();
+        default:       /* should not reached */
+            usage();
+        }
+    }
+   /*
+    * Main body
+    */
+    if ((argc - optind) != 2) { /* There must two argument */
+        printf("Wrong number of arguments %d\n", argc - optind);
+        usage();
+    }
+    /* open pipe, input and output file */
+    if (pipe(pipefd) == -1) { 
+       perror("Cannot create buffer pipe"); 
+       exit(EXIT_FAILURE); 
+    }
+    in_fd = open(argv[optind], O_RDONLY);
+    if (in_fd < 0) {
+       printf("Input error %s on %s\n", strerror(errno), argv[optind]);
+       exit(EXIT_FAILURE); 
+    }
+    out_fd = open(argv[optind+1], O_CREAT|O_RDWR, 0644);
+    if (out_fd < 0) {
+       printf("Cannot open %s, error %s\n", argv[optind+1], strerror(errno));
+       exit(EXIT_FAILURE); 
+    }
+    /* copy loop */
+    printf("Size %d\n", size);
+    while (1) {
+       nread = splice(in_fd, NULL, pipefd[1], NULL, size, 0);
+       printf("read %d bytes\n", nread);
+       if (nread == 0) break;
+       if (nread < 0) {
+           if (errno == EINTR) {
+               continue;
+           } else {
+               perror("read error");
+               exit(EXIT_FAILURE); 
+           } 
+       }
+       do {
+           nwrite = splice(pipefd[0], NULL, out_fd, NULL, nread, 0); 
+           printf("write %d bytes\n", nwrite);
+           if (nwrite == 0) continue;
+           if (nwrite < 0) {
+               if (errno == EINTR)
+                   continue;
+           } else {
+               perror("write error");
+               exit(EXIT_FAILURE); 
+           }
+           nread -= nwrite;
+           printf("left %d bytes", nread);
+       } while (nread);
+    }
+    return EXIT_SUCCESS;
+}
+
+
+
+/*
+ * routine to print usage info and exit 
+ */
+void usage(void) {
+    printf("Program splicecp: copy two file using splice syscall\n");
+    printf("Usage:\n");
+    printf("  splicecp [-h] [-s N] filesrc filedst \n");
+    printf("  -h           print this help\n");
+    printf("  -s N         set a buffer size of N bytes \n");
+    exit(1);
+}