From eba75c4aaf390ff55ad6697ab80d4c1512ea2f39 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sat, 11 Aug 2007 19:06:11 +0000 Subject: [PATCH] Materiale su splice, ed esempio non funzionante --- fileadv.tex | 62 ++++++++++++++++--- img/pipe.dia | Bin 1161 -> 1388 bytes ipc.tex | 5 +- sources/splicecp.c | 150 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 205 insertions(+), 12 deletions(-) create mode 100644 sources/splicecp.c diff --git a/fileadv.tex b/fileadv.tex index 5fa13de..1581fbb 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -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 @@ -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 -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 @@ -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 -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) -% e http://kerneltrap.org/node/6505 diff --git a/img/pipe.dia b/img/pipe.dia index 8be4c57d318eb0fbcb5b4427b36ce39d05bf3d9c..801cbc600211517c89f44a62641c6a71bb511673 100644 GIT binary patch literal 1388 zcmV-y1(W(8iwFP!000001MON%Z{s!)zUNm6$~8-q67|}wv*;EmdMMCCx2K{oD2tZa z$dp0RalD8A_N5+)Z9VK*vb4^^0usRTXof@0_kA<6K7D>(MA{P-35)qyM*!*?<I2EHrfmPts3geJQh@*a{?c^goFr zGEzn({ozK_b{zynlJs10mPjd>zminrWI@NePo|Hdh*vz&bF0E`8b`6vo=7y-Z)e$| zj|w-VJwFG0FG)y!LCIsYYp4#-YvX!JMcM6Q87EAc$j!21(%>ikzhhHaCCZ4054XSI z+k8pIiLI}?g*FC}3nD_st8vucMEOP-z%>j*ZHDE!9(1sSUiRelaQ?92qG7{{VZ*Ux zvW$fkgvn}1KaL|xcpg=X6>T3UnUYAA*rBvKWHDn>#z)paBT@2}1oG3bXgd|TpNQ+CCra#U51Ry&h_x(esdo8QMmuIm2$1P z!38Vr>_Y7SN2jt#?=MMsKt!N@(7wda`nEGseF+Q3`k!!rd&&tZXNnyw`?HK+i%3!N z9V#bWrIaS;zF+n&)anTjBl_asajZKCJjc4niuSEL1Z=}<7m-GEF`34KSNn$Zq?857 zsHB?Kt9W&AJ*O<3%VysYSl<5Owu|P+BB0_}DiA=cM2Tj*c*#6oPik7#<2qc=2cs<% zT4Mus#fAlpI}6x7qQe46p~C`}LWc{mLWd2Ee$mk>skh+6EX(W_Fc$}yuk=~&AO;nP zF}fngOsN;(9uZ>#)6PT$S*f5HrjscOZiyM0Zp4vhsbtf1L$e8V&#pAA&Vqm7zYX*1 zfd;N=Vu-n{i2Q1WWr5y4JNsZqkNB(PQr6*Zj-fuITh-Q~+9w8VnmL zp-s^JB79RJwh6P}*B*F40%5m6YO)OZg4W+q%2$h;hW}8@U)QyshKr|cNo8bgmtqbf z;O1GH+g=4cZ*Ng1;CXv%^ey0>lDamyKa*bLbLh1(gjzdWwN?OmCu)tZYCW7<8&|D< zCt6LvsXF|FaatqUR#!&CnYwvBauQZ^Hna^D#dR=p?=9fCo?)xW8+o4Dk_~Go4+Y(Chiqyb{@!$bKl1p$)@NPqjVv1g)t z)%ZXU(g88r7_h1d!)j_EFiSnb{w2fl!P7apel*gbWoj=S9f~4EH9w$ zy`diZnl9cmQfsc;ma}<4lKJr#ru5JYnS(sR^}2#2YqiZDG2#Imy4hpfT&NLJCy=L# zGZkv*@`ZYpP@yGDGNo6YKDSPntM4k*mn_r`9E9LmNC@}(-iHS;Hr0H90eqn$$97Eh u*?u4M!Xp)&Mpq*0k%;j1g^!D&qWp9A_VdHd-s{m1H{SuTuKs9dH2?r-Iloo_ literal 1161 zcmV;41a|u$iwFP!000001MOK$Z`(K!zUNm6$~C1#z17q%+65Lp6zE~Qr^UjcELvtu zlLke{aS#3Nr5=f6y=+TXfB-g-0G5W|aE3GA%+Mb`KCYYk)ebP zeR`v5F9BjCQTD8Silh`I+DNQ1w89fTLi3-A;2Rd}g;Xgw=adWW0nv$myU0JfQNkDp zI33t)l;B8U^s^n>RG%>H1HHzg3cFhKlqeCoTh~NdaI*g|WJ;-239)2)`^mX2wp2dY zV>NBGRf$|7kq}nbqkKaPM_3@REbGY+=c|auS3$>DA;woh(%G5|DG-r$H4*0&BUWgV zVuSnZN#}^Fkm)i7_D5e3DfyB8FAz;nF`#(-oIU4eVj@V~ornh#Eht+O%jN8`%UvcI zaO?&CZZ!M{l9GtxCJP9YgU|a3es>x8>IvnHyk9;rA_}xt%8vu=V)uN?Pc|gR>5))7 zlxaa)mSV;+uUF+xbxiT7Qh;+66z#Am;Xm(7uT~y#$vQ8*z@r~{E=%+Nk%+}e#M(RU zGk?_gorLNmNIcQMnTPJF8l=D!`_=rj=FdT-==Ba(4X#s08+a5|v4z?_VhP1h_`dJn znIQDtdq+{Zdk2AMx&1U^idVBa7pz|AFJn@!Ag7MHS_feG?8Bk4?*i-2?d$QAqTdBjMZXJN75xElRP=km z8aMg}8Ffnh+u)i3ubu(l@uO@=0c&Uq*cn#>XT%h+f$f@prUj}3U^$^>WhJ2JDagzZ zN1B_8Oxt#trG1euanwp#^ocO9ltrItja?}R8FlRx-%_1)E>S0~SE-WzbCpyH@HVO> zyjIEas-$(Tk(aKK_?HThuY}1= ztYQ|=kPv*^Zj(I_c}6iyx_3WV#Zmv9sA0|-Q(2)>H?7sVr#ISCrF>Z%B+uJmZU0t9 zb1eoM*4pJ-c(~TC-w{_fbV*Y3hLTbMoc*Xybl2kTxe%%Ef2yG zS*d1RT?Cpr>jd4* /* file control functions */ +#include /* unix standard library */ +#include /* C standard library */ +#include /* error definitions and routines */ +#include /* standard I/O library */ +#include /* C strings library */ +#include +#include + +/* + * 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); +} -- 2.30.2