Correzioni alla citazione del codice
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index bdbdf2c13d9068e85617b49f2ff16cc321cf416e..536d0960ce3a5c81630a339dc56c8f771f7ed484 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -6,7 +6,7 @@ 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.
+\textit{fifo} e i meccanismi di intercomunicazione di System V e quelli POSIX.
 
 Tralasceremo invece tutte le problematiche relative alla comunicazione
 attraverso la rete (e le relative interfacce) che saranno affrontate in
@@ -20,12 +20,11 @@ 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.
+Il primo meccanismo di comunicazione fra processi introdotto nei sistemi Unix,
+è quello delle cosiddette \textit{pipe}; esse costituiscono 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}
@@ -33,39 +32,36 @@ evoluto.
 
 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 è:
+sostanza di una una coppia di file descriptor\footnote{si tenga presente che
+  le pipe sono oggetti creati dal kernel e non risiedono su disco.} connessi
+fra di loro in modo che se quanto scrive su di uno si può rileggere
+dall'altro. Si viene così a costituire un canale di comunicazione tramite i
+due file descriptor, nella forma di un \textsl{tubo} (da cui il nome)
+attraverso cui fluiscono i dati.
+
+La funzione che permette di creare questa speciale coppia di file descriptor
+associati ad una \textit{pipe} è appunto \func{pipe}, ed il suo prototipo è:
 \begin{prototype}{unistd.h}
 {int pipe(int filedes[2])} 
   
-Crea una coppia di file descriptor associati ad una pipe.
+Crea una coppia di file descriptor associati ad una \textit{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
+La funzione restituisce la coppia di file descriptor nell'array
+\param{filedes}; il primo è aperto in lettura ed il secondo in scrittura. Come
+accennato concetto di funzionamento di una pipe è 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.
+nel file descriptor aperto in lettura. 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.
 
 \begin{figure}[htb]
   \centering
@@ -74,12 +70,12 @@ attraverso la 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
+Chiaramente creare una pipe all'interno di un singolo 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.
 
@@ -92,16 +88,16 @@ capo della pipe, l'altro pu
 \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
+comunicazione fra processi attraverso una pipe, utilizzando le proprietà
+ordinarie 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
+  unidirezionale, ma 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.
+devono comunque derivare da uno stesso processo padre in cui è avvenuta la
+creazione della pipe, o, più comunemente, essere nella relazione padre/figlio.
 
-A differenza di quanto avviene con i file normali la lettura da una pipe può
+A differenza di quanto avviene con i file normali, la lettura da una pipe può
 essere bloccante (qualora non siano presenti dati), inoltre se si legge da una
 pipe il cui capo in scrittura è stato chiuso, si avrà la ricezione di un EOF
 (vale a dire che la funzione \func{read} ritornerà restituendo 0).  Se invece
@@ -122,14 +118,14 @@ da altri processi.
 \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
+Per capire meglio il funzionamento delle 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{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.
+di un'altro. Realizzeremo il programma di esempio nella forma di un
+\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} deve rispondere a
 delle caratteristiche specifiche, esso infatti non viene lanciato da una
@@ -143,13 +139,13 @@ che ne descrive il mime-type) sullo standard output, in modo che il web-server
 possa reinviarlo al browser che ha effettuato la richiesta, che in questo modo
 è in grado di visualizzarlo opportunamente.
 
-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. Usando una
-pipe potremo inviare l'output del primo sull'input del secondo, secondo lo
-schema mostrato in \figref{fig:ipc_pipe_use}, in cui la direzione del flusso
-dei dati è data dalle frecce continue.
+Per realizzare quanto voluto 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. Usando una pipe potremo inviare l'output del primo sull'input del
+secondo, secondo lo schema mostrato in \figref{fig:ipc_pipe_use}, in cui la
+direzione del flusso dei dati è data dalle frecce continue.
 
 \begin{figure}[htb]
   \centering
@@ -168,7 +164,8 @@ file.\footnote{il problema potrebbe essere superato determinando in anticipo
   un nome appropriato per il file temporaneo, che verrebbe utilizzato dai vari
   sotto-processi, e cancellato alla fine della loro esecuzione; ma a questo le
   cose non sarebbero più tanto semplici.}  L'uso di una pipe invece permette
-di risolvere il problema in maniera semplice ed elegante.
+di risolvere il problema in maniera semplice ed elegante, oltre ad essere
+molto più efficiente, dato che non si deve scrivere su disco.
 
 Il programma ci servirà anche come esempio dell'uso delle funzioni di
 duplicazione dei file descriptor che abbiamo trattato in
@@ -187,7 +184,7 @@ nel file \file{BarCodePage.c} che si trova nella directory dei sorgenti.
 int main(int argc, char *argv[], char *envp[])
 {
     ...
-    /* create two pipes to handle process communication */
+    /* create two pipes, pipein and pipeout, to handle communication */
     if ( (retval = pipe(pipein)) ) {
         WriteMess("input pipe creation error");
         exit(0);        
@@ -207,14 +204,14 @@ int main(int argc, char *argv[], char *envp[])
         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);
+        execlp("barcode", "barcode", size, 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 */
+    if ( (pid = fork()) == -1) {
         WriteMess("child creation error");
         exit(0);
     }
@@ -243,7 +240,7 @@ La prima operazione del programma (\texttt{\small 4--12}) 
 le due pipe che serviranno per la comunicazione fra i due comandi 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
+richiesta.\footnote{la funzione \func{WriteMess} non è riportata in
   \secref{fig:ipc_barcodepage_code}; essa si incarica semplicemente di
   formattare l'uscita alla maniera dei CGI, aggiungendo l'opportuno
   \textit{mime type}, e formattando il messaggio in HTML, in modo che
@@ -379,7 +376,7 @@ originarie del codice a barre e produce un JPEG delle dimensioni adeguate.
 Questo però ci porta a scontrarci con una caratteristica peculiare delle pipe,
 che a prima vista non è evidente. Per poter effettuare la conversione di un
 PDF infatti è necessario, per la struttura del formato, dover eseguire delle
-\func{lseek} sul file da convertire; se si esegue \cmd{gs} su un file normale
+\func{lseek} sul file da convertire; se si esegue \cmd{gs} su un file regolare
 non ci sono problemi, ma una pipe però è rigidamente sequenziale, ed il
 tentativo di eseguire detta operazione su una pipe comporta l'immediato
 fallimento con un errore di \macro{ESPIPE}.  Questo ci dice che in generale la
@@ -523,23 +520,106 @@ stare molto attenti alla possibili deadlock.\footnote{se si cerca di leggere
   processo si blocca e non potrà quindi mai eseguire le funzioni di
   scrittura.}
 
-
+Per la loro caratteristica di essere accessibili attraverso il filesystem, è
+piuttosto frequente l'utilizzo di una fifo come canale di comunicazione nelle
+situazioni un processo deve ricevere informazioni dagli altri. In questo caso
+è fondamentale che le operazioni di scrittura siano atomiche; per questo si
+deve sempre tenere presente che questo è vero soltanto fintanto che non si
+supera il limite delle dimensioni di \macro{PIPE\_BUF} (si ricordi quanto
+detto in \secref{sec:ipc_pipes}).
+
+A parte il precedente, che resta probabilmente il più comune, Stevens riporta
+in \cite{APUE} altre due casistiche principali per l'uso delle fifo:
+\begin{itemize}
+\item Da parte dei comandi di shell, per evitare la creazione di file
+  temporanei quando si devono inviare i dati di uscita di un processo
+  sull'input di parecchi altri (attraverso l'uso del comando \cmd{tee}).
   
+\item Come canale di comunicazione fra un client ed un server (il modello
+  \textit{client-server} è illustrato in \secref{sec:net_cliserv}).
+\end{itemize}
+
+Nel primo caso quello che si fa è creare tante pipe quanti sono i processi a
+cui i vogliono inviare i dati, da usare come standard input per gli stessi; una
+volta che li si saranno posti in esecuzione ridirigendo lo standard input si
+potrà eseguire il processo iniziale replicandone, con il comando \cmd{tee},
+l'output sulle pipe.
+
+Il secondo caso è relativamente semplice qualora si debba comunicare con un
+processo alla volta (nel qual caso basta usare due pipe, una per leggere ed
+una per scrivere), le cose diventano invece molto più complesse quando si
+vuole effettuare una comunicazione fra il server ed un numero imprecisato di
+client; se il primo infatti può ricevere le richieste attraverso una fifo
+``nota'', per le risposte non si può fare altrettanto, dato che, per la
+struttura sequenziale delle fifo, i client dovrebbero sapere, prima di
+leggerli, quando i dati inviati sono destinati a loro.
+
+Per risolvere questo problema, si può usare un'architettura come quella
+illustrata da Stevens in \cite{APUE}, in cui le risposte vengono inviate su
+fifo temporanee identificate dal \acr{pid} dei client, ma in ogni caso il
+sistema è macchinoso e continua ad avere vari inconvenienti\footnote{lo stesso
+  Stevens nota come sia impossibile per il server sapere se un client è andato
+  in crash, con la possibilità di far restare le fifo temporanee sul
+  filesystem, come sia necessario intercettare \macro{SIGPIPE} dato che un
+  client può terminare dopo aver fatto una richiesta, ma prima che la risposta
+  sia inviata, e come occorra gestire il caso in cui non ci sono client attivi
+  (e la lettura dalla fifo nota restituisca al serve un end-of-file.}; in
+generale infatti l'interfaccia delle fifo non è adatta a risolvere questo tipo
+di problemi, che possono essere affrontati in maniera più semplice ed efficace
+o usando i \textit{socket}\index{socket} (che tratteremo in dettaglio a
+partire da \capref{cha:socket_intro}) o ricorrendo a diversi meccanismi di
+comunicazione, come quelli che esamineremo in \secref{sec:ipc_sysv}.
+
+
+
 \section{La comunicazione fra processi di System V}
 \label{sec:ipc_sysv}
 
 Benché le pipe (e le fifo) siano ancora ampiamente usate, esse presentano
 numerosi limiti, il principale dei quali è che il meccanismo di comunicazione
-è rigidamente sequenziale; una situazione in cui un processo scrive qualcosa
-che molti altri devono poter leggere non può essere implementata con una pipe.
+è rigidamente sequenziale; per questo una situazione in cui un processo scrive
+qualcosa che molti altri devono poter leggere non può essere implementata in
+maniera semplice con una pipe.
+
+Per superare questi limiti nello sviluppo di System V vennero introdotti una
+serie di nuovi oggetti di comunicazione e relative interfacce di
+programmazione in grado di garantire una maggiore flessibilità; in questa
+sezione esamineremo quello che viene ormai chiamato il \textsl{Sistema di
+  comunicazione inter-processo} di System V, (o \textit{System V IPC
+  (Inter-Process Comunication)}.
+
+
+
+\subsection{Considerazioni generali}
+\label{sec:ipc_sysv_generic}
+
+La principale caratteristica del sistema di IPC di System V è quella di essere
+basato su oggetti permanenti che risiedono nel kernel. Questi, a differenza di
+quanto avviene per i file descriptor, non mantengono un contatore dei
+riferimenti, pertanto non vengono cancellati dal sistema una volta che non
+sono più in uso. Questo comporta che, al contrario di quanto avviene per pipe
+e fifo, la memoria allocata per questi oggetti non viene rilasciata
+automaticamente, ed essi devono essere cancellati esplicitamente, altrimenti
+resteranno attivi fintanto che non si riavvia il sistema. 
+
+Gli oggetti usati nel System V IPC vengono creati direttamente dal kernel, e
+sono accessibili solo specificando il relativo \textsl{identificatore}, che è
+il numero progressivo che il kernel gli assengna quanto vengono creati (il
+prodedimento è simile a quello con cui si assegna il \acr{pid} dei processi).
+
+L'identificatore è in genere restituito dalle funzioni che creano l'oggetto,
+nasce quindi il problema di come processi diversi possono accedere allo stesso
+oggetto. Per far questo a ciascuno di essi viene anche associata una
+\textsl{chiave}, che può essere indicata in fasi di creazione. Usando la
+stessa chiave due processi diversi potranno ricavare l'identificatore
+associato ad un oggetto e accedervi entrambi.
+
+Questa caratteristica mostra il primo dei problemi associati al sistema di IPC
+di System V. Un secondo problema riguarda le modalità per l'accesso a questi
+oggetti. 
+
+
 
-Per superarne i vari limiti, nello sviluppo di System V vennero introdotti una
-serie di nuovi oggetti di comunicazione e relative interfacce id
-programmazione che garantissero una maggiore flessibilità; in questa sezione
-esamineremo quello che viene ormai chiamato il \textsl{Sistema di
-  comunicazione inter-processo} di System V , più comunemente noto come
-\textit{System V IPC (Inter-Process Comunication)}.
 
 \subsection{Code di messaggi}
 \label{sec:ipc_messque}
@@ -559,6 +639,19 @@ Il secondo oggetto introdotto dal \textit{System V IPC} 
 Il terzo oggetto introdotto dal \textit{System V IPC} è quello della memoria
 condivisa.
 
+
+
+
+\section{La comunicazione fra processi di POSIX}
+\label{sec:ipc_posix}
+
+Lo standard POSIX.1b ha introdotto dei nuovi meccanismi di comunicazione,
+rifacendosi a quelli di System V, introducendo una nuova interfaccia che
+evitasse i principali problemi evidenziati in ...
+
+
+
+
 %%% Local Variables: 
 %%% mode: latex
 %%% TeX-master: "gapil"