\chapter{La comunicazione fra processi}
\label{cha:IPC}


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.

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{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}

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 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
%%% TeX-master: "gapil"
%%% End: 
