Si prosegue
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index f86a851e9fb41c5b43913f428d8e80354758fd15..7dd8c67907ad02b670c4e76a5a8482cee72705f8 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
 \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 capitolo affronteremo solo alcuni dei 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.
+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.
 
-Esistono pure sistemi più complessi ed evoluti come le RPC (\textit{Remote
-  Procedure Calls}) e CORBA (\textit{Common Object Request Brocker
-  Architecture}) che non saranno affrontati qui.
 
 
 \section{La comunicazione fra processi tradizionale}
 \label{sec:ipc_unix}
 
-Il primo meccanismo di comunicazione fra processi usato dai sistemi unix-like
-è quello delle \textit{pipe}, in questa sezione descriveremo le sue basi, le
-funzioni che ne gestiscono l'uso e le varie forme in cui si è evoluto.
+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}
 
+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
+  riporta in APUE come limite anche il fatto che la comunicazione è
+  unidirezionale, in realtà questo è un limite facilmente risolvibile 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-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.
+
+Un programma che deve essere eseguito come \textit{cgi-bin} 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-bin} 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.
+
+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);        
+    }    
+    /* fork child to run barcode program */
+    pid = fork();
+    if (pid == -1) {
+        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);
+        }
+    }
+    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, 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; 
+
+
+
+
+\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 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.
+
+
+
+
 
 
 \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
+sul filesystem, e che i processi possono usare per le comunicazioni senza
+dovere per forza essere in relazione diretta.
 
 
 
+  
 \section{La comunicazione fra processi di System V}
 \label{sec:ipc_sysv}
 
-Per ovviare ad i vari limiti dei meccanismo tradizionale di comunicazione fra
-processi basato sulle \textit{pipe}, nello sviluppo di System V vennero
-introdotti una serie di nuovi oggetti che garantissero una maggiore
-flessibilità; in questa sezione esamineremo quello che viene ormai chiamato il
-sistema \textit{SystemV IPC}.
+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}
 
+Il primo oggetto introdotto dal \textit{SystemV IPC} è quello delle code di
+messaggi.
+
 \subsection{Semafori}
 \label{sec:ipc_semaph}
 
+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