X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=fileadv.tex;h=60a002b3e2f4769c897878ed68a891fb25c88354;hp=325d8a59ea7f1d24bb472f96dff79894f5137b86;hb=2ee09e1100e6d070dbf5d4d13d900dba516d83de;hpb=b7d7d53a7edf4b2d1803041bc82136d0c07ba516 diff --git a/fileadv.tex b/fileadv.tex index 325d8a5..60a002b 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -590,29 +590,29 @@ semantica POSIX), e la variabile \var{cmd} che specifica la modalità di richiesta del \textit{file lock} (bloccante o meno), a seconda dell'opzione \cmd{-b}. -Il programma inizia col controllare (\texttt{\small 11--14}) che venga passato +Il programma inizia col controllare (\texttt{\small 11-14}) che venga passato un argomento (il file da bloccare), che sia stato scelto (\texttt{\small - 15--18}) il tipo di blocco, dopo di che apre (\texttt{\small 19}) il file, -uscendo (\texttt{\small 20--23}) in caso di errore. A questo punto il + 15-18}) il tipo di blocco, dopo di che apre (\texttt{\small 19}) il file, +uscendo (\texttt{\small 20-23}) in caso di errore. A questo punto il comportamento dipende dalla semantica scelta; nel caso sia BSD occorre reimpostare il valore di \var{cmd} per l'uso con \func{flock}; infatti il valore preimpostato fa riferimento alla semantica POSIX e vale rispettivamente \const{F\_SETLKW} o \const{F\_SETLK} a seconda che si sia impostato o meno la modalità bloccante. -Nel caso si sia scelta la semantica BSD (\texttt{\small 25--34}) prima si -controlla (\texttt{\small 27--31}) il valore di \var{cmd} per determinare se +Nel caso si sia scelta la semantica BSD (\texttt{\small 25-34}) prima si +controlla (\texttt{\small 27-31}) il valore di \var{cmd} per determinare se si vuole effettuare una chiamata bloccante o meno, reimpostandone il valore opportunamente, dopo di che a seconda del tipo di blocco al valore viene aggiunta la relativa opzione, con un OR aritmetico, dato che \func{flock} vuole un argomento \param{operation} in forma di maschera binaria. Nel caso invece che si sia scelta la semantica POSIX le operazioni sono molto più -immediate si prepara (\texttt{\small 36--40}) la struttura per il lock, e lo +immediate si prepara (\texttt{\small 36-40}) la struttura per il lock, e lo si esegue (\texttt{\small 41}). In entrambi i casi dopo aver richiesto il blocco viene controllato il -risultato uscendo (\texttt{\small 44--46}) in caso di errore, o stampando un -messaggio (\texttt{\small 47--49}) in caso di successo. Infine il programma si +risultato uscendo (\texttt{\small 44-46}) in caso di errore, o stampando un +messaggio (\texttt{\small 47-49}) in caso di successo. Infine il programma si pone in attesa (\texttt{\small 50}) finché un segnale (ad esempio un \cmd{C-c} dato da tastiera) non lo interrompa; in questo caso il programma termina, e tutti i blocchi vengono rilasciati. @@ -1280,16 +1280,19 @@ interruzione si potranno eseguire le relative operazioni. \label{sec:file_poll} Nello sviluppo di System V, invece di utilizzare l'interfaccia di -\func{select}, che è una estensione tipica di BSD, è stata introdotta un'altra -interfaccia, basata sulla funzione \funcd{poll},\footnote{la funzione è - prevista dallo standard XPG4, ed è stata introdotta in Linux come system - call a partire dal kernel 2.1.23 ed inserita nelle \acr{libc} 5.4.28.} il +\func{select}, che è una estensione tipica di BSD, è stata introdotta una +interfaccia completamente diversa, basata sulla funzione di sistema +\funcd{poll},\footnote{la funzione è prevista dallo standard XPG4, ed è stata + introdotta in Linux come system call a partire dal kernel 2.1.23 ed inserita + nelle \acr{libc} 5.4.28, originariamente l'argomento \param{nfds} era di + tipo \ctyp{unsigned int}, la funzione è stata inserita nello standard + POSIX.1-2001 in cui è stato introdotto il tipo nativo \type{nfds\_t}.} il cui prototipo è: \begin{funcproto}{ \fhead{sys/poll.h} -\fdecl{int poll(struct pollfd *ufds, unsigned int nfds, int timeout)} -\fdesc{La funzione attende un cambiamento di stato su un insieme di file +\fdecl{int poll(struct pollfd *ufds, nfds\_t nfds, int timeout)} +\fdesc{Attende un cambiamento di stato su un insieme di file descriptor.} } @@ -1311,8 +1314,19 @@ vettore di strutture \struct{pollfd}. Come con \func{select} si può interrompere l'attesa dopo un certo tempo, questo deve essere specificato con l'argomento \param{timeout} in numero di millisecondi: un valore negativo indica un'attesa indefinita, mentre un valore nullo comporta il ritorno -immediato (e può essere utilizzato per impiegare \func{poll} in modalità -\textsl{non-bloccante}). +immediato, e può essere utilizzato per impiegare \func{poll} in modalità +\textsl{non-bloccante}. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{0.90\textwidth} + \includestruct{listati/pollfd.h} + \end{minipage} + \normalsize + \caption{La struttura \structd{pollfd}, utilizzata per specificare le + modalità di controllo di un file descriptor alla funzione \func{poll}.} + \label{fig:file_pollfd} +\end{figure} Per ciascun file da controllare deve essere inizializzata una struttura \struct{pollfd} nel vettore indicato dall'argomento \param{ufds}. La @@ -1321,30 +1335,24 @@ prevede tre campi: in \var{fd} deve essere indicato il numero del file descriptor da controllare, in \var{events} deve essere specificata una maschera binaria di flag che indichino il tipo di evento che si vuole controllare, mentre in \var{revents} il kernel restituirà il relativo -risultato. Usando un valore negativo per \param{fd} la corrispondente -struttura sarà ignorata da \func{poll}. Dato che i dati in ingresso sono del +risultato. + +Usando un valore negativo per \param{fd} la corrispondente struttura sarà +ignorata da \func{poll} ed il campo \var{revents} verrà azzerato, questo +consente di eliminare temporaneamente un file descriptor dalla lista senza +dover modificare il vettore \param{ufds}. Dato che i dati in ingresso sono del tutto indipendenti da quelli in uscita (che vengono restituiti in \var{revents}) non è necessario reinizializzare tutte le volte il valore delle strutture \struct{pollfd} a meno di non voler cambiare qualche condizione. -\begin{figure}[!htb] - \footnotesize \centering - \begin{minipage}[c]{\textwidth} - \includestruct{listati/pollfd.h} - \end{minipage} - \normalsize - \caption{La struttura \structd{pollfd}, utilizzata per specificare le - modalità di controllo di un file descriptor alla funzione \func{poll}.} - \label{fig:file_pollfd} -\end{figure} - Le costanti che definiscono i valori relativi ai bit usati nelle maschere -binarie dei campi \var{events} e \var{revents} sono riportati in +binarie dei campi \var{events} e \var{revents} sono riportate in tab.~\ref{tab:file_pollfd_flags}, insieme al loro significato. Le si sono -suddivise in tre gruppi, nel primo gruppo si sono indicati i bit utilizzati -per controllare l'attività in ingresso, nel secondo quelli per l'attività in -uscita, mentre il terzo gruppo contiene dei valori che vengono utilizzati solo -nel campo \var{revents} per notificare delle condizioni di errore. +suddivise in tre gruppi principali, nel primo gruppo si sono indicati i bit +utilizzati per controllare l'attività in ingresso, nel secondo quelli per +l'attività in uscita, infine il terzo gruppo contiene dei valori che vengono +utilizzati solo nel campo \var{revents} per notificare delle condizioni di +errore. \begin{table}[htb] \centering @@ -1386,33 +1394,35 @@ nel campo \var{revents} per notificare delle condizioni di errore. dettagli in sez.~\ref{sec:TCP_shutdown}.} Il valore \const{POLLMSG} non viene utilizzato ed è definito solo per -compatibilità con l'implementazione di SysV che usa gli -\textit{stream};\footnote{essi sono una interfaccia specifica di SysV non - presente in Linux, e non hanno nulla a che fare con i file \textit{stream} - delle librerie standard del C.} è da questi che derivano i nomi di alcune -costanti, in quanto per essi sono definite tre classi di dati: -\textsl{normali}, \textit{prioritari} ed \textit{urgenti}. In Linux la -distinzione ha senso solo per i dati urgenti \itindex{out-of-band} dei socket -(vedi sez.~\ref{sec:TCP_urgent_data}), ma su questo e su come \func{poll} -reagisce alle varie condizioni dei socket torneremo in +compatibilità con l'implementazione di System V che usa i cosiddetti +``\textit{stream}''. Si tratta di una interfaccia specifica di SysV non +presente in Linux, che non ha nulla a che fare con gli \textit{stream} delle +librerie standard del C visti in sez.~\ref{sec:file_stream}. Da essa derivano +i nomi di alcune costanti poiché per quegli \textit{stream} sono definite tre +classi di dati: \textsl{normali}, \textit{prioritari} ed \textit{urgenti}. In +Linux la distinzione ha senso solo per i dati urgenti \itindex{out-of-band} +dei socket (vedi sez.~\ref{sec:TCP_urgent_data}), ma su questo e su come +\func{poll} reagisce alle varie condizioni dei socket torneremo in sez.~\ref{sec:TCP_serv_poll}, dove vedremo anche un esempio del suo utilizzo. -Si tenga conto comunque che le costanti relative ai diversi tipi di dati -normali e prioritari, vale a dire \const{POLLRDNORM}, \const{POLLWRNORM}, -\const{POLLRDBAND} e \const{POLLWRBAND} fanno riferimento alle implementazioni -in stile SysV (in particolare le ultime due non vengono usate su Linux), e -sono utilizzabili soltanto qualora si sia definita la macro -\macro{\_XOPEN\_SOURCE}.\footnote{e ci si ricordi di farlo sempre in testa al - file, definirla soltanto prima di includere \headfile{sys/poll.h} non è - sufficiente.} - -In caso di successo funzione ritorna restituendo il numero di file (un valore -positivo) per i quali si è verificata una delle condizioni di attesa richieste -o per i quali si è verificato un errore, nel qual caso vengono utilizzati i -valori di tab.~\ref{tab:file_pollfd_flags} esclusivi di \var{revents}. Un -valore nullo indica che si è raggiunto il timeout, mentre un valore negativo -indica un errore nella chiamata, il cui codice viene riportato al solito -tramite \var{errno}. +Le costanti relative ai diversi tipi di dati normali e prioritari che fanno +riferimento alle implementazioni in stile System V sono \const{POLLRDNORM}, +\const{POLLWRNORM}, \const{POLLRDBAND} e \const{POLLWRBAND}. Le prime due sono +equivalenti rispettivamente a \const{POLLIN} e \const{POLLOUT}, +\const{POLLRDBAND} non viene praticamente mai usata su Linux mentre +\const{POLLWRBAND} ha senso solo sui socket. In ogni caso queste costanti sono +utilizzabili soltanto qualora si sia definita la macro +\macro{\_XOPEN\_SOURCE}. + +In caso di successo \func{poll} ritorna restituendo il numero di file (un +valore positivo) per i quali si è verificata una delle condizioni di attesa +richieste o per i quali si è verificato un errore, avvalorando i relativi bit +di \var{revents}. In caso di errori sui file vengono utilizzati i valori della +terza sezione di tab.~\ref{tab:file_pollfd_flags} che hanno significato solo +per \var{revents} (se specificati in \var{events} vengono ignorati). Un valore +di ritorno nullo indica che si è raggiunto il timeout, mentre un valore +negativo indica un errore nella chiamata, il cui codice viene riportato al +solito tramite \var{errno}. L'uso di \func{poll} consente di superare alcuni dei problemi illustrati in precedenza per \func{select}; anzitutto, dato che in questo caso si usa un @@ -1420,11 +1430,10 @@ vettore di strutture \struct{pollfd} di dimensione arbitraria, non esiste il limite introdotto dalle dimensioni massime di un \itindex{file~descriptor~set} \textit{file descriptor set} e la dimensione dei dati passati al kernel dipende solo dal numero dei file descriptor che si vogliono controllare, non -dal loro valore.\footnote{anche se usando dei bit un \textit{file descriptor - set} può essere più efficiente di un vettore di strutture \struct{pollfd}, - qualora si debba osservare un solo file descriptor con un valore molto alto - ci si troverà ad utilizzare inutilmente un maggiore quantitativo di - memoria.} +dal loro valore. Infatti, anche se usando dei bit un \textit{file descriptor + set} può essere più efficiente di un vettore di strutture \struct{pollfd}, +qualora si debba osservare un solo file descriptor con un valore molto alto ci +si troverà ad utilizzare inutilmente un maggiore quantitativo di memoria. Inoltre con \func{select} lo stesso \itindex{file~descriptor~set} \textit{file descriptor set} è usato sia in ingresso che in uscita, e questo significa @@ -1444,16 +1453,19 @@ prevista da nessuno standard; essa può essere utilizzata esclusivamente se si definisce la macro \macro{\_GNU\_SOURCE} ed ovviamente non deve essere usata se si ha a cuore la portabilità. La funzione è \funcd{ppoll}, ed il suo prototipo è: -\begin{prototype}{sys/poll.h} - {int ppoll(struct pollfd *fds, nfds\_t nfds, const struct timespec *timeout, - const sigset\_t *sigmask)} - - La funzione attende un cambiamento di stato su un insieme di file - descriptor. - - \bodydesc{La funzione restituisce il numero di file descriptor con attività - in caso di successo, o 0 se c'è stato un timeout e -1 in caso di errore, - ed in quest'ultimo caso \var{errno} assumerà uno dei valori: + +\begin{funcproto}{ +\fhead{sys/poll.h} +\fdecl{int ppoll(struct pollfd *fds, nfds\_t nfds, + const struct timespec *timeout, \\ +\phantom{int ppoll(}const sigset\_t *sigmask)} + +\fdesc{Attende un cambiamento di stato su un insieme di file descriptor.} +} + +{La funzione ritorna il numero di file descriptor con attività in caso di + successo, $0$ se c'è stato un timeout e $-1$ per un errore, nel qual caso + \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EBADF}] si è specificato un file descriptor sbagliato in uno degli insiemi. @@ -1461,8 +1473,9 @@ prototipo è: \item[\errcode{EINVAL}] il valore di \param{nfds} eccede il limite \const{RLIMIT\_NOFILE}. \end{errlist} - ed inoltre \errval{EFAULT} e \errval{ENOMEM}.} -\end{prototype} +ed inoltre \errval{EFAULT} e \errval{ENOMEM} nel loro significato generico. +} +\end{funcproto} La funzione ha lo stesso comportamento di \func{poll}, solo che si può specificare, con l'argomento \param{sigmask}, il puntatore ad una @@ -1476,14 +1489,17 @@ del seguente codice: Eccetto per \param{timeout}, che come per \func{pselect} deve essere un puntatore ad una struttura \struct{timespec}, gli altri argomenti comuni con \func{poll} hanno lo stesso significato, e la funzione restituisce gli stessi -risultati illustrati in precedenza. Come nel caso di \func{pselect} la system -call che implementa \func{ppoll} restituisce, se la funzione viene interrotta -da un segnale, il tempo mancante in \param{timeout}, e come per \func{pselect} -la funzione di libreria fornita dalle \acr{glibc} maschera questo -comportamento non modificando mai il valore di \param{timeout}.\footnote{anche - se in questo caso non esiste nessuno standard che richiede questo - comportamento.} - +risultati illustrati in precedenza. Come nel caso di \func{pselect} la +\textit{system call} che implementa \func{ppoll} restituisce, se la funzione +viene interrotta da un segnale, il tempo mancante in \param{timeout}, e come +per \func{pselect} la funzione di libreria fornita dalle \acr{glibc} maschera +questo comportamento non modificando mai il valore di \param{timeout} anche se +in questo caso non esiste nessuno standard che richieda questo comportamento. + +Infine anche per \func{poll} e \func{ppoll} valgono le considerazioni relative +alla possibilità di avere delle notificazione spurie della disponibilita di +accesso ai file descriptor illustrate per \func{select} in +sez.~\ref{sec:file_select}, che non staremo a ripetere qui. \subsection{L'interfaccia di \textit{epoll}} \label{sec:file_epoll} @@ -1501,10 +1517,10 @@ da \func{poll} a trasferire i dati da e verso il kernel è proporzionale al numero di file descriptor osservati, non a quelli che presentano attività. Quando ci sono decine di migliaia di file descriptor osservati e migliaia di -eventi al secondo,\footnote{il caso classico è quello di un server web di un - sito con molti accessi.} l'uso di \func{poll} comporta la necessità di -trasferire avanti ed indietro da user space a kernel space la lunga lista -delle strutture \struct{pollfd} migliaia di volte al secondo. A questo poi si +eventi al secondo (il caso classico è quello di un server web di un sito con +molti accessi) l'uso di \func{poll} comporta la necessità di trasferire avanti +ed indietro da \textit{user space} a \textit{kernel space} una lunga lista di +strutture \struct{pollfd} migliaia di volte al secondo. A questo poi si aggiunge il fatto che la maggior parte del tempo di esecuzione sarà impegnato ad eseguire una scansione su tutti i file descriptor tenuti sotto controllo per determinare quali di essi (in genere una piccola percentuale) sono @@ -1513,13 +1529,12 @@ dell'interfaccia dell'\textit{I/O multiplexing} viene a costituire un collo di bottiglia che degrada irrimediabilmente le prestazioni. Per risolvere questo tipo di situazioni sono state ideate delle interfacce -specialistiche\footnote{come \texttt{/dev/poll} in Solaris, o \texttt{kqueue} - in BSD.} il cui scopo fondamentale è quello di restituire solamente le -informazioni relative ai file descriptor osservati che presentano una -attività, evitando così le problematiche appena illustrate. In genere queste -prevedono che si registrino una sola volta i file descriptor da tenere sotto -osservazione, e forniscono un meccanismo che notifica quali di questi -presentano attività. +specialistiche (come \texttt{/dev/poll} in Solaris, o \texttt{kqueue} in BSD) +il cui scopo fondamentale è quello di restituire solamente le informazioni +relative ai file descriptor osservati che presentano una attività, evitando +così le problematiche appena illustrate. In genere queste prevedono che si +registrino una sola volta i file descriptor da tenere sotto osservazione, e +forniscono un meccanismo che notifica quali di questi presentano attività. Le modalità con cui avviene la notifica sono due, la prima è quella classica (quella usata da \func{poll} e \func{select}) che viene chiamata \textit{level @@ -1546,88 +1561,87 @@ il file descriptor sia tornato non essere pronto, si potrà ricevere una ulteriore notifica qualora ritornasse pronto. Nel caso di Linux al momento la sola interfaccia che fornisce questo tipo di -servizio è \textit{epoll},\footnote{l'interfaccia è stata creata da Davide - Libenzi, ed è stata introdotta per la prima volta nel kernel 2.5.44, ma la - sua forma definitiva è stata raggiunta nel kernel 2.5.66.} anche se sono in -discussione altre interfacce con le quali si potranno effettuare lo stesso -tipo di operazioni;\footnote{al momento della stesura di queste note (Giugno - 2007) un'altra interfaccia proposta è quella di \textit{kevent}, che - fornisce un sistema di notifica di eventi generico in grado di fornire le - stesse funzionalità di \textit{epoll}, esiste però una forte discussione - intorno a tutto ciò e niente di definito.} \textit{epoll} è in grado di -operare sia in modalità \textit{level triggered} che \textit{edge triggered}. - -La prima versione \textit{epoll} prevedeva l'apertura di uno speciale file di -dispositivo, \texttt{/dev/epoll}, per ottenere un file descriptor da -utilizzare con le funzioni dell'interfaccia,\footnote{il backporting - dell'interfaccia per il kernel 2.4, non ufficiale, utilizza sempre questo - file.} ma poi si è passati all'uso di apposite \textit{system call}. Il -primo passo per usare l'interfaccia di \textit{epoll} è pertanto quello -ottenere detto file descriptor chiamando una delle funzioni -\funcd{epoll\_create} e \funcd{epoll\_create1},\footnote{l'interfaccia di - \textit{epoll} è stata inserita nel kernel a partire dalla versione 2.5.44, - ed il supporto è stato aggiunto alle \acr{glibc} 2.3.2.} i cui prototipi -sono: -\begin{functions} - \headdecl{sys/epoll.h} +servizio è chiamata \textit{epoll},\footnote{l'interfaccia è stata creata da + Davide Libenzi, ed è stata introdotta per la prima volta nel kernel 2.5.44, + ma la sua forma definitiva è stata raggiunta nel kernel 2.5.66, il supporto + è stato aggiunto nelle \acr{glibc} a partire dalla versione 2.3.2.} anche se +sono state in discussione altre interfacce con le quali effettuare lo stesso +tipo di operazioni; \textit{epoll} è in grado di operare sia in modalità +\textit{level triggered} che \textit{edge triggered}. + +La prima versione di \textit{epoll} prevedeva l'apertura di uno speciale file +di dispositivo, \texttt{/dev/epoll}, per ottenere un file descriptor da +utilizzare con le funzioni dell'interfaccia ma poi si è passati all'uso di +apposite \textit{system call}. Il primo passo per usare l'interfaccia di +\textit{epoll} è pertanto quello ottenere detto file descriptor chiamando una +delle due funzioni di sistema \funcd{epoll\_create} e \funcd{epoll\_create1}, +i cui prototipi sono: - \funcdecl{int epoll\_create(int size)} - \funcdecl{int epoll\_create1(int flags)} - - Apre un file descriptor per \textit{epoll}. - - \bodydesc{Le funzioni restituiscono un file descriptor per \textit{epoll} in - caso di successo, o $-1$ in caso di errore, nel qual caso \var{errno} - assumerà uno dei valori: +\begin{funcproto}{ +\fhead{sys/epoll.h} +\fdecl{int epoll\_create(int size)} +\fdecl{int epoll\_create1(int flags)} + +\fdesc{Apre un file descriptor per \textit{epoll}.} +} +{Le funzioni ritornano un file descriptor per \textit{epoll} in caso di + successo e $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei + valori: \begin{errlist} \item[\errcode{EINVAL}] si è specificato un valore di \param{size} non positivo o non valido per \param{flags}. - \item[\errcode{ENFILE}] si è raggiunto il massimo di file descriptor aperti - nel sistema. \item[\errcode{EMFILE}] si è raggiunto il limite sul numero massimo di istanze di \textit{epoll} per utente stabilito da \sysctlfile{fs/epoll/max\_user\_instances}. + \item[\errcode{ENFILE}] si è raggiunto il massimo di file descriptor aperti + nel sistema. \item[\errcode{ENOMEM}] non c'è sufficiente memoria nel kernel per creare l'istanza. \end{errlist} -} -\end{functions} +} +\end{funcproto} Entrambe le funzioni restituiscono un file descriptor speciale,\footnote{esso non è associato a nessun file su disco, inoltre a differenza dei normali file descriptor non può essere inviato ad un altro processo attraverso un socket locale (vedi sez.~\ref{sec:sock_fd_passing}).} detto anche \textit{epoll descriptor}, che viene associato alla infrastruttura utilizzata -dal kernel per gestire la notifica degli eventi. Nel caso di -\func{epoll\_create} l'argomento \param{size} serviva a dare l'indicazione del -numero di file descriptor che si vorranno tenere sotto controllo, e costituiva -solo un suggerimento per semplificare l'allocazione di risorse sufficienti, -non un valore massimo.\footnote{ma a partire dal kernel 2.6.8 esso viene - totalmente ignorato e l'allocazione è sempre dinamica.} - -La seconda versione della funzione, \func{epoll\_create1} è stata -introdotta\footnote{è disponibile solo a partire dal kernel 2.6.27.} come -estensione della precedente, per poter passare dei flag di controllo come -maschera binaria in fase di creazione del file descriptor. Al momento l'unico -valore legale per \param{flags} (a parte lo zero) è \const{EPOLL\_CLOEXEC}, -che consente di impostare in maniera atomica sul file descriptor il flag di -\itindex{close-on-exec} \textit{close-on-exec} (si veda il significato di -\const{O\_CLOEXEC} in sez.~\ref{sec:file_open_close}), senza che sia +dal kernel per gestire la notifica degli eventi. Una volta che se ne sia +terminato l'uso si potranno rilasciare tutte le risorse allocate chiudendolo +come ogni altro file descriptor con \func{close}. + +Nel caso di \func{epoll\_create} l'argomento \param{size} serviva a dare +l'indicazione del numero di file descriptor che si vorranno tenere sotto +controllo, e costituiva solo un suggerimento per semplificare l'allocazione di +risorse sufficienti, non un valore massimo, ma a partire dal kernel 2.6.8 esso +viene totalmente ignorato e l'allocazione è sempre dinamica. + +La seconda versione della funzione, \func{epoll\_create1} è stata introdotta +come estensione della precedente (è disponibile solo a partire dal kernel +2.6.27) per poter passare dei flag di controllo come maschera binaria in fase +di creazione del file descriptor. Al momento l'unico valore legale +per \param{flags} (a parte lo zero) è \const{EPOLL\_CLOEXEC}, che consente di +impostare in maniera atomica sul file descriptor il flag di +\itindex{close-on-exec} \textit{close-on-exec} (si è trattato il significato +di \const{O\_CLOEXEC} in sez.~\ref{sec:file_open_close}), senza che sia necessaria una successiva chiamata a \func{fcntl}. Una volta ottenuto un file descriptor per \textit{epoll} il passo successivo è indicare quali file descriptor mettere sotto osservazione e quali operazioni -controllare, per questo si deve usare la seconda funzione dell'interfaccia, -\funcd{epoll\_ctl}, il cui prototipo è: -\begin{prototype}{sys/epoll.h} - {int epoll\_ctl(int epfd, int op, int fd, struct epoll\_event *event)} - - Esegue le operazioni di controllo di \textit{epoll}. - - \bodydesc{La funzione restituisce $0$ in caso di successo o $-1$ in caso di - errore, nel qual caso \var{errno} assumerà uno dei valori: +controllare, per questo si deve usare la seconda funzione di sistema +dell'interfaccia, \funcd{epoll\_ctl}, il cui prototipo è: + +\begin{funcproto}{ +\fhead{sys/epoll.h} +\fdecl{int epoll\_ctl(int epfd, int op, int fd, struct epoll\_event *event)} + +\fdesc{Esegue le operazioni di controllo di \textit{epoll}.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: \begin{errlist} - \item[\errcode{EBADF}] il file descriptor \param{epfd} o \param{fd} non sono + \item[\errcode{EBADF}] i file descriptor \param{epfd} o \param{fd} non sono validi. \item[\errcode{EEXIST}] l'operazione richiesta è \const{EPOLL\_CTL\_ADD} ma \param{fd} è già stato inserito in \param{epfd}. @@ -1638,13 +1652,14 @@ controllare, per questo si deve usare la seconda funzione dell'interfaccia, \const{EPOLL\_CTL\_DEL} ma \param{fd} non è inserito in \param{epfd}. \item[\errcode{ENOMEM}] non c'è sufficiente memoria nel kernel gestire l'operazione richiesta. - \item[\errcode{EPERM}] il file \param{fd} non supporta \textit{epoll}. \item[\errcode{ENOSPC}] si è raggiunto il limite massimo di registrazioni per utente di file descriptor da osservare imposto da \sysctlfile{fs/epoll/max\_user\_watches}. + \item[\errcode{EPERM}] il file associato a \param{fd} non supporta l'uso di + \textit{epoll}. \end{errlist} -} -\end{prototype} + } +\end{funcproto} Il comportamento della funzione viene controllato dal valore dall'argomento \param{op} che consente di specificare quale operazione deve essere eseguita. @@ -1670,7 +1685,8 @@ delle operazioni cui fanno riferimento. \param{event}.\\ \const{EPOLL\_CTL\_DEL}& Rimuove il file descriptor \param{fd} dalla lista dei file controllati tramite \param{epfd}.\\ - \hline + \const{EPOLL\_CTL\_DISABLE}& da fare.\\ + \hline \end{tabular} \caption{Valori dell'argomento \param{op} che consentono di scegliere quale operazione di controllo effettuare con la funzione \func{epoll\_ctl}.} @@ -1700,7 +1716,7 @@ sotto controllo. L'argomento viene ignorato con l'operazione \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{\textwidth} + \begin{minipage}[c]{0.90\textwidth} \includestruct{listati/epoll_event.h} \end{minipage} \normalsize @@ -1731,7 +1747,7 @@ identificazione del file descriptor. \begin{table}[htb] \centering \footnotesize - \begin{tabular}[c]{|l|p{8cm}|} + \begin{tabular}[c]{|l|p{10cm}|} \hline \textbf{Valore} & \textbf{Significato} \\ \hline @@ -1760,7 +1776,8 @@ identificazione del file descriptor. \const{EPOLLET} & Imposta la notifica in modalità \textit{edge triggered} per il file descriptor associato.\\ \const{EPOLLONESHOT}& Imposta la modalità \textit{one-shot} per il file - descriptor associato.\footnotemark\\ + descriptor associato (questa modalità è disponibile + solo a partire dal kernel 2.6.2).\\ \hline \end{tabular} \caption{Costanti che identificano i bit del campo \param{events} di @@ -1772,9 +1789,6 @@ identificazione del file descriptor. ed è utile per riconoscere la chiusura di una connessione dall'altro capo quando si lavora in modalità \textit{edge triggered}.} -\footnotetext[48]{questa modalità è disponibile solo a partire dal kernel - 2.6.2.} - % TODO aggiunto EPOLLWAKEUP con il 3.5 @@ -1810,33 +1824,35 @@ non è necessario usare \const{EPOLL\_CTL\_DEL}. Infine una particolare modalità di notifica è quella impostata con \const{EPOLLONESHOT}: a causa dell'implementazione di \textit{epoll} infatti quando si è in modalità \textit{edge triggered} l'arrivo in rapida successione -di dati in blocchi separati\footnote{questo è tipico con i socket di rete, in - quanto i dati arrivano a pacchetti.} può causare una generazione di eventi -(ad esempio segnalazioni di dati in lettura disponibili) anche se la -condizione è già stata rilevata.\footnote{si avrebbe cioè una rottura della - logica \textit{edge triggered}.} +di dati in blocchi separati (questo è tipico con i socket di rete, in quanto i +dati arrivano a pacchetti) può causare una generazione di eventi (ad esempio +segnalazioni di dati in lettura disponibili) anche se la condizione è già +stata rilevata (si avrebbe cioè una rottura della logica \textit{edge + triggered}). Anche se la situazione è facile da gestire, la si può evitare utilizzando \const{EPOLLONESHOT} per impostare la modalità \textit{one-shot}, in cui la notifica di un evento viene effettuata una sola volta, dopo di che il file descriptor osservato, pur restando nella lista di osservazione, viene -automaticamente disattivato,\footnote{la cosa avviene contestualmente al - ritorno di \func{epoll\_wait} a causa dell'evento in questione.} e per -essere riutilizzato dovrà essere riabilitato esplicitamente con una successiva -chiamata con \const{EPOLL\_CTL\_MOD}. +automaticamente disattivato (la cosa avviene contestualmente al ritorno di +\func{epoll\_wait} a causa dell'evento in questione) e per essere riutilizzato +dovrà essere riabilitato esplicitamente con una successiva chiamata con +\const{EPOLL\_CTL\_MOD}. Una volta impostato l'insieme di file descriptor che si vogliono osservare con i relativi eventi, la funzione che consente di attendere l'occorrenza di uno di tali eventi è \funcd{epoll\_wait}, il cui prototipo è: -\begin{prototype}{sys/epoll.h} - {int epoll\_wait(int epfd, struct epoll\_event * events, int maxevents, int - timeout)} - - Attende che uno dei file descriptor osservati sia pronto. - - \bodydesc{La funzione restituisce il numero di file descriptor pronti in - caso di successo o $-1$ in caso di errore, nel qual caso \var{errno} - assumerà uno dei valori: + +\begin{funcproto}{ +\fhead{sys/epoll.h} +\fdecl{int epoll\_wait(int epfd, struct epoll\_event * events, int maxevents, + int timeout)} + +\fdesc{Attende che uno dei file descriptor osservati sia pronto.} +} + +{La funzione ritorna il numero di file descriptor pronti in caso di successo e + $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EBADF}] il file descriptor \param{epfd} non è valido. \item[\errcode{EFAULT}] il puntatore \param{events} non è valido. @@ -1845,8 +1861,8 @@ di tali eventi è \funcd{epoll\_wait}, il cui prototipo è: \item[\errcode{EINVAL}] il file descriptor \param{epfd} non è stato ottenuto con \func{epoll\_create}, o \param{maxevents} non è maggiore di zero. \end{errlist} -} -\end{prototype} +} +\end{funcproto} La funzione si blocca in attesa di un evento per i file descriptor registrati nella lista di osservazione di \param{epfd} fino ad un tempo massimo @@ -1859,10 +1875,10 @@ con l'argomento \param{maxevents}. La funzione ritorna il numero di eventi rilevati, o un valore nullo qualora sia scaduto il tempo massimo impostato con \param{timeout}. Per quest'ultimo, oltre ad un numero di millisecondi, si può utilizzare il valore nullo, che -indica di non attendere e ritornare immediatamente,\footnote{anche in questo - caso il valore di ritorno sarà nullo.} o il valore $-1$, che indica -un'attesa indefinita. L'argomento \param{maxevents} dovrà invece essere sempre -un intero positivo. +indica di non attendere e ritornare immediatamente (anche in questo caso il +valore di ritorno sarà nullo) o il valore $-1$, che indica un'attesa +indefinita. L'argomento \param{maxevents} dovrà invece essere sempre un intero +positivo. Come accennato la funzione restituisce i suoi risultati nel vettore di strutture \struct{epoll\_event} puntato da \param{events}; in tal caso nel @@ -1871,8 +1887,8 @@ eventi accaduti, mentre nel campo \var{data} sarà restituito il valore che era stato impostato per il file descriptor per cui si è verificato l'evento quando questo era stato registrato con le operazioni \const{EPOLL\_CTL\_MOD} o \const{EPOLL\_CTL\_ADD}, in questo modo il campo \var{data} consente di -identificare il file descriptor.\footnote{ed è per questo che, come accennato, - è consuetudine usare per \var{data} il valore del file descriptor stesso.} +identificare il file descriptor, ed è per questo che, come accennato, è +consuetudine usare per \var{data} il valore del file descriptor stesso. Si ricordi che le occasioni per cui \func{epoll\_wait} ritorna dipendono da come si è impostata la modalità di osservazione (se \textit{level triggered} o @@ -1901,21 +1917,24 @@ per fare questo di nuovo è necessaria una variante della funzione di attesa che consenta di reimpostare all'uscita una \index{maschera~dei~segnali} maschera di segnali, analoga alle estensioni \func{pselect} e \func{ppoll} che abbiamo visto in precedenza per \func{select} e \func{poll}; in questo caso la -funzione si chiama \funcd{epoll\_pwait}\footnote{la funziona è stata +funzione si chiama \funcd{epoll\_pwait}\footnote{la funzione è stata introdotta a partire dal kernel 2.6.19, ed è come tutta l'interfaccia di \textit{epoll}, specifica di Linux.} ed il suo prototipo è: -\begin{prototype}{sys/epoll.h} - {int epoll\_pwait(int epfd, struct epoll\_event * events, int maxevents, + +\begin{funcproto}{ +\fhead{sys/epoll.h} +\fdecl{int epoll\_pwait(int epfd, struct epoll\_event * events, int maxevents, int timeout, const sigset\_t *sigmask)} - Attende che uno dei file descriptor osservati sia pronto, mascherando i - segnali. +\fdesc{Attende che uno dei file descriptor osservati sia pronto, mascherando + i segnali.} } - \bodydesc{La funzione restituisce il numero di file descriptor pronti in - caso di successo o $-1$ in caso di errore, nel qual caso \var{errno} - assumerà uno dei valori già visti con \funcd{epoll\_wait}. -} -\end{prototype} +{La funzione ritorna il numero di file descriptor pronti in caso di successo e + $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori già + visti con \funcd{epoll\_wait}. + +} +\end{funcproto} La funzione è del tutto analoga \funcd{epoll\_wait}, soltanto che alla sua uscita viene ripristinata la \index{maschera~dei~segnali} maschera di segnali @@ -1963,15 +1982,15 @@ risposte, mentre con l'arrivo di un segnale si possono avere interruzioni asincrone in qualunque momento. Questo comporta la necessità di dover gestire, quando si deve tener conto di entrambi i tipi di eventi, le interruzioni delle funzioni di attesa sincrone, ed evitare possibili -\itindex{race~condition} \textit{race conditions}.\footnote{in sostanza se non - fossero per i segnali non ci sarebbe da doversi preoccupare, fintanto che si - effettuano operazioni all'interno di un processo, della non atomicità delle - \index{system~call~lente} \textit{system call} lente che vengono interrotte - e devono essere riavviate.} +\itindex{race~condition} \textit{race conditions}. In sostanza se non ci +fossero i segnali non ci sarebbe da preoccuparsi, fintanto che si effettuano +operazioni all'interno di un processo, della non atomicità delle +\index{system~call~lente} \textit{system call} lente che vengono interrotte e +devono essere riavviate. Abbiamo visto però in sez.~\ref{sec:sig_real_time} che insieme ai segnali \textit{real-time} sono state introdotte anche delle interfacce di gestione -sincrona dei segnali con la funzione \func{sigwait} e le sue affini. Queste +sincrona dei segnali, con la funzione \func{sigwait} e le sue affini. Queste funzioni consentono di gestire i segnali bloccando un processo fino alla avvenuta ricezione e disabilitando l'esecuzione asincrona rispetto al resto del programma del gestore del segnale. Questo consente di risolvere i problemi @@ -1986,9 +2005,9 @@ Per risolvere questo problema nello sviluppo del kernel si è pensato di introdurre un meccanismo alternativo per la notifica dei segnali (esteso anche ad altri eventi generici) che, ispirandosi di nuovo alla filosofia di Unix per cui tutto è un file, consentisse di eseguire la notifica con l'uso di -opportuni file descriptor.\footnote{ovviamente si tratta di una funzionalità - specifica di Linux, non presente in altri sistemi unix-like, e non prevista - da nessuno standard, per cui va evitata se si ha a cuore la portabilità.} +opportuni file descriptor. Ovviamente si tratta di una funzionalità specifica +di Linux, non presente in altri sistemi unix-like, e non prevista da nessuno +standard, per cui va evitata se si ha a cuore la portabilità. In sostanza, come per \func{sigwait}, si può disabilitare l'esecuzione di un gestore in occasione dell'arrivo di un segnale, e rilevarne l'avvenuta @@ -2000,10 +2019,10 @@ stesso modo di quelli associati a file o socket, per cui alla fine si potrà attendere in contemporanea sia l'arrivo del segnale che la disponibilità di accesso ai dati relativi a questi ultimi. -La funzione che permette di abilitare la ricezione dei segnali tramite file -descriptor è \funcd{signalfd},\footnote{in realtà quella riportata è - l'interfaccia alla funzione fornita dalle \acr{glibc}, esistono infatti due - versioni diverse della \textit{system call}; una prima versione, +La funzione di sistema che permette di abilitare la ricezione dei segnali +tramite file descriptor è \funcd{signalfd},\footnote{in realtà quella + riportata è l'interfaccia alla funzione fornita dalle \acr{glibc}, esistono + infatti due versioni diverse della \textit{system call}; una prima versione, \func{signalfd}, introdotta nel kernel 2.6.22 e disponibile con le \acr{glibc} 2.8 che non supporta l'argomento \texttt{flags}, ed una seconda versione, \funcm{signalfd4}, introdotta con il kernel 2.6.27 e che è quella @@ -2011,27 +2030,30 @@ descriptor è \funcd{signalfd},\footnote{in realtà quella riportata è argomento aggiuntivo \code{size\_t sizemask} che indica la dimensione della \index{maschera~dei~segnali} maschera dei segnali, il cui valore viene impostato automaticamente dalle \acr{glibc}.} il cui prototipo è: -\begin{prototype}{sys/signalfd.h} - {int signalfd(int fd, const sigset\_t *mask, int flags)} - Crea o modifica un file descriptor per la ricezione dei segnali. +\begin{funcproto}{ +\fhead{sys/signalfd.h} +\fdecl{int signalfd(int fd, const sigset\_t *mask, int flags)} - \bodydesc{La funzione restituisce un numero di file descriptor in caso di - successo o $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno - dei valori: +\fdesc{Crea o modifica un file descriptor per la ricezione dei segnali.} +} + +{La funzione ritorna un numero di file descriptor in caso di successo e $-1$ + per un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EBADF}] il valore \param{fd} non indica un file descriptor. \item[\errcode{EINVAL}] il file descriptor \param{fd} non è stato ottenuto con \func{signalfd} o il valore di \param{flags} non è valido. - \item[\errcode{ENOMEM}] non c'è memoria sufficiente per creare un nuovo file - descriptor di \func{signalfd}. \item[\errcode{ENODEV}] il kernel non può montare internamente il dispositivo per la gestione anonima degli \itindex{inode} \textit{inode} associati al file descriptor. + \item[\errcode{ENOMEM}] non c'è memoria sufficiente per creare un nuovo file + descriptor di \func{signalfd}. \end{errlist} - ed inoltre \errval{EMFILE} e \errval{ENFILE}. -} -\end{prototype} + ed inoltre \errval{EMFILE} e \errval{ENFILE} nel loro significato generico. + +} +\end{funcproto} La funzione consente di creare o modificare le caratteristiche di un file descriptor speciale su cui ricevere le notifiche della ricezione di @@ -2056,11 +2078,11 @@ loro inserimento nella maschera verrà ignorato senza generare errori. L'argomento \param{flags} consente di impostare direttamente in fase di creazione due flag per il file descriptor analoghi a quelli che si possono impostare con una creazione ordinaria con \func{open}, evitando una -impostazione successiva con \func{fcntl}.\footnote{questo è un argomento - aggiuntivo, introdotto con la versione fornita a partire dal kernel 2.6.27, - per kernel precedenti il valore deve essere nullo.} L'argomento deve essere -specificato come maschera binaria dei valori riportati in -tab.~\ref{tab:signalfd_flags}. +impostazione successiva con \func{fcntl}.\footnote{si ricordi che questo è un + argomento aggiuntivo, introdotto con la versione fornita a partire dal + kernel 2.6.27, per kernel precedenti il valore deve essere nullo.} +L'argomento deve essere specificato come maschera binaria dei valori riportati +in tab.~\ref{tab:signalfd_flags}. \begin{table}[htb] \centering @@ -2087,9 +2109,10 @@ ordinaria dei segnali indicati da \param{mask}; questa, se si vuole effettuare la ricezione tramite il file descriptor, dovrà essere disabilitata esplicitamente bloccando gli stessi segnali con \func{sigprocmask}, altrimenti verranno comunque eseguite le azioni di default (o un eventuale gestore -installato in precedenza).\footnote{il blocco non ha invece nessun effetto sul - file descriptor restituito da \func{signalfd}, dal quale sarà possibile - pertanto ricevere qualunque segnale, anche se questo risultasse bloccato.} +installato in precedenza). Il blocco non ha invece nessun effetto sul file +descriptor restituito da \func{signalfd}, dal quale sarà possibile pertanto +ricevere qualunque segnale, anche se questo risultasse bloccato. + Si tenga presente inoltre che la lettura di una struttura \struct{signalfd\_siginfo} relativa ad un segnale pendente è equivalente alla esecuzione di un gestore, vale a dire che una volta letta il segnale non sarà @@ -2108,12 +2131,12 @@ diversi. Inoltre è anche possibile tenere sotto osservazione lo stesso segnale con più file descriptor, anche se la pratica è sconsigliata; in tal caso la ricezione del segnale potrà essere effettuata con una lettura da uno qualunque dei file descriptor a cui è associato, ma questa potrà essere eseguita -soltanto una volta.\footnote{questo significa che tutti i file descriptor su - cui è presente lo stesso segnale risulteranno pronti in lettura per le - funzioni di \textit{I/O multiplexing}, ma una volta eseguita la lettura su - uno di essi il segnale sarà considerato ricevuto ed i relativi dati non - saranno più disponibili sugli altri file descriptor, che (a meno di una - ulteriore occorrenza del segnale nel frattempo) di non saranno più pronti.} +soltanto una volta. Questo significa che tutti i file descriptor su cui è +presente lo stesso segnale risulteranno pronti in lettura per le funzioni di +\textit{I/O multiplexing}, ma una volta eseguita la lettura su uno di essi il +segnale sarà considerato ricevuto ed i relativi dati non saranno più +disponibili sugli altri file descriptor, che (a meno di una ulteriore +occorrenza del segnale nel frattempo) di non saranno più pronti. Quando il file descriptor per la ricezione dei segnali non serve più potrà essere chiuso con \func{close} liberando tutte le risorse da esso allocate. In @@ -2150,7 +2173,7 @@ successivo con \func{fcntl}. \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{\textwidth} + \begin{minipage}[c]{0.90\textwidth} \includestruct{listati/signalfd_siginfo.h} \end{minipage} \normalsize @@ -2169,6 +2192,17 @@ dimensione maggiore potranno essere letti in unica soluzione i dati relativi ad eventuali più segnali pendenti, fino al numero massimo di strutture \struct{signalfd\_siginfo} che possono rientrare nel buffer. +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{\codesamplewidth} + \includecodesample{listati/FifoReporter-init.c} + \end{minipage} + \normalsize + \caption{Sezione di inizializzazione del codice del programma + \file{FifoReporter.c}.} + \label{fig:fiforeporter_code_init} +\end{figure} + Il contenuto di \struct{signalfd\_siginfo} ricalca da vicino quella della analoga struttura \struct{siginfo\_t} (illustrata in fig.~\ref{fig:sig_siginfo_t}) usata dall'interfaccia ordinaria dei segnali, e @@ -2188,43 +2222,32 @@ codice completo si trova al solito nei sorgenti allegati alla guida (nel file In fig.~\ref{fig:fiforeporter_code_init} si è riportata la parte iniziale del programma in cui vengono effettuate le varie inizializzazioni necessarie per l'uso di \itindex{epoll} \textit{epoll} e \func{signalfd}, a partire -(\texttt{\small 12--16}) dalla definizione delle varie variabili e strutture +(\texttt{\small 12-16}) dalla definizione delle varie variabili e strutture necessarie. Al solito si è tralasciata la parte dedicata alla decodifica delle opzioni che consentono ad esempio di cambiare il nome del file associato alla fifo. -\begin{figure}[!htbp] - \footnotesize \centering - \begin{minipage}[c]{\codesamplewidth} - \includecodesample{listati/FifoReporter-init.c} - \end{minipage} - \normalsize - \caption{Sezione di inizializzazione del codice del programma - \file{FifoReporter.c}.} - \label{fig:fiforeporter_code_init} -\end{figure} - -Il primo passo (\texttt{\small 19--20}) è la creazione di un file descriptor +Il primo passo (\texttt{\small 19-20}) è la creazione di un file descriptor \texttt{epfd} di \itindex{epoll} \textit{epoll} con \func{epoll\_create} che è quello che useremo per il controllo degli altri. É poi necessario disabilitare la ricezione dei segnali (nel caso \signal{SIGINT}, \signal{SIGQUIT} e \signal{SIGTERM}) per i quali si vuole la notifica tramite -file descriptor. Per questo prima li si inseriscono (\texttt{\small 22--25}) +file descriptor. Per questo prima li si inseriscono (\texttt{\small 22-25}) in una \index{maschera~dei~segnali} maschera di segnali \texttt{sigmask} che useremo con (\texttt{\small 26}) \func{sigprocmask} per disabilitarli. Con la -stessa maschera si potrà per passare all'uso (\texttt{\small 28--29}) di +stessa maschera si potrà per passare all'uso (\texttt{\small 28-29}) di \func{signalfd} per abilitare la notifica sul file descriptor -\var{sigfd}. Questo poi (\texttt{\small 30--33}) dovrà essere aggiunto con +\var{sigfd}. Questo poi (\texttt{\small 30-33}) dovrà essere aggiunto con \func{epoll\_ctl} all'elenco di file descriptor controllati con \texttt{epfd}. -Occorrerà infine (\texttt{\small 35--38}) creare la \textit{named fifo} se -questa non esiste ed aprirla per la lettura (\texttt{\small 39--40}); una +Occorrerà infine (\texttt{\small 35-38}) creare la \textit{named fifo} se +questa non esiste ed aprirla per la lettura (\texttt{\small 39-40}); una volta fatto questo sarà necessario aggiungere il relativo file descriptor (\var{fifofd}) a quelli osservati da \itindex{epoll} \textit{epoll} in maniera del tutto analoga a quanto fatto con quello relativo alla notifica dei segnali. -\begin{figure}[!htbp] +\begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{\codesamplewidth} \includecodesample{listati/FifoReporter-main.c} @@ -2235,118 +2258,117 @@ segnali. \end{figure} Una volta completata l'inizializzazione verrà eseguito indefinitamente il -ciclo principale del programma (\texttt{\small 2--45}) che si è riportato in +ciclo principale del programma (\texttt{\small 2-45}) che si è riportato in fig.~\ref{fig:fiforeporter_code_body}, fintanto che questo non riceva un segnale di \signal{SIGINT} (ad esempio con la pressione di \texttt{C-c}). Il -ciclo prevede che si attenda (\texttt{\small 2--3}) la presenza di un file -descriptor pronto in lettura con \func{epoll\_wait},\footnote{si ricordi che - entrambi i file descriptor \var{fifofd} e \var{sigfd} sono stati posti in - osservazioni per eventi di tipo \const{EPOLLIN}.} che si bloccherà fintanto -che non siano stati scritti dati sulla fifo o che non sia arrivato un -segnale.\footnote{per semplificare il codice non si è trattato il caso in cui - \func{epoll\_wait} viene interrotta da un segnale, assumendo che tutti - quelli che possano interessare siano stati predisposti per la notifica - tramite file descriptor, per gli altri si otterrà semplicemente l'uscita dal - programma.} +ciclo prevede che si attenda (\texttt{\small 2-3}) la presenza di un file +descriptor pronto in lettura con \func{epoll\_wait} (si ricordi che entrambi i +file descriptor \var{fifofd} e \var{sigfd} sono stati posti in osservazioni +per eventi di tipo \const{EPOLLIN}) che si bloccherà fintanto che non siano +stati scritti dati sulla fifo o che non sia arrivato un segnale.\footnote{per + semplificare il codice non si è trattato il caso in cui \func{epoll\_wait} + viene interrotta da un segnale, assumendo che tutti quelli che possano + interessare siano stati predisposti per la notifica tramite file descriptor, + per gli altri si otterrà semplicemente l'uscita dal programma.} Anche se in questo caso i file descriptor pronti possono essere al più due, si è comunque adottato un approccio generico in cui questi verranno letti -all'interno di un opportuno ciclo (\texttt{\small 5--44}) sul numero +all'interno di un opportuno ciclo (\texttt{\small 5-44}) sul numero restituito da \func{epoll\_wait}, esaminando i risultati presenti nel vettore \var{events} all'interno di una catena di condizionali alternativi sul valore -del file descriptor riconosciuto come pronto.\footnote{controllando cioè a - quale dei due file descriptor possibili corrisponde il campo relativo, - \var{events[i].data.fd}.} +del file descriptor riconosciuto come pronto, controllando cioè a quale dei +due file descriptor possibili corrisponde il campo relativo, +\var{events[i].data.fd}. -Il primo condizionale (\texttt{\small 6--24}) è relativo al caso che si sia +Il primo condizionale (\texttt{\small 6-24}) è relativo al caso che si sia ricevuto un segnale e che il file descriptor pronto corrisponda (\texttt{\small 6}) a \var{sigfd}. Dato che in generale si possono ricevere anche notifiche relativi a più di un singolo segnale, si è scelto di leggere una struttura \struct{signalfd\_siginfo} alla volta, eseguendo la lettura -all'interno di un ciclo (\texttt{\small 8--24}) che prosegue fintanto che vi +all'interno di un ciclo (\texttt{\small 8-24}) che prosegue fintanto che vi siano dati da leggere. -Per questo ad ogni lettura si esamina (\texttt{\small 9--14}) se il valore di +Per questo ad ogni lettura si esamina (\texttt{\small 9-14}) se il valore di ritorno della funzione \func{read} è negativo, uscendo dal programma (\texttt{\small 11}) in caso di errore reale, o terminando il ciclo (\texttt{\small 13}) con un \texttt{break} qualora si ottenga un errore di -\errcode{EAGAIN} per via dell'esaurimento dei dati.\footnote{si ricordi come - sia la fifo che il file descriptor per i segnali siano stati aperti in - modalità non-bloccante, come previsto per l’\textit{I/O multiplexing}, - pertanto ci si aspetta di ricevere un errore di \errcode{EAGAIN} quando non - vi saranno più dati da leggere.} +\errcode{EAGAIN} per via dell'esaurimento dei dati. Si ricordi infatti come +sia la fifo che il file descriptor per i segnali siano stati aperti in +modalità non-bloccante, come previsto per l’\textit{I/O multiplexing}, +pertanto ci si aspetta di ricevere un errore di \errcode{EAGAIN} quando non vi +saranno più dati da leggere. In presenza di dati invece il programma proseguirà l'esecuzione stampando -(\texttt{\small 19--20}) il nome del segnale ottenuto all'interno della -struttura \struct{signalfd\_siginfo} letta in \var{siginf}\footnote{per la - stampa si è usato il vettore \var{sig\_names} a ciascun elemento del quale - corrisponde il nome del segnale avente il numero corrispondente, la cui - definizione si è omessa dal codice di fig.~\ref{fig:fiforeporter_code_init} - per brevità.} ed il \textit{pid} del processo da cui lo ha ricevuto; inoltre -(\texttt{\small 21--24}) si controllerà anche se il segnale ricevuto è +(\texttt{\small 19-20}) il nome del segnale ottenuto all'interno della +struttura \struct{signalfd\_siginfo} letta in \var{siginf} ed il \textit{pid} +del processo da cui lo ha ricevuto;\footnote{per la stampa si è usato il + vettore \var{sig\_names} a ciascun elemento del quale corrisponde il nome + del segnale avente il numero corrispondente, la cui definizione si è omessa + dal codice di fig.~\ref{fig:fiforeporter_code_init} per brevità.} inoltre +(\texttt{\small 21-24}) si controllerà anche se il segnale ricevuto è \signal{SIGINT}, che si è preso come segnale da utilizzare per la terminazione del programma, che verrà eseguita dopo aver rimosso il file della \textit{name fifo}. -Il secondo condizionale (\texttt{\small 26--39}) è invece relativo al caso in +Il secondo condizionale (\texttt{\small 26-39}) è invece relativo al caso in cui ci siano dati pronti in lettura sulla fifo e che il file descriptor pronto corrisponda (\texttt{\small 26}) a \var{fifofd}. Di nuovo si effettueranno le -letture in un ciclo (\texttt{\small 28--39}) ripetendole fin tanto che la +letture in un ciclo (\texttt{\small 28-39}) ripetendole fin tanto che la funzione \func{read} non restituisce un errore di \errcode{EAGAIN} -(\texttt{\small 29--35}).\footnote{il procedimento è lo stesso adottato per il - file descriptor associato al segnale, in cui si esce dal programma in caso - di errore reale, in questo caso però alla fine dei dati prima di uscire si - stampa anche (\texttt{\small 32}) un messaggio di chiusura.} Se invece vi -sono dati validi letti dalla fifo si inserirà (\texttt{\small 36}) una -terminazione di stringa sul buffer e si stamperà il tutto (\texttt{\small - 37--38}) sullo \textit{standard output}. L'ultimo condizionale -(\texttt{\small 40--44}) è semplicemente una condizione di cattura per una +(\texttt{\small 29-35}). Il procedimento è lo stesso adottato per il file +descriptor associato al segnale, in cui si esce dal programma in caso di +errore reale, in questo caso però alla fine dei dati prima di uscire si stampa +anche (\texttt{\small 32}) un messaggio di chiusura. + +Se invece vi sono dati validi letti dalla fifo si inserirà (\texttt{\small + 36}) una terminazione di stringa sul buffer e si stamperà il tutto +(\texttt{\small 37-38}) sullo \textit{standard output}. L'ultimo condizionale +(\texttt{\small 40-44}) è semplicemente una condizione di cattura per una eventualità che comunque non dovrebbe mai verificarsi, e che porta alla uscita dal programma con una opportuna segnalazione di errore. A questo punto si potrà eseguire il comando lanciandolo su un terminale, ed osservarne le reazioni agli eventi generati da un altro terminale; lanciando il programma otterremo qualcosa del tipo: -\begin{Verbatim} -piccardi@hain:~/gapil/sources$ ./a.out +\begin{Console} +piccardi@hain:~/gapil/sources$ \textbf{./a.out} FifoReporter starting, pid 4568 -\end{Verbatim} +\end{Console} %$ e scrivendo qualcosa sull'altro terminale con: -\begin{Verbatim} -root@hain:~# echo prova > /tmp/reporter.fifo -\end{Verbatim} +\begin{Console} +root@hain:~# \textbf{echo prova > /tmp/reporter.fifo} +\end{Console} si otterrà: -\begin{Verbatim} +\begin{Console} Message from fifo: prova end message -\end{Verbatim} +\end{Console} mentre inviando un segnale: -\begin{Verbatim} -root@hain:~# kill 4568 -\end{Verbatim} +\begin{Console} +root@hain:~# \textbf{kill 4568} +\end{Console} si avrà: -\begin{Verbatim} +\begin{Console} Signal received: Got SIGTERM From pid 3361 -\end{Verbatim} +\end{Console} ed infine premendo \texttt{C-\bslash} sul terminale in cui è in esecuzione si vedrà: -\begin{Verbatim} -^\Signal received: +\begin{Console} +^\\Signal received: Got SIGQUIT From pid 0 -\end{Verbatim} +\end{Console} e si potrà far uscire il programma con \texttt{C-c} ottenendo: -\begin{Verbatim} +\begin{Console} ^CSignal received: Got SIGINT From pid 0 SIGINT means exit -\end{Verbatim} - +\end{Console} Lo stesso paradigma di notifica tramite file descriptor usato per i segnali è stato adottato anche per i timer. In questo caso, rispetto a quanto visto in @@ -2355,10 +2377,10 @@ file descriptor senza dover ricorrere ad altri meccanismi di notifica come un segnale o un \textit{thread}. Di nuovo questo ha il vantaggio di poter utilizzare le funzioni dell'\textit{I/O multiplexing} per attendere allo stesso tempo la disponibilità di dati o la ricezione della scadenza di un -timer.\footnote{in realtà per questo sarebbe già sufficiente \func{signalfd} - per ricevere i segnali associati ai timer, ma la nuova interfaccia - semplifica notevolmente la gestione e consente di fare tutto con una sola - \textit{system call}.} +timer. In realtà per questo sarebbe già sufficiente \func{signalfd} per +ricevere i segnali associati ai timer, ma la nuova interfaccia semplifica +notevolmente la gestione e consente di fare tutto con una sola \textit{system + call}. Le funzioni di questa nuova interfaccia ricalcano da vicino la struttura delle analoghe versioni ordinarie introdotte con lo standard POSIX.1-2001, che @@ -2368,30 +2390,33 @@ abbiamo già illustrato in sez.~\ref{sec:sig_timer_adv}.\footnote{questa reintrodotta in una forma considerata adeguata nel kernel 2.6.25, il supporto nelle \acr{glibc} è stato introdotto a partire dalla versione 2.8.6, la versione del kernel 2.6.22, presente solo su questo kernel, non è - supportata e non deve essere usata.} La prima funzione prevista, quella che -consente di creare un timer, è \funcd{timerfd\_create}, il cui prototipo è: -\begin{prototype}{sys/timerfd.h} - {int timerfd\_create(int clockid, int flags)} + supportata e non deve essere usata.} La prima funzione di sistema prevista, +quella che consente di creare un timer, è \funcd{timerfd\_create}, il cui +prototipo è: - Crea un timer associato ad un file descriptor per la notifica. +\begin{funcproto}{ +\fhead{sys/timerfd.h} +\fdecl{int timerfd\_create(int clockid, int flags)} - \bodydesc{La funzione restituisce un numero di file descriptor in caso di - successo o $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno - dei valori: +\fdesc{Crea un timer associato ad un file descriptor per la notifica.} +} + +{La funzione ritorna un numero di file descriptor in caso di successo e $-1$ + per un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EINVAL}] l'argomento \param{clockid} non è \const{CLOCK\_MONOTONIC} o \const{CLOCK\_REALTIME}, o l'argomento \param{flag} non è valido, o è diverso da zero per kernel precedenti il 2.6.27. - \item[\errcode{ENOMEM}] non c'è memoria sufficiente per creare un nuovo file - descriptor di \func{signalfd}. \item[\errcode{ENODEV}] il kernel non può montare internamente il dispositivo per la gestione anonima degli \itindex{inode} \textit{inode} associati al file descriptor. + \item[\errcode{ENOMEM}] non c'è memoria sufficiente per creare un nuovo file + descriptor di \func{signalfd}. \end{errlist} - ed inoltre \errval{EMFILE} e \errval{ENFILE}. -} -\end{prototype} + ed inoltre \errval{EMFILE} e \errval{ENFILE} nel loro significato generico. +} +\end{funcproto} La funzione prende come primo argomento un intero che indica il tipo di orologio a cui il timer deve fare riferimento, i valori sono gli stessi delle @@ -2429,41 +2454,43 @@ tab.~\ref{tab:timerfd_flags}. In caso di successo la funzione restituisce un file descriptor sul quale verranno notificate le scadenze dei timer. Come per quelli restituiti da \func{signalfd} anche questo file descriptor segue la semantica dei sistemi -unix-like, in particolare resta aperto attraverso una \func{exec},\footnote{a - meno che non si sia impostato il flag di \textit{close-on exec} con - \const{TFD\_CLOEXEC}.} e viene duplicato attraverso una \func{fork}; questa +unix-like, in particolare resta aperto attraverso una \func{exec} (a meno che +non si sia impostato il flag di \textit{close-on exec} con +\const{TFD\_CLOEXEC}) e viene duplicato attraverso una \func{fork}; questa ultima caratteristica comporta però che anche il figlio può utilizzare i dati di un timer creato nel padre, a differenza di quanto avviene invece con i -timer impostati con le funzioni ordinarie.\footnote{si ricordi infatti che, - come illustrato in sez.~\ref{sec:proc_fork}, allarmi, timer e segnali - pendenti nel padre vengono cancellati per il figlio dopo una \func{fork}.} +timer impostati con le funzioni ordinarie. Si ricordi infatti che, come +illustrato in sez.~\ref{sec:proc_fork}, allarmi, timer e segnali pendenti nel +padre vengono cancellati per il figlio dopo una \func{fork}. Una volta creato il timer con \func{timerfd\_create} per poterlo utilizzare occorre \textsl{armarlo} impostandone un tempo di scadenza ed una eventuale -periodicità di ripetizione, per farlo si usa la funzione omologa di -\func{timer\_settime} per la nuova interfaccia; questa è +periodicità di ripetizione, per farlo si usa una funzione di sistema omologa +di \func{timer\_settime} per la nuova interfaccia; questa è \funcd{timerfd\_settime} ed il suo prototipo è: -\begin{prototype}{sys/timerfd.h} - {int timerfd\_settime(int fd, int flags, - const struct itimerspec *new\_value, - struct itimerspec *old\_value)} - Crea un timer associato ad un file descriptor per la notifica. +\begin{funcproto}{ +\fhead{sys/timerfd.h} +\fdecl{int timerfd\_settime(int fd, int flags, + const struct itimerspec *new\_value,\\ +\phantom{int timerfd\_settime(}struct itimerspec *old\_value)} - \bodydesc{La funzione restituisce un numero di file descriptor in caso di - successo o $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno - dei valori: +\fdesc{Crea un timer associato ad un file descriptor per la notifica.} +} + +{La funzione ritorna un numero di file descriptor in caso di successo e $-1$ + per un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EBADF}] l'argomento \param{fd} non corrisponde ad un file descriptor. + \item[\errcode{EFAULT}] o \param{new\_value} o \param{old\_value} non sono + puntatori validi. \item[\errcode{EINVAL}] il file descriptor \param{fd} non è stato ottenuto con \func{timerfd\_create}, o i valori di \param{flag} o dei campi \var{tv\_nsec} in \param{new\_value} non sono validi. - \item[\errcode{EFAULT}] o \param{new\_value} o \param{old\_value} non sono - puntatori validi. \end{errlist} -} -\end{prototype} +} +\end{funcproto} In questo caso occorre indicare su quale timer si intende operare specificando come primo argomento il file descriptor ad esso associato, che deve essere @@ -2486,14 +2513,16 @@ valori possibili rispettivamente soltanto $0$ e L'ultima funzione prevista dalla nuova interfaccia è \funcd{timerfd\_gettime}, che è l'analoga di \func{timer\_gettime}, il suo prototipo è: -\begin{prototype}{sys/timerfd.h} - {int timerfd\_gettime(int fd, struct itimerspec *curr\_value)} - Crea un timer associato ad un file descriptor per la notifica. +\begin{funcproto}{ +\fhead{sys/timerfd.h} +\fdecl{int timerfd\_gettime(int fd, struct itimerspec *curr\_value)} - \bodydesc{La funzione restituisce un numero di file descriptor in caso di - successo o $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno - dei valori: +\fdesc{Crea un timer associato ad un file descriptor per la notifica.} +} + +{La funzione ritorna un numero di file descriptor in caso di successo e $-1$ + per un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EBADF}] l'argomento \param{fd} non corrisponde ad un file descriptor. @@ -2501,24 +2530,18 @@ che è l'analoga di \func{timer\_gettime}, il suo prototipo è: con \func{timerfd\_create}. \item[\errcode{EFAULT}] o \param{curr\_value} non è un puntatore valido. \end{errlist} -} -\end{prototype} - - - - +ed inoltre nel suo significato generico. + +} +\end{funcproto} Questo infatti diverrà pronto in lettura per tutte le varie funzioni dell'I/O multiplexing in presenza di una o più scadenze del timer ad esso associato. Inoltre sarà possibile ottenere il numero di volte che il timer è scaduto -dalla ultima impostazione - -che può essere -usato per leggere le notifiche delle scadenze dei timer. Queste possono essere -ottenute leggendo in maniera ordinaria il file descriptor con una \func{read}, - - +dalla ultima impostazione che può essere usato per leggere le notifiche delle +scadenze dei timer. Queste possono essere ottenute leggendo in maniera +ordinaria il file descriptor con una \func{read}, % TODO trattare qui eventfd, timerfd introdotte con il 2.6.22 @@ -3268,17 +3291,17 @@ funzioni di ausilio è riportato in fig.~\ref{fig:inotify_monitor_example}. \end{figure} Una volta completata la scansione delle opzioni il corpo principale del -programma inizia controllando (\texttt{\small 11--15}) che sia rimasto almeno +programma inizia controllando (\texttt{\small 11-15}) che sia rimasto almeno un argomento che indichi quale file o directory mettere sotto osservazione (e qualora questo non avvenga esce stampando la pagina di aiuto); dopo di che -passa (\texttt{\small 16--20}) all'inizializzazione di \textit{inotify} +passa (\texttt{\small 16-20}) all'inizializzazione di \textit{inotify} ottenendo con \func{inotify\_init} il relativo file descriptor (oppure usce in caso di errore). -Il passo successivo è aggiungere (\texttt{\small 21--30}) alla coda di +Il passo successivo è aggiungere (\texttt{\small 21-30}) alla coda di notifica gli opportuni osservatori per ciascuno dei file o directory indicati all'invocazione del comando; questo viene fatto eseguendo un ciclo -(\texttt{\small 22--29}) fintanto che la variabile \var{i}, inizializzata a +(\texttt{\small 22-29}) fintanto che la variabile \var{i}, inizializzata a zero (\texttt{\small 21}) all'inizio del ciclo, è minore del numero totale di argomenti rimasti. All'interno del ciclo si invoca (\texttt{\small 23}) \func{inotify\_add\_watch} per ciascuno degli argomenti, usando la maschera @@ -3287,7 +3310,7 @@ nella scansione delle opzioni), in caso di errore si esce dal programma altrimenti si incrementa l'indice (\texttt{\small 29}). Completa l'inizializzazione di \textit{inotify} inizia il ciclo principale -(\texttt{\small 32--56}) del programma, nel quale si resta in attesa degli +(\texttt{\small 32-56}) del programma, nel quale si resta in attesa degli eventi che si intendono osservare. Questo viene fatto eseguendo all'inizio del ciclo (\texttt{\small 33}) una \func{read} che si bloccherà fintanto che non si saranno verificati eventi. @@ -3298,13 +3321,13 @@ dimensioni adeguate, inizializzato in (\texttt{\small 7}) ad un valore di approssimativamente 512 eventi.\footnote{si ricordi che la quantità di dati restituita da \textit{inotify} è variabile a causa della diversa lunghezza del nome del file restituito insieme a \struct{inotify\_event}.} In caso di -errore di lettura (\texttt{\small 35--40}) il programma esce con un messaggio -di errore (\texttt{\small 37--39}), a meno che non si tratti di una +errore di lettura (\texttt{\small 35-40}) il programma esce con un messaggio +di errore (\texttt{\small 37-39}), a meno che non si tratti di una interruzione della \textit{system call}, nel qual caso (\texttt{\small 36}) si ripete la lettura. Se la lettura è andata a buon fine invece si esegue un ciclo (\texttt{\small - 43--52}) per leggere tutti gli eventi restituiti, al solito si inizializza + 43-52}) per leggere tutti gli eventi restituiti, al solito si inizializza l'indice \var{i} a zero (\texttt{\small 42}) e si ripetono le operazioni (\texttt{\small 43}) fintanto che esso non supera il numero di byte restituiti in lettura. Per ciascun evento all'interno del ciclo si assegna\footnote{si @@ -3317,7 +3340,7 @@ comando sfruttando il fatto che i \textit{watch descriptor} vengono assegnati in ordine progressivo crescente a partire da 1. Qualora sia presente il riferimento ad un nome di file associato all'evento lo -si stampa (\texttt{\small 47--49}); si noti come in questo caso si sia +si stampa (\texttt{\small 47-49}); si noti come in questo caso si sia utilizzato il valore del campo \var{event->len} e non al fatto che \var{event->name} riporti o meno un puntatore nullo.\footnote{l'interfaccia infatti, qualora il nome non sia presente, non avvalora il campo @@ -3334,15 +3357,16 @@ aggiornare l'indice \var{i} per farlo puntare all'evento successivo. Se adesso usiamo il programma per mettere sotto osservazione una directory, e da un altro terminale eseguiamo il comando \texttt{ls} otterremo qualcosa del tipo di: -\begin{verbatim} -piccardi@gethen:~/gapil/sources$ ./inotify_monitor -a /home/piccardi/gapil/ +\begin{Console} +piccardi@gethen:~/gapil/sources$ \textbf{./inotify_monitor -a /home/piccardi/gapil/} Watch descriptor 1 Observed event on /home/piccardi/gapil/ IN_OPEN, Watch descriptor 1 Observed event on /home/piccardi/gapil/ IN_CLOSE_NOWRITE, -\end{verbatim} +\end{Console} +%$ I lettori più accorti si saranno resi conto che nel ciclo di lettura degli eventi appena illustrato non viene trattato il caso particolare in cui la @@ -4951,10 +4975,10 @@ fig.~\ref{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 +(\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. +(\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 @@ -4967,8 +4991,8 @@ infine (\texttt{\small 28--31}) la \textit{pipe} che verrà usata come buffer. \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 33-58}) 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} e l'uso della coppia di file descriptor ad esse associati @@ -4983,13 +5007,13 @@ 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 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 + 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 ad una interruzione, o altrimenti si esce con un messaggio di errore -(\texttt{\small 41--43}). +(\texttt{\small 41-43}). 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 45-57}); 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 faccia di nuovo riferimento alla \textit{pipe} (in questo caso si usa il capo in lettura, per i dettagli si @@ -4999,7 +5023,7 @@ del file di destinazione. 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 48-55}). Infine si chiude il ciclo di scrittura sottraendo (\texttt{\small 57}) 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}, @@ -5140,25 +5164,25 @@ allegati alla guida. \label{fig:tee_example} \end{figure} -La prima parte del programma (\texttt{\small 10--35}) si cura semplicemente di -controllare (\texttt{\small 11--14}) che sia stato fornito almeno un argomento -(il nome del file su cui scrivere), di aprirlo ({\small 15--19}) e che sia lo -standard input (\texttt{\small 20--27}) che lo standard output (\texttt{\small - 28--35}) corrispondano ad una \textit{pipe}. +La prima parte del programma (\texttt{\small 10-35}) si cura semplicemente di +controllare (\texttt{\small 11-14}) che sia stato fornito almeno un argomento +(il nome del file su cui scrivere), di aprirlo ({\small 15-19}) e che sia lo +standard input (\texttt{\small 20-27}) che lo standard output (\texttt{\small + 28-35}) corrispondano ad una \textit{pipe}. -Il ciclo principale (\texttt{\small 37--58}) inizia con la chiamata a +Il ciclo principale (\texttt{\small 37-58}) inizia con la chiamata a \func{tee} che duplica il contenuto dello standard input sullo standard output (\texttt{\small 39}), questa parte è del tutto analoga ad una lettura ed infatti come nell'esempio di fig.~\ref{fig:splice_example} si controlla il valore di ritorno della funzione in \var{len}; se questo è nullo significa che non ci sono più dati da leggere e si chiude il ciclo (\texttt{\small 40}), se è negativo c'è stato un errore, ed allora si ripete la chiamata se questo è -dovuto ad una interruzione (\texttt{\small 42--44}) o si stampa un messaggio -di errore e si esce negli altri casi (\texttt{\small 44--47}). +dovuto ad una interruzione (\texttt{\small 42-44}) o si stampa un messaggio +di errore e si esce negli altri casi (\texttt{\small 44-47}). Una volta completata la copia dei dati sullo standard output si possono estrarre dalla standard input e scrivere sul file, di nuovo su usa un ciclo di -scrittura (\texttt{\small 50--58}) in cui si ripete una chiamata a +scrittura (\texttt{\small 50-58}) in cui si ripete una chiamata a \func{splice} (\texttt{\small 51}) fintanto che non si sono scritti tutti i \var{len} byte copiati in precedenza con \func{tee} (il funzionamento è identico all'analogo ciclo di scrittura del precedente esempio di