X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=cd9c68fed1b9596b3bf07e68eb041f09b5aa82df;hp=3c30111cebf747b7316715bdcc672a4e373b441c;hb=e15bf09623a78b9a5ddc5cef72d54fe1f4c411a2;hpb=f554a11afa7c50c2b0267e890fb7581b6605384d diff --git a/ipc.tex b/ipc.tex index 3c30111..cd9c68f 100644 --- a/ipc.tex +++ b/ipc.tex @@ -101,6 +101,16 @@ 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). + + \subsection{Un esempio dell'uso delle pipe} \label{sec:ipc_pipe_use} @@ -158,8 +168,8 @@ 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 +229,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 +237,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 @@ -344,8 +354,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,16 +390,16 @@ 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 @@ -427,12 +437,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("
\n"); } \end{lstlisting} \end{minipage} @@ -472,33 +476,47 @@ 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. - -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. - - - - -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). - -che invece possono risiedere -sul filesystem, e che i processi possono usare per le comunicazioni senza -dovere per forza essere in relazione diretta. - - +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 sigola 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 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 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}