Altra roba connessa con le pipe
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index 7ec9f2d47f0a45e1f2f728cbc7de818c352ee180..898305fdd703de19aeb56ca31e5e53d9f23f2bb6 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
-\chapter{La comunicazione fra porcessi}
+\chapter{La comunicazione fra processi}
 \label{cha:IPC}
 
 
-\section{Introduzione}
-\label{sec:ipc_intro}
+Uno degli aspetti fondamentali della programmazione in un sistema unix-like è
+la comunicazione fra processi. In questo capitolo affronteremo solo i
+meccanismi più elementari che permettono di mettere in comunicazione processi
+diversi, come quelli tradizionali che coinvolgono \textit{pipe} e
+\textit{fifo} e i meccanismi di intercomunicazione di System V.
 
-Uno degli aspetti fondamentali della programmazione in unix è la comunicazione
-fra processi. In questo testo affronteremo solo alcuni dei meccanismi
-fondamentali che permettono di scrivere applicazioni, esistono pure sistemi
-più complessi ed evoluti come le RPC (\textit{Remote Procedure Calls})  e
-CORBA (\textit{Common Object Request Brocker Architecture}) non saranno
-affrontati qui. 
+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 invece 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.
 
-\section{Le pipes standard}
+
+
+\section{La comunicazione fra processi tradizionale}
+\label{sec:ipc_unix}
+
+Il primo meccanismo di comunicazione fra processi usato dai sistemi unix-like,
+e quello che viene correntemente usato di più, è quello delle \textit{pipe},
+che sono una delle caratteristiche peculiari del sistema, in particolar modo
+dell'interfaccia a linea di comando. In questa sezione descriveremo le sue
+basi, le funzioni che ne gestiscono l'uso e le varie forme in cui si è
+evoluto.
+
+
+\subsection{Le \textit{pipe} standard}
 \label{sec:ipc_pipes}
 
-\section{Le pipes con nome}
-\label{sec:ipc_nampipe}
+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 uno speciale tipo di file descriptor, più precisamente una coppia
+di file descriptor,\footnote{si tenga presente che le pipe sono oggetti creati
+  dal kernel e non risiedono su disco.}  su cui da una parte si scrive e da
+un'altra si legge. Si viene così a costituire un canale di comunicazione
+tramite i due file descriptor, nella forma di un \textsl{tubo} (da cui il
+nome) in cui in genere un processo immette dati che poi arriveranno ad un
+altro.
+
+La funzione che permette di creare una pipe è appunto \func{pipe}; il suo
+prototipo è:
+\begin{prototype}{unistd.h}
+{int pipe(int filedes[2])} 
+  
+Crea una coppia di file descriptor associati ad una pipe.
+  
+  \bodydesc{La funzione restituisce zero in caso di successo e -1 per un
+    errore, nel qual caso \var{errno} potrà assumere i valori \macro{EMFILE},
+    \macro{ENFILE} e \macro{EFAULT}.}
+\end{prototype}
+
+La funzione restituisce una coppia di file descriptor nell'array
+\param{filedes}; il primo aperto in lettura ed il secondo in scrittura. Il
+concetto di funzionamento di una pipe è relativamente semplice, quello che si
+scrive nel file descriptor aperto in scrittura viene ripresentato tale e quale
+nel file descriptor aperto in lettura, da cui può essere riletto.
+
+I file descriptor infatti non sono connessi a nessun file reale, ma ad un
+buffer nel kernel, la cui dimensione è specificata dalla costante
+\macro{PIPE\_BUF}, (vedi \secref{sec:sys_file_limits}); lo schema di
+funzionamento di una pipe è illustrato in \figref{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
+attraverso la pipe.
+
+\begin{figure}[htb]
+  \centering
+  \includegraphics[height=5cm]{img/pipe}
+  \caption{Schema della struttura di una pipe.}
+  \label{fig:ipc_pipe_singular}
+\end{figure}
+
+Chiaramente creare una pipe all'interno di un processo non serve a niente; se
+però ricordiamo quanto esposto in \secref{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
+\figref{fig:ipc_pipe_fork}). In questo modo se uno dei processi scrive su un
+capo della pipe, l'altro può leggere.
+
+\begin{figure}[htb]
+  \centering
+  \includegraphics[height=5cm]{img/pipefork}
+  \caption{Schema dell'uso di una pipe come mezzo di comunicazione fra
+  processo attraverso una \func{fork}.}
+  \label{fig:ipc_pipe_fork}
+\end{figure}
+
+Tutto ciò ci mostra come sia immediato realizzare un meccanismo di
+comunicazione fra processi attraverso una pipe, utilizzando le ordinarie
+proprietà dei file, ma ci mostra anche qual'è il principale\footnote{Stevens
+  in \cite{APUE} riporta come limite anche il fatto che la comunicazione è
+  unidirezionale, 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 derivare da uno stesso processo padre che ha aperto la pipe,
+o, più comunemente, essere nella relazione padre/figlio.
+
+
+
+\subsection{Un esempio dell'uso delle pipe}
+\label{sec:ipc_pipe_use}
+
+Per capire meglio il funzionamento di una pipe faremo un esempio di quello che
+è il loro uso più comune, analogo a quello effettuato della shell, e che
+consiste nell'inviare l'output di un processo (lo standard output) sull'input
+di un'altro. Realizzaremo il programma nella forma di un
+\textit{cgi}\footnote{NdA, inserire una breve descrizione di cosa è un cgi.}
+per apache, che genera una immagine JPEG di un codice a barre, specificato
+come parametro di input.
+
+Un programma che deve essere eseguito come \textit{cgi} per apache deve
+rispondere a delle caratteristiche specifiche, esso infatti non viene lanciato
+da una shell, ma dallo stesso web server, alla richiesta di una specifica URL
+che di solito ha la forma:
+\begin{verbatim}
+http://www.sito.it/cgi-bin/programma?parametro
+\end{verbatim}
+ed il risultato dell'elaborazione deve essere presentato (con una intestazione
+che ne descrive il mime-type) sullo standard output, in modo che apache possa
+reinviarlo al browser che ha effettuato la richiesta.
+
+
+Per fare questo useremo in sequenza i programmi \cmd{barcode} e \cmd{gs}, il
+primo infatti è in grado di generare immagini postscript di codici a barre
+corrispondenti ad una qualunque stringa, mentre il secondo serve per poter
+effettuare la conversione della stessa immagine in formato JPEG.
+
+Si potrebbe obiettare che sarebbe molto più semplice salvare il risultato
+intermedio su un file temporaneo. Questo però non tiene conto del fatto che il
+\textit{cgi} deve poter gestire più richieste in concorrenza, e si avrebbe una
+evidente race condition in caso di accesso simultaneo a detto
+file.\footnote{la questione potrebbe essere evitata creando prima dei file
+  temporanei, da comunicare poi ai vari sotto-processi, da cancellare alla
+  fine dell'esecuzione; ma a questo punto avremmo perso tutta la semplicità.}
+L'uso di una pipe invece permette di risolvere il problema in maniera semplice
+ed elegante.
+
+Il programma ci servirà anche come esempio dell'uso di alcune delle funzioni
+di manipolazione dei file descriptor, come \func{dup} e \func{dup2}, viste in
+\secref{sec:file_dup}; è attraverso queste funzioni che è possibile dirottare
+gli stream standard dei processi (che abbiamo visto in
+\secref{sec:file_std_descr} e \secref{sec:file_std_stream}) sulla pipe. Le
+sezioni significative del programma è riportato in
+\figref{fig:ipc_barcode_code}, il codice è disponibile nel file
+\file{BarCode.c} nella directory dei sorgenti.
+
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \begin{lstlisting}{}
+int main(int argc, char *argv[], char *envp[])
+{
+    ...
+    /* create two pipes to handle process communication */
+    if ( (retval = pipe(pipein)) ) {
+        WriteMess("input pipe creation error");
+        exit(0);        
+    }
+    if ( (retval = pipe(pipeout)) ) {
+        WriteMess("output pipe creation error");
+        exit(0);        
+    }    
+    /* First fork: use child to run barcode program */
+    if ( (pid = fork()) == -1) {          /* on error exit */
+        WriteMess("child creation error");
+        exit(0);        
+    }
+    /* if child */
+    if (pid == 0) {
+        close(pipein[1]);                /* close pipe write end  */
+        dup2(pipein[0], STDIN_FILENO);   /* remap stdin to pipe read end */
+        close(pipeout[0]);
+        dup2(pipeout[1], STDOUT_FILENO); /* remap stdout in pipe output */
+        execlp("barcode", "barcode", size, NULL); //"-o", "-",  NULL);
+    } 
+    close(pipein[0]);                    /* close input side of input pipe */
+    write(pipein[1], argv[1], strlen(argv[1]));  /* write parameter to pipe */
+    close(pipein[1]);                    /* closing write end */
+    waitpid(pid, NULL, 0);               /* wait child completion */
+    /* Second fork: use child to run ghostscript */
+    if ( (pid = fork()) == -1) {          /* on error exit */
+        WriteMess("child creation error");
+        exit(0);
+    }
+    /* second child, convert PS to JPEG  */
+    if (pid == 0) {                     
+        close(pipeout[1]);              /* close write end */
+        dup2(pipeout[0], STDIN_FILENO); /* remap read end to stdin */
+        /* send mime type */
+        write(STDOUT_FILENO, content, strlen(content));
+        execlp("gs", "gs", "-q", "-sDEVICE=jpeg", "-sOutputFile=-", "-", NULL);
+    }
+    /* still parent */
+    close(pipeout[1]); 
+    waitpid(pid, NULL, 0);
+    exit(0);
+}
+    \end{lstlisting}
+  \end{minipage} 
+  \normalsize 
+  \caption{Codice del \textit{cgi-bin} \cmd{BarCode}.}
+  \label{fig:ipc_barcode_code}
+\end{figure}
+
+Il primo passo (\texttt{\small 4--12}) è quello di creare le due pipe che
+servono per la comunicazione fra i due programmi che verranno utilizzati per
+produrre il codice a barre; si ha cura di controllare la riuscita della
+chiamata, inviando in caso di errore un messaggio invece dell'immagine
+richiesta.\footnote{la funzione \func{WriteMess}, non è riportata in
+  \ref{fig:ipc_barcode_code}, ma si incarica semplicemente di formattare
+  l'uscita, aggiungendo un \textit{mime type}, in modo che possa essere
+  interpretata direttamente da un browser.}
+
+Una volta create le pipe il programma può creare (\texttt{\small 13-17}) il
+primo processo figlio, che si incaricherà (\texttt{\small 19--25}) di eseguire
+il programma \cmd{barcode}: quest'ultimo funziona ricevendo dallo standard
+input la stringa da convertire nell'immagine postscript del codice a barre,
+che sarà scritta sullo standard output.
+
+Per utilizzare queste caratteristiche il primo figlio chiude (\texttt{\small
+  20}) il capo aperto in scrittura della prima pipe, dato che userà il capo
+aperto in lettura per ricevere dal padre la stringa da codificare; per far
+questo collega (\texttt{\small 21}) il capo in lettura della pipe allo
+standard input usando \func{dup2}. Dato che \cmd{barcode} scrive l'immagine
+postscript del codice a barre sullo standard output per poter effettuare una
+ulteriore redirezione il capo in lettura della seconda pipe viene chiuso
+(\texttt{\small 22}) mentre il capo in scrittura viene collegato allo standard
+output (\texttt{\small 23}).  
+
+In questo modo all'esecuzione (\texttt{\small 25}) di \cmd{barcode} (cui si
+passa in \var{size} la dimensione per l'immagine) quest'ultimo leggerà la
+stringa da codificare che gli viene inviata dal padre dalla prima pipe e
+scriverà l'immagine postscript del codice a barre sulla seconda.
+
+Dall'altra parte il processo padre prima chiude (\texttt{\small 26}) il capo
+inutilizzato della prima pipe (quello in input), poi scrive (\texttt{\small
+  27}) la stringa da convertire sul capo in output così che \cmd{barcode}
+possa riceverla dallo standard input; a questo punto l'uso della prima pipe è
+finito ed essa può essere definitivamente chiusa (\texttt{\small 28}), si
+attende poi (\texttt{\small 29}) che l'esecuzione di \cmd{barcode} sia
+completata.
+
+Alla conclusione della sua esecuzione \cmd{barcode} avrà effettuato inviato
+l'immagine postscript del codice a barre sul capo in scrittura della seconda
+pipe; a questo punto si può eseguire la seconda conversione, da PS a JPEG,
+usando il programma \cmd{gs}. Per questo si crea (\texttt{\small 30--34}) un
+secondo processo figlio, che poi (\texttt{\small 35--42}) eseguirà questo
+programma leggendo l'immagine postscript creata da \cmd{barcode} sullo
+standard input per convertirla in JPEG.
 
-\section{System V IPC}
+Per fare tutto ciò il secondo figlio anzitutto chiude (\texttt{\small 37}) il
+capo in scrittura della seconda pipe, e collega (\texttt{\small 38}) il capo
+in lettura allo standard input. Per poter formattare l'output del programma in
+maniera utilizzabile da un browser, si provvede anche \texttt{\small 40}) alla
+scrittura dell'apposita stringa di mime-type in testa allo standard output. A
+questo punto si può invocare \texttt{\small 41}) il programma \cmd{gs},
+provvedendo gli appositi switch che consentono di leggere il file da
+convertire dallo standard input, ed inviare la conversione sullo standard
+output.
+
+Per concludere le operazioni il processo padre chiude \texttt{\small 44}) il
+capo in scrittura della seconda pipe, e attende la conclusione del figlio
+\texttt{\small 45}), per poi uscire \texttt{\small 46}). Si tenga conto che,
+l'operazione di chiudere il capo in scrittura della seconda pipe è necessaria,
+infatti non chiudendola \cmd{gs}, che legge il suo stardard input da detta
+pipe, resterebbe bloccato in attesa di ulteriore input (l'unico modo che un
+programma ha per sapere che l'input è terminato è rilevare che lo standard
+input è stato chiuso), e la \func{wait} non ritornerebbe. 
+
+
+\subsection{Le funzioni \func{popen} e \func{pclose}}
+\label{sec:ipc_popen}
+
+Come si è visto la modalità più comune di utilizzo di una pipe è quella di
+utilizzarla per fare da tramite fra output ed input di due programmi invocati
+in sequenza; per questo motivo lo standard POSIX.2 ha introdotto due funzioni
+che permettono di sintetizzare queste operazioni. La prima di esse si chiama
+\func{popen} ed il suo prototipo è:
+\begin{prototype}{stdio.h}
+{FILE *popen(const char *command, const char *type)}
+
+Esegue il programma \param{command}, di cui, a seconda di \param{type},
+restituisce, lo standard input o lo standard output nella pipe collegata allo
+stream restituito come valore di ritorno.
+  
+\bodydesc{La funzione restituisce l'indirizzo dello stream associato alla pipe
+  in caso di successo e \macro{NULL} per un errore, nel qual caso \var{errno}
+  potrà assumere i valori relativi alle sottostanti invocazioni di \func{pipe}
+  e \func{fork} o \macro{EINVAL} se \param{type} non è valido.}
+\end{prototype}
+\noindent e serve per semplificare l'uso di \func{pipe}. 
+
+La funzione crea una pipe, esegue una \func{fork}, ed invoca il programma
+\param{command} attraverso la shell (in sostanza esegue \file{/bin/sh} con il
+flag \code{-c}); l'argomento \param{type} deve essere una stringa \verb|"w"| o
+\verb|"r"|, per indicare se la pipe sarà collegata allo standard input o allo
+standard output del comando invocato.
+
+La funzione restituisce il puntatore allo stream associato alla pipe creata,
+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
+standard visti in \secref{cha:files_std_interface}, e viene sempre aperto in
+modalità \textit{fully-buffered} (vedi \secref{sec:file_buffering}); l'unica
+differenza è che deve essere chiuso dalla seconda delle due funzioni,
+\func{pclose}, il cui prototipo è:
+\begin{prototype}{stdio.h}
+{int pclose(FILE *stream)}
+
+Chiude il file \param{stream}, restituito da una prededente \func{popen}
+attendendo la terminazione del processo ad essa associato.
+  
+\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+  errore; nel quel caso il valore di \func{errno} deriva dalle sottostanti
+  chiamate.}
+\end{prototype}
+\noindent che si incarica anche di attendere la conclusione del processo
+creato dalla precedente \func{popen}.
+
+Per illustrare l'uso di queste due funzioni riprendiamo l'esempio in
+\figref{fig:ipc_barcode_code}: esso per quanto funzionante, è piuttosto
+complesso; inoltre nella pratica sconta un problema di \cmd{gs} che non è in
+grado\footnote{nella versione GNU Ghostscript 6.53 (2002-02-13).} di
+riconoscere correttamente l'encapsulated postscript, per cui tutte le volte
+generata una pagina intera, invece che una semplice figura.  Se si vuole
+generare una immagine di dimensioni corrette si deve allora ricorrere ad
+ulteriore programma, \cmd{epstopsf}, per convertire in PDF il file EPS
+generato da \cmd{barcode}. Utilizzando un file in PDF invece, \cmd{gs} esegue
+la conversione rispettando le dimensioni originarie del codice a barre.
+
+
+
+
+
+\subsection{Le \textit{pipe} con nome, o \textit{fifo}}
+\label{sec:ipc_named_pipe}
+
+Come accennato in \secref{sec:ipc_pipes} il problema delle \textit{pipe} è che
+esse possono essere utilizzate solo da processi con un progenitore comune o
+nella relazione padre/figlio; per superare questo problema lo standard POSIX.1
+ha definito dei nuovi oggetti, le \textit{fifo}, che hanno le stesse
+caratteristiche delle pipe, ma invece che essere struttura interne del kernel
+visibili solo attraverso un file descriptor comune, possono essere viste
+attraverso un inode che risiede sul filesystem.
+
+
+Abbiamo già accennato in \secref{sec:file_mknod}
+
+che invece possono risiedere
+sul filesystem, e che i processi possono usare per le comunicazioni senza
+dovere per forza essere in relazione diretta.
+
+
+
+
+Per poter superare il problema delle \textit{pipe}, illustrato in
+\secref{sec:ipc_pipes}, che ne consente l'uso solo fra processi con un
+progenitore comune o nella relazione padre/figlio,
+  
+\section{La comunicazione fra processi di System V}
 \label{sec:ipc_sysv}
 
-\section{Code di messaggi}
+Per ovviare ai vari limiti dei meccanismo tradizionale di comunicazione fra
+processi visto in \secref{sec:ipc_unix}, nello sviluppo di System V vennero
+introdotti una serie di nuovi oggetti e relative interfacce che garantissero
+una maggiore flessibilità; in questa sezione esamineremo quello che viene
+ormai chiamato il \textit{System V Inter-Process Comunication System}, più
+comunemente noto come \textit{SystemV IPC}.
+
+\subsection{Code di messaggi}
 \label{sec:ipc_messque}
 
-\section{Semafori}
+Il primo oggetto introdotto dal \textit{SystemV IPC} è quello delle code di
+messaggi.
+
+\subsection{Semafori}
 \label{sec:ipc_semaph}
 
-\section{Memoria condivisa}
+Il secondo oggetto introdotto dal \textit{SystemV IPC} è quello dei semafori.
+
+
+\subsection{Memoria condivisa}
 \label{sec:ipc_shar_mem}
 
+Il terzo oggetto introdotto dal \textit{SystemV IPC} è quello della memoria
+condivisa.
+
+%%% Local Variables: 
+%%% mode: latex
+%%% TeX-master: "gapil"
+%%% End: