Altra roba connessa con le pipe
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index 21fae712f9ee9894e9c5061670b5b847cd8c4cbc..898305fdd703de19aeb56ca31e5e53d9f23f2bb6 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -1,4 +1,4 @@
-f\chapter{La comunicazione fra processi}
+\chapter{La comunicazione fra processi}
 \label{cha:IPC}
 
 
@@ -94,8 +94,8 @@ 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,
@@ -110,11 +110,11 @@ 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.}
+\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-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:
@@ -133,13 +133,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 +167,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 +209,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
-l'esecuzione di \cmd{barcode} venga completata.
+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 
-
-
+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.
+
+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}}
@@ -256,19 +281,61 @@ pipe; a questo punto
 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 è:
-
-
-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.
+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.
 
 
 
@@ -277,15 +344,27 @@ file EPS generato da \cmd{barcode}, che invece viene trattato correttamente.
 \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.
+
+
+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}