Nuovo esempio (funzionante) e primo abbozzo delle spiegazioni delle fifo.
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index 7dd8c67907ad02b670c4e76a5a8482cee72705f8..e5631536c274f154f1304afa51cb82241931b9e3 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -94,15 +94,14 @@ capo della pipe, l'altro pu
 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
-  riporta in APUE come limite anche il fatto che la comunicazione è
-  unidirezionale, in realtà questo è un limite facilmente risolvibile usando
+  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}
 
@@ -110,11 +109,12 @@ 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-bin}\footnote{breve descrizione, da fare, di cosa è un cgi-bin.}
-per apache, che genera una immagine JPEG di un codice a barre, specificato
-come parametro di input.
+\textit{CGI}\footnote{Un CGI (\textit{Common Gateway Interface} è un programma
+  che permette la creazione dinamica di un oggetto da inserire all'interno di
+  una pagina HTML.}  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-bin} per apache deve
+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:
@@ -125,7 +125,6 @@ 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
@@ -133,13 +132,13 @@ 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-bin} deve poter gestire più richieste in concorrenza, e si avrebbe
-una evidente race condition in caso di accesso simultaneo a detto
+\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 processi, e 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.
+  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
@@ -167,41 +166,39 @@ int main(int argc, char *argv[], char *envp[])
         WriteMess("output pipe creation error");
         exit(0);        
     }    
-    /* fork child to run barcode program */
-    pid = fork();
-    if (pid == -1) {
+    /* 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 output side of input pipe */
-        dup2(0, pipein[0]);      /* remap stdin in pipe input */
-        close(pipeout[0]);       /* close input side of output pipe */
-        dup2(1, pipeout[1]);     /* remap stdout in pipe output */
-        execlp("barcode", "barcode", "-E", NULL);
-    } else { 
-        /* first set the pipe */
-        close(pipein[0]);        /* close input side of input pipe */
-        close(pipeout[1]);       /* close output side of output pipe */
-        write(pipein[1], argv[1], strlen(argv[1]));
-        close(pipein[1]);
-        waitpid(pid, NULL, 0);
-        pid = fork();
-        if (pid == -1) {
-            WriteMess("child creation error")
-            exit(0);
-        }
-        if (pid == 0) {
-            /* send mime type */
-            write(0,content, strlen(content));
-            dup2(0, pipeout[0]);
-            execlp("gs", "gs", "-sDEVICE=jpeg", "-sOutputFile=-", "-", NULL);
-        } else {
-            close(pipeout[0]);
-            waitpid(pid, NULL, 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}
@@ -211,43 +208,70 @@ int main(int argc, char *argv[], char *envp[])
   \label{fig:ipc_barcode_code}
 \end{figure}
 
-
-Il primo passo (\texttt{\small 4-12}) è quello di creare le due pipe, una per
-l'input e l'altra per l'output, che servono per la comunicazione con i due
-programmi che verranno utilizzati, inviando in caso di errore (attraverso una
-apposita funzione \func{WriteMess}, non riportata in
-\ref{fig:ipc_barcode_code}, che si incarica di formattare l'output in HTML
-perché sia interpretabile da un browser) un messaggio invece dell'immagine
-richiesta.
-
-Una volta create le pipe il programma può creare (\texttt{\small 13-18}) il
-primo processo figlio, che si incaricherà (\texttt{\small 19-25}) di eseguire
-\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 questo il processo figlio prima chiude (\texttt{\small 21}) il capo aperto
-in scrittura della prima pipe (che sarà usato dal padre per trasmettergli la
-stringa da codificare), e poi collega (\texttt{\small 22}) il capo il lettura
-allo standard input usando \func{dup2}.  Analogamente il capo in lettura della
-seconda pipe sarà chiuso mentre il capo in scrittura viene collegato allo
-standard output (\texttt{\small 23-24}.  In questo modo all'esecuzione
-(\texttt{\small 25}) di \cmd{barcode} quest'ultimo leggerà la stringa da
-codificare dalla prima pipe e scriverà l'immagine postscript nella seconda.
-
-Dall'altra parte il processo padre prima chiude (\texttt{\small 28-29}) i due
-capi inutilizzati delle pipe (input della prima ed output della seconda), poi
-scrive (\texttt{\small 30}) la stringa da convertire sull'output della prima
-pipe 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 31}), si attenderà poi (\texttt{\small 32}) che pure
-l'esecuzione di \cmd{barcode} venga 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; 
-
-
+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à 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} dallo standard input,
+per convertirla in JPEG.
+
+Per fare tutto ciò il secondo figlio anzitutto chiude (\texttt{\small 37}) il
+capo in scrittura della seconda pipe, e ne 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}}
@@ -256,36 +280,146 @@ pipe;
 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 comuni in una sola
-chiamata. La prima di esse si chiama \func{popen} ed il suo prototipo è:
-
+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.
+
+Ci si trova dunque davanti al classico caso dell'uso delle pipe in cui si
+devono eseguire più processi in fila, inviando l'output di ciascuno all'input
+del successivo, per poi ottenere il risultato finale sullo standard output.
+Dato che questo caso ciascun processo deve scrivere il suo output sullo
+standard input del successivo, occorrerà usare \func{popen} aprendo la pipe in
+scrittura.
+
+Il codice del nuovo programma è riportato in \figref{fig:ipc_barcode2_code};
+come si può notare l'ordine di invocazione dei programmi è l'inverso di quello
+in cui ci si aspetta vengano effettivamente eseguiti. Questo non comporta
+nessun problema; infatti la lettura su una pipe è bloccante, per cui ciascun
+processo, per quanto lanciato per primo, si bloccherà in attesa di ricevere
+sullo standard input il risultato dell'elaborazione del precendente, benchè
+quest'ultimo venga invocato dopo.
 
-L'esempio in \figref{fig:ipc_barcode_code} per quanto perfettamente
-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}, che invece viene trattato correttamente.
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \begin{lstlisting}{}
+int main(int argc, char *argv[], char *envp[])
+{
+}
 
+    \end{lstlisting}
+  \end{minipage} 
+  \normalsize 
+  \caption{Codice del \textit{cgi-bin} \cmd{BarCode2}.}
+  \label{fig:ipc_barcode2_code}
+\end{figure}
 
+Nel nostro caso il primo passo (\texttt{\small 12}) è scrivere il mime-type
+sullo standard output; a questo punto il processo padre non necessita più di
+eseguire ulteriori operazioni sullo standard output e può tranquillamente
+provvedere alla redirezione. Il primo processo figlio ad essere invocato
+(\texttt{\small 14}) è necessariamente l'ultimo della sequenza, in quanto è
+lui che deve uscire sullo standard output, gli altri saranno tutti rediretti.
 
+Una volta lanciato il processo finale si può iniziare la catena delle
+redirezioni; ogni volta (\texttt{\small 16} e \texttt{\small 20}) duplicheremo
+il file restituito dalla chiamata precedente a \func{popen} sullo standard
+output, in questo modo alla successiva chiamata di \func{popen} il processo
+eseguito scriverà il suo standard output sulla pipe collegata allo standard
+input del precedente.
 
+Alla fine tutto quello che resta da fare è scrivere (\texttt{\small 22}) la
+stringa del codice a barre sulla pipe collegata allo standard input
+dell'ultimo processo lanciato, e poi chiudere tutte le pipe create con
+\func{pclose}.
 
 
 \subsection{Le \textit{pipe} con nome, o \textit{fifo}}
 \label{sec:ipc_named_pipe}
 
-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, lo standard POSIX.1
-definisce dei nuovi oggetti, le \textit{fifo}, che invece possono risiedere
+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.
+
+Utilizzando una fifo tutti i dati passeranno attraverso un apposito buffer nel
+kernel, senza transitare dal filesystem, l'inode serve solo a fornire un punto
+d'appoggio per i vari processi che permetta loro di accedere alla stessa
+fifo.  
+
+
+
+
+Abbiamo già visto in \secref{sec:file_mknod} le modalità che permettono di
+creare una fifo, attraverso le funzioni \func{mknod} e \func{mkfifo}; per
+utilizzarle un processo non avrà che da aprire il relativo file in lettura o
+scrittura (a seconda della direzione che si vuole dare ai dati).
+
+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}