Aggiunte varie sempre sui segnali real-time
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index 3c30111cebf747b7316715bdcc672a4e373b441c..03bc5e790755d3525bed19df604eb9b2e8cc9c4e 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
@@ -101,6 +101,23 @@ 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.
 
+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
+si esegue una scrittura su una pipe il cui capo in lettura non è aperto il
+processo riceverà il segnale \macro{EPIPE}, e la funzione di scrittura
+restituirà un errore di \macro{EPIPE} (al ritorno del manipolatore, o qualora
+il segnale sia ignorato o bloccato).
+
+La dimensione del buffer della pipe (\macro{PIPE\_BUF}) ci dà inoltre un'altra
+importante informazione riguardo il comportamento delle operazioni di lettura
+e scrittura su di una pipe; esse infatti sono atomiche fintanto che la
+quantità di dati da scrivere non supera questa dimensione. Qualora ad esempio
+si effettui una scrittura di una quantità di dati superiore l'operazione verrà
+effettuata in più riprese, consentendo l'intromissione di scritture effettuate
+da altri processi.
+
 
 \subsection{Un esempio dell'uso delle pipe}
 \label{sec:ipc_pipe_use}
@@ -108,7 +125,7 @@ o, pi
 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
+di un'altro. Realizzeremo 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
@@ -148,18 +165,19 @@ intermedio su un file temporaneo. Questo per
 \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{il problema potrebbe essere superato determinando in anticipo
-  un nome appropiato per il file temporaneo, che verrebbe utilizzato dai vari
+  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
 \secref{sec:file_dup}, in particolare di \func{dup2}. È attraverso queste
 funzioni infatti 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. In \figref{fig:ipc_barcode_code}
-abbiamo riportato il corpo del programm, il cui codice completo è disponibile
+\secref{sec:file_std_stream}) sulla pipe. In \figref{fig:ipc_barcodepage_code}
+abbiamo riportato il corpo del programma, il cui codice completo è disponibile
 nel file \file{BarCodePage.c} che si trova nella directory dei sorgenti.
 
 
@@ -219,7 +237,7 @@ int main(int argc, char *argv[], char *envp[])
   \normalsize 
   \caption{Sezione principale del codice del \textit{CGI} 
     \file{BarCodePage.c}.}
-  \label{fig:ipc_barcode_code}
+  \label{fig:ipc_barcodepage_code}
 \end{figure}
 
 La prima operazione del programma (\texttt{\small 4--12}) è quella di creare
@@ -227,10 +245,10 @@ 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
-  \secref{fig:ipc_barcode_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 quest'ultimo possa essere
-  visualizzato correttamente da un browser.}
+  \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
+  quest'ultimo possa essere visualizzato correttamente 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
@@ -285,7 +303,7 @@ capo in scrittura della seconda pipe, e attende la conclusione del figlio
 (\texttt{\small 45}); a questo punto può (\texttt{\small 46}) uscire. Si tenga
 conto che l'operazione di chiudere il capo in scrittura della seconda pipe è
 necessaria, infatti, se non venisse chiusa, \cmd{gs}, che legge il suo
-stardard input da detta pipe, resterebbe bloccato in attesa di ulteriori dati
+standard input da detta pipe, resterebbe bloccato in attesa di ulteriori dati
 in ingresso (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.
@@ -332,7 +350,7 @@ 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}
+Chiude il file \param{stream}, restituito da una precedente \func{popen}
 attendendo la terminazione del processo ad essa associato.
   
 \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
@@ -344,8 +362,8 @@ attendendo la terminazione del processo ad essa associato.
 \func{popen}.
 
 Per illustrare l'uso di queste due funzioni riprendiamo il problema
-precedente: il programma mostrato in \figref{fig:ipc_barcode_code} per quanto
-funzionante, è (volutamente) codificato in maniera piuttosto complessa,
+precedente: il programma mostrato in \figref{fig:ipc_barcodepage_code} per
+quanto funzionante, è (volutamente) codificato in maniera piuttosto complessa,
 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 deve essere usato
@@ -380,19 +398,19 @@ dimensioni corrette attraverso vari programmi di manipolazione (\cmd{pnmcrop},
 
 In questo caso però occorre eseguire in sequenza ben quattro comandi diversi,
 inviando l'output di ciascuno all'input del successivo, per poi ottenere il
-risultato finale sullo standard output; un caso classico di utilizzazione
+risultato finale sullo standard output: un caso classico di utilizzazione
 delle pipe, in cui l'uso di \func{popen} e \func{pclose} permette di
 semplificare notevolmente la stesura del codice.
 
 Nel nostro caso, dato che 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
+\figref{fig:ipc_barcode_code}.  Come si può notare l'ordine di invocazione dei
+programmi è l'inverso di quello in cui ci si aspetta che vengano
+effettivamente eseguiti. Questo non comporta nessun problema dato che 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
+risultato dell'elaborazione del precedente, benchè quest'ultimo venga
 invocato dopo.
 
 \begin{figure}[!htb]
@@ -427,12 +445,6 @@ int main(int argc, char *argv[], char *envp[])
         pclose((pipe[i]));
     }
     exit(0);
-}
-void WriteMess(char *mess)
-{
-    printf("Content-type: text/html\n\n");
-    perror(mess);
-    printf("<br>\n");
 }
     \end{lstlisting}
   \end{minipage} 
@@ -472,63 +484,169 @@ Come accennato in \secref{sec:ipc_pipes} il problema delle \textit{pipe} 
 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.
+caratteristiche delle pipe, ma che invece di essere strutture interne del
+kernel, visibili solo attraverso un file descriptor, sono accessibili
+attraverso un inode che risiede sul filesystem, così che i processi le possono
+usare senza dovere per forza essere in una relazione di \textsl{parentela}.
+
+Utilizzando una \textit{fifo} tutti i dati passeranno, come per le pipe,
+attraverso un apposito buffer nel kernel, senza transitare dal filesystem;
+l'inode allocato sul filesystem serve infatti solo a fornire un punto di
+riferimento per i processi, che permetta loro di accedere alla stessa fifo; il
+comportamento delle funzioni di lettura e scrittura è identico a quello
+illustrato per le pipe in \secref{sec:ipc_pipes}.
+
+Abbiamo già visto in \secref{sec:file_mknod} le funzioni \func{mknod} e
+\func{mkfifo} che permettono di creare una fifo; per utilizzarne una un
+processo non avrà che da aprire il relativo file speciale o in lettura o
+scrittura; nel primo caso sarà collegato al capo di uscita della fifo, e dovrà
+leggere, nel secondo al capo di ingresso, e dovrà scrivere.
+
+Il kernel crea una singola pipe per ciascuna fifo che sia stata aperta, che può
+essere acceduta contemporaneamente da più processi, sia in lettura che in
+scrittura. Dato che per funzionare deve essere aperta in entrambe le
+direzioni, per una fifo di norma la funzione \func{open} si blocca se viene
+eseguita quando l'altro capo non è aperto.
+
+Le fifo però possono essere anche aperte in modalità \textsl{non-bloccante},
+nel qual caso l'apertura del capo in lettura avrà successo solo quando anche
+l'altro capo è aperto, mentre l'apertura del capo in scrittura restituirà
+l'errore di \macro{ENXIO} fintanto che non verrà aperto il capo in lettura.
+
+In Linux\footnote{lo standard POSIX lascia indefinito questo comportamento.} è
+possibile aprire le fifo anche in lettura/scrittura, operazione che avrà
+sempre successo immediato qualunque sia la modalità di apertura (bloccante e
+non bloccante); questo può essere utilizzato per aprire comunque una fifo in
+scrittura anche se non ci sono ancora processi il lettura; è possibile anche
+usare la fifo all'interno di un solo processo, nel qual caso però occorre
+stare molto attenti alla possibili deadlock.\footnote{se si cerca di leggere
+  da una fifo che non contiene dati si avrà un deadlock immediato, dato che il
+  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}.
 
-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.  
 
 
+\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; per cui una situazione in cui un processo scrive
+qualcosa che molti altri devono poter leggere non può essere implementata in
+maniera semplice con una pipe.
 
-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).
+Per superarne questi limiti nello sviluppo di System V vennero introdotti una
+serie di nuovi oggetti di comunicazione e relative interfacce di
+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)}.
 
-che invece possono risiedere
-sul filesystem, e che i processi possono usare per le comunicazioni senza
-dovere per forza essere in relazione diretta.
+
+
+\subsection{Considerazioni generali}
+\label{sec:ipc_sysv_generic}
+
+La principale caratteristica, (che può essere considerato anche uno dei suoi
+maggiori difetti) del sistema di IPC di System V è che è basato su oggetti che
+risiedono nel kernel, a differenza delle pipe che sono locali ai processi che
+condividono lo stesso file descriptor, e delle fifo, cui invece si accede
+attraverso il filesystem. 
+
+Ad essi si accede attraverso un identificatore generato autonomamente dal
+kernel alla loro creazione (come un numero intero progressivo, in maniera
+simile a quanto fatto per i \acr{pid}). A ciascun oggetto è pure associata una
+chiave, che di norma viene usata per ricavare l'identificatore. 
+
+Una seconda caratteristica di questi oggetti è che non prevedono un numero di
 
 
 
 
-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}
 
-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
+Il primo oggetto introdotto dal \textit{System V IPC} è quello delle code di
 messaggi.
 
 \subsection{Semafori}
 \label{sec:ipc_semaph}
 
-Il secondo oggetto introdotto dal \textit{SystemV IPC} è quello dei semafori.
+Il secondo oggetto introdotto dal \textit{System V IPC} è quello dei semafori.
 
 
 \subsection{Memoria condivisa}
 \label{sec:ipc_shar_mem}
 
-Il terzo oggetto introdotto dal \textit{SystemV IPC} è quello della memoria
+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"