Inizio lavoro sulle pipe, aggiunta pipe2.
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index be507a5b1c3b9fe4828e1f95977b76eeffed730e..3ead8bbb4d6144786d80cb7305a7e37ea5422960 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -1,6 +1,6 @@
 %% ipc.tex
 %%
-%% Copyright (C) 2000-2012 Simone Piccardi.  Permission is granted to
+%% Copyright (C) 2000-2013 Simone Piccardi.  Permission is granted to
 %% copy, distribute and/or modify this document under the terms of the GNU Free
 %% Documentation License, Version 1.1 or any later version published by the
 %% Free Software Foundation; with the Invariant Sections being "Un preambolo",
@@ -22,9 +22,9 @@ diversi, come quelli tradizionali che coinvolgono \textit{pipe} e
 Tralasceremo invece tutte le problematiche relative alla comunicazione
 attraverso la rete (e le relative interfacce) che saranno affrontate in
 dettaglio in un secondo tempo.  Non affronteremo neanche meccanismi più
-complessi ed evoluti come le RPC (\textit{Remote Procedure Calls}) e CORBA
-(\textit{Common Object Request Brocker Architecture}) che in genere sono
-implementati con un ulteriore livello sopra i meccanismi elementari.
+complessi ed evoluti come le RPC (\textit{Remote Procedure Calls}) che in
+genere sono implementati da un ulteriore livello di librerie sopra i
+meccanismi elementari.
 
 
 \section{L'intercomunicazione fra processi tradizionale}
@@ -42,37 +42,54 @@ ne gestiscono l'uso e le varie forme in cui si è evoluto.
 
 Le \textit{pipe} nascono sostanzialmente con Unix, e sono il primo, e tuttora
 uno dei più usati, meccanismi di comunicazione fra processi. Si tratta in
-sostanza di una coppia di file descriptor\footnote{si tenga presente che
-  le pipe sono oggetti creati dal kernel e non risiedono su disco.} connessi
-fra di loro in modo che se quanto scrive su di uno si può rileggere
-dall'altro. Si viene così a costituire un canale di comunicazione tramite i
-due file descriptor, nella forma di un \textsl{tubo} (da cui il nome)
-attraverso cui fluiscono i dati.
-
-La funzione che permette di creare questa speciale coppia di file descriptor
-associati ad una \textit{pipe} è appunto \funcd{pipe}, ed il suo prototipo è:
-\begin{prototype}{unistd.h}
-{int pipe(int filedes[2])} 
-  
-Crea una coppia di file descriptor associati ad una \textit{pipe}.
-  
-  \bodydesc{La funzione restituisce zero in caso di successo e -1 per un
-    errore, nel qual caso \var{errno} potrà assumere i valori \errval{EMFILE},
-    \errval{ENFILE} e \errval{EFAULT}.}
-\end{prototype}
+sostanza di una coppia di file descriptor connessi fra di loro in modo che
+quanto scrive su di uno si può rileggere dall'altro.  Si viene così a
+costituire un canale di comunicazione realizzato tramite i due file
+descriptor, che costituisce appunto una sorta di \textsl{tubo} (che appunto il
+significato del termine inglese \textit{pipe}) attraverso cui si possono far
+passare i dati.
+
+In pratica si tratta di un buffer circolare in memoria in cui il kernel
+appoggia i dati immessi nel file descriptor su cui si scrive per farli poi
+riemergere dal file descriptor da cui si legge. Si tenga ben presente che in
+questo passaggio di dati non è previsto nessun tipo di accesso al disco e che
+nonostante l'uso dei file descriptor le pipe non han nulla a che fare con i
+file di dati di cui si è parlato al cap.~\ref{cha:file_IO_interface}.
+
+La funzione di sistema che permette di creare questa speciale coppia di file
+descriptor associati ad una \textit{pipe} è appunto \funcd{pipe}, ed il suo
+prototipo è:
+
+\begin{funcproto}{
+\fhead{unistd.h}
+\fdecl{int pipe(int filedes[2])}
+\fdesc{Crea la coppia di file descriptor di una \textit{pipe}.} 
+}
+
+{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{EFAULT}] \param{filedes} non è un indirizzo valido.
+  \end{errlist}
+  ed inoltre \errval{EMFILE} e \errval{ENFILE} nel loro significato generico.}
+\end{funcproto}
 
 La funzione restituisce la coppia di file descriptor nel vettore
-\param{filedes}; il primo è aperto in lettura ed il secondo in scrittura. Come
-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, 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
+\param{filedes}, il primo è aperto in lettura ed il secondo in scrittura. Come
+accennato concetto di funzionamento di una \textit{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, come
+accennato, 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
-indicano la direzione del flusso dei dati.
+illustrato in fig.~\ref{fig:ipc_pipe_singular}, in cui sono indicati i due
+capi della \textit{pipe}, associati a ciascun file descriptor, con le frecce
+che indicano la direzione del flusso dei dati.
+
+% TODO: la dimensione è cambiata a 64k (vedi man 7 pipe) e può essere
+% modificata con F_SETPIPE_SZ dal 2.6.35 (vedi fcntl)
 
 \begin{figure}[!htb]
   \centering
@@ -81,12 +98,42 @@ indicano la direzione del flusso dei dati.
   \label{fig:ipc_pipe_singular}
 \end{figure}
 
-Chiaramente creare una pipe all'interno di un singolo processo non serve a
-niente; se però ricordiamo quanto esposto in sez.~\ref{sec:file_sharing}
-riguardo al comportamento dei file descriptor nei processi figli, è immediato
-capire come una pipe possa diventare un meccanismo di intercomunicazione. Un
-processo figlio infatti condivide gli stessi file descriptor del padre,
-compresi quelli associati ad una pipe (secondo la situazione illustrata in
+Della funzione di sistema esiste una seconda versione, \funcd{pipe2},
+introdotta con il kernel 2.6.27 e le \acr{glibc} 2.9 e specifica di Linux
+(utilizzabile solo definendo la macro \macro{\_GNU\_SOURCE}), che consente di
+impostare atomicamente le caratteristiche dei file descriptor restituiti, il
+suo prototipo è:
+
+\begin{funcproto}{
+\fhead{unistd.h}
+\fhead{fcntl.h}
+\fdecl{int pipe2(int pipefd[2], int flags)}
+\fdesc{Crea la coppia di file descriptor di una \textit{pipe}.} 
+}
+
+{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{EINVAL}] il valore di \param{flags} non valido.
+  \end{errlist}
+  e gli altri già visti per \func{pipe} con lo stesso significato.}
+\end{funcproto}
+
+Utilizzando un valore nullo per \param{flags} la funzione è identica a
+\func{pipe}, si può però passare come valore l'OR aritmetico di uno qualunque
+fra \const{O\_NONBLOCK} o \const{O\_CLOEXEC} che hanno l'effetto di impostare
+su entrambi i file descriptor restituiti dalla funzione i relativi flag, già
+descritti per \func{open} in tab.~\ref{tab:open_operation_flag}, che attivano
+rispettivamente la modalità di accesso \textsl{non-bloccante} ed il
+\textit{close-on-exec} \itindex{close-on-exec}.
+
+Chiaramente creare una \textit{pipe} all'interno di un singolo processo non
+serve a niente; se però ricordiamo quanto esposto in
+sez.~\ref{sec:file_shared_access} riguardo al comportamento dei file
+descriptor nei processi figli, è immediato capire come una \textit{pipe} possa
+diventare un meccanismo di intercomunicazione. Un processo figlio infatti
+condivide gli stessi file descriptor del padre, compresi quelli associati ad
+una pipe (secondo la situazione illustrata in
 fig.~\ref{fig:ipc_pipe_fork}). In questo modo se uno dei processi scrive su un
 capo della pipe, l'altro può leggere.
 
@@ -100,27 +147,28 @@ capo della pipe, l'altro può leggere.
 
 Tutto ciò ci mostra come sia immediato realizzare un meccanismo di
 comunicazione fra processi attraverso una pipe, utilizzando le proprietà
-ordinarie dei file, ma ci mostra anche qual è il principale\footnote{Stevens
-  in \cite{APUE} riporta come limite anche il fatto che la comunicazione è
-  unidirezionale, ma in realtà questo è un limite facilmente superabile usando
-  una coppia di pipe.} limite nell'uso delle pipe. È necessario infatti che i
-processi possano condividere i file descriptor della pipe, e per questo essi
-devono comunque essere \textsl{parenti} (dall'inglese \textit{siblings}), cioè
-o derivare da uno stesso processo padre in cui è avvenuta la creazione della
-pipe, o, più comunemente, essere nella relazione padre/figlio.
-
-A differenza di quanto avviene con i file normali, la lettura da una pipe può
-essere bloccante (qualora non siano presenti dati), inoltre se si legge da una
-pipe il cui capo in scrittura è stato chiuso, si avrà la ricezione di un EOF
-(vale a dire che la funzione \func{read} ritornerà restituendo 0).  Se invece
-si esegue una scrittura su una pipe il cui capo in lettura non è aperto il
-processo riceverà il segnale \signal{SIGPIPE}, e la funzione di scrittura
-restituirà un errore di \errcode{EPIPE} (al ritorno del gestore, o qualora il
-segnale sia ignorato o bloccato).
-
-La dimensione del buffer della pipe (\const{PIPE\_BUF}) ci dà inoltre un'altra
-importante informazione riguardo il comportamento delle operazioni di lettura
-e scrittura su di una pipe; esse infatti sono atomiche fintanto che la
+ordinarie dei file, ma ci mostra anche qual è il principale limite nell'uso
+delle pipe.\footnote{Stevens in \cite{APUE} riporta come limite anche il fatto
+  che la comunicazione è unidirezionale, ma in realtà questo è un limite
+  superabile usando una coppia di pipe, anche se al costo di una maggiore
+  complessità di gestione.}  È necessario infatti che i processi possano
+condividere i file descriptor della pipe, e per questo essi devono comunque
+essere \textsl{parenti} (dall'inglese \textit{siblings}), cioè o derivare da
+uno stesso processo padre in cui è avvenuta la creazione della \textit{pipe},
+o, più comunemente, essere nella relazione padre/figlio.
+
+A differenza di quanto avviene con i file normali, la lettura da una
+\textit{pipe} può essere bloccante (qualora non siano presenti dati), inoltre
+se si legge da una pipe il cui capo in scrittura è stato chiuso, si avrà la
+ricezione di un EOF (vale a dire che la funzione \func{read} ritornerà
+restituendo 0).  Se invece si esegue una scrittura su una pipe il cui capo in
+lettura non è aperto il processo riceverà il segnale \signal{SIGPIPE}, e la
+funzione di scrittura restituirà un errore di \errcode{EPIPE} (al ritorno del
+gestore, o qualora il segnale sia ignorato o bloccato).
+
+La dimensione del buffer della \textit{pipe} (\const{PIPE\_BUF}) ci dà inoltre
+un'altra importante informazione riguardo il comportamento delle operazioni di
+lettura e scrittura su di una pipe; esse infatti sono atomiche fintanto che la
 quantità di dati da scrivere non supera questa dimensione. Qualora ad esempio
 si effettui una scrittura di una quantità di dati superiore l'operazione verrà
 effettuata in più riprese, consentendo l'intromissione di scritture effettuate
@@ -184,11 +232,10 @@ Il programma ci servirà anche come esempio dell'uso delle funzioni di
 duplicazione dei file descriptor che abbiamo trattato in
 sez.~\ref{sec:file_dup}, in particolare di \func{dup2}. È attraverso queste
 funzioni infatti che è possibile dirottare gli stream standard dei processi
-(che abbiamo visto in sez.~\ref{sec:file_std_descr} e
-sez.~\ref{sec:file_std_stream}) sulla pipe. In
-fig.~\ref{fig:ipc_barcodepage_code} abbiamo riportato il corpo del programma,
-il cui codice completo è disponibile nel file \file{BarCodePage.c} che si
-trova nella directory dei sorgenti.
+(che abbiamo visto in tab.~\ref{tab:file_std_files} e
+sez.~\ref{sec:file_stream}) sulla pipe. In fig.~\ref{fig:ipc_barcodepage_code}
+abbiamo riportato il corpo del programma, il cui codice completo è disponibile
+nel file \file{BarCodePage.c} che si trova nella directory dei sorgenti.
 
 \begin{figure}[!htbp]
   \footnotesize \centering
@@ -302,9 +349,9 @@ che sarà aperto in sola lettura (e quindi associato allo standard output del
 programma indicato) in caso si sia indicato \code{"r"}, o in sola scrittura (e
 quindi associato allo standard input) in caso di \code{"w"}.
 
-Lo stream restituito da \func{popen} è identico a tutti gli effetti ai file
-stream visti in cap.~\ref{cha:files_std_interface}, anche se è collegato ad
-una pipe e non ad un file, e viene sempre aperto in modalità
+Lo \textit{stream} restituito da \func{popen} è identico a tutti gli effetti
+ai \textit{file stream} visti in sez.~\ref{sec:files_std_interface}, anche se
+è collegato ad una pipe e non ad un file, e viene sempre aperto in modalità
 \textit{fully-buffered} (vedi sez.~\ref{sec:file_buffering}); l'unica
 differenza con gli usuali stream è che dovrà essere chiuso dalla seconda delle
 due nuove funzioni, \funcd{pclose}, il cui prototipo è:
@@ -431,7 +478,7 @@ quello illustrato per le pipe in sez.~\ref{sec:ipc_pipes}.
 
 Abbiamo già visto in sez.~\ref{sec:file_mknod} le funzioni \func{mknod} e
 \func{mkfifo} che permettono di creare una fifo; per utilizzarne una un
-processo non avrà che da aprire il relativo \index{file!speciale} file
+processo non avrà che da aprire il relativo \index{file!speciali} file
 speciale o in lettura o scrittura; nel primo caso sarà collegato al capo di
 uscita della fifo, e dovrà leggere, nel secondo al capo di ingresso, e dovrà
 scrivere.
@@ -511,7 +558,7 @@ un detto a caso estratto da un insieme di frasi; sia il numero delle frasi
 dell'insieme, che i file da cui esse vengono lette all'avvio, sono importabili
 da riga di comando. Il corpo principale del server è riportato in
 fig.~\ref{fig:ipc_fifo_server}, dove si è tralasciata la parte che tratta la
-gestione delle opzioni a riga di comando, che effettua il settaggio delle
+gestione delle opzioni a riga di comando, che effettua l'impostazione delle
 variabili \var{fortunefilename}, che indica il file da cui leggere le frasi,
 ed \var{n}, che indica il numero di frasi tenute in memoria, ad un valore
 diverso da quelli preimpostati. Il codice completo è nel file
@@ -2065,6 +2112,10 @@ vengono effettuate con la funzione \funcd{semop}, il cui prototipo è:
 }
 \end{functions}
 
+
+%TODO manca semtimedop, trattare qui, referenziata in
+%sez.~\ref{sec:sig_gen_beha}.
+
 La funzione permette di eseguire operazioni multiple sui singoli semafori di
 un insieme. La funzione richiede come primo argomento l'identificatore
 \param{semid} dell'insieme su cui si vuole operare. Il numero di operazioni da
@@ -2363,6 +2414,8 @@ ripeteremo quanto detto al proposito in sez.~\ref{sec:ipc_sysv_mq}. L'argomento
 \param{size} specifica invece la dimensione, in byte, del segmento, che viene
 comunque arrotondata al multiplo superiore di \const{PAGE\_SIZE}.
 
+% TODO aggiungere l'uso di SHM_HUGETLB introdotto con il kernel 2.6.0
+
 La memoria condivisa è la forma più veloce di comunicazione fra due processi,
 in quanto permette agli stessi di vedere nel loro spazio di indirizzi una
 stessa sezione di memoria.  Pertanto non è necessaria nessuna operazione di
@@ -3053,7 +3106,7 @@ La prima possibilità, utilizzata fin dalle origini di Unix, è quella di usare
 dei \textsl{file di lock} (per i quali esiste anche una opportuna directory,
 \file{/var/lock}, nel filesystem standard). Per questo si usa la
 caratteristica della funzione \func{open} (illustrata in
-sez.~\ref{sec:file_open}) che prevede\footnote{questo è quanto dettato dallo
+sez.~\ref{sec:file_open_close}) che prevede\footnote{questo è quanto dettato dallo
   standard POSIX.1, ciò non toglie che in alcune implementazioni questa
   tecnica possa non funzionare; in particolare per Linux, nel caso di NFS, si
   è comunque soggetti alla possibilità di una \itindex{race~condition}
@@ -3085,7 +3138,7 @@ cancella con \func{unlink}.
 \end{figure}
 
 Uno dei limiti di questa tecnica è che, come abbiamo già accennato in
-sez.~\ref{sec:file_open}, questo comportamento di \func{open} può non
+sez.~\ref{sec:file_open_close}, questo comportamento di \func{open} può non
 funzionare (la funzione viene eseguita, ma non è garantita l'atomicità
 dell'operazione) se il filesystem su cui si va ad operare è su NFS; in tal
 caso si può adottare una tecnica alternativa che prevede l'uso della
@@ -3255,7 +3308,12 @@ più avanti, quando realizzeremo una nuova versione del monitor visto in
 sez.~\ref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete.
 \itindend{memory~mapping}
 
-% TODO fare esempio di mmap anonima
+% TODO: fare esempio di mmap anonima
+
+% TODO: con il kernel 3.2 è stata introdotta un nuovo meccanismo di
+% intercomunicazione veloce chiamato Cross Memory Attach, da capire se e come
+% trattarlo qui, vedi http://lwn.net/Articles/405346/
+% https://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=fcf634098c00dd9cd247447368495f0b79be12d1
 
 \section{L'intercomunicazione fra processi di POSIX}
 \label{sec:ipc_posix}
@@ -3414,7 +3472,7 @@ diversi.
 La funzione è del tutto analoga ad \func{open} ed analoghi sono i valori che
 possono essere specificati per \param{oflag}, che deve essere specificato come
 maschera binaria; i valori possibili per i vari bit sono quelli visti in
-tab.~\ref{tab:file_open_flags} dei quali però \func{mq\_open} riconosce solo i
+sez.~\ref{sec:file_open_close} dei quali però \func{mq\_open} riconosce solo i
 seguenti:
 \begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
 \item[\const{O\_RDONLY}] Apre la coda solo per la ricezione di messaggi. Il
@@ -3844,7 +3902,7 @@ La funzione è del tutto analoga ad \func{open} ed analoghi sono i valori che
 possono essere specificati per \param{oflag}, che deve essere specificato come
 maschera binaria comprendente almeno uno dei due valori \const{O\_RDONLY} e
 \const{O\_RDWR}; i valori possibili per i vari bit sono quelli visti in
-tab.~\ref{tab:file_open_flags} dei quali però \func{shm\_open} riconosce solo
+sez.~\ref{sec:file_open_close} dei quali però \func{shm\_open} riconosce solo
 i seguenti:
 \begin{basedescript}{\desclabelwidth{2.0cm}\desclabelstyle{\nextlinelabel}}
 \item[\const{O\_RDONLY}] Apre il file descriptor associato al segmento di
@@ -3866,7 +3924,7 @@ In caso di successo la funzione restituisce un file descriptor associato al
 segmento di memoria condiviso con le stesse modalità di
 \func{open}\footnote{in realtà, come accennato, \func{shm\_open} è un semplice
   wrapper per \func{open}, usare direttamente quest'ultima avrebbe lo stesso
-  effetto.}  viste in sez.~\ref{sec:file_open}; in particolare viene impostato
+  effetto.}  viste in sez.~\ref{sec:file_open_close}; in particolare viene impostato
 il flag \const{FD\_CLOEXEC}.  Chiamate effettuate da diversi processi usando
 lo stesso nome, restituiranno file descriptor associati allo stesso segmento
 (così come, nel caso di file di dati, essi sono associati allo stesso
@@ -4032,7 +4090,7 @@ automaticamente un nome nella forma \texttt{sem.qualchenome}.\footnote{si ha
 L'argomento \param{oflag} è quello che controlla le modalità con cui opera la
 funzione, ed è passato come maschera binaria; i bit corrispondono a quelli
 utilizzati per l'analogo argomento di \func{open}, anche se dei possibili
-valori visti in sez.~\ref{sec:file_open} sono utilizzati soltanto
+valori visti in sez.~\ref{sec:file_open_close} sono utilizzati soltanto
 \const{O\_CREAT} e \const{O\_EXCL}.
 
 Se si usa \const{O\_CREAT} si richiede la creazione del semaforo qualora