From: Simone Piccardi Date: Tue, 2 Jul 2002 22:23:58 +0000 (+0000) Subject: Completate pure le fifo. X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=commitdiff_plain;h=1fe9dd622fcc8e8c83de032cf8679806cf52359b Completate pure le fifo. --- diff --git a/fileunix.tex b/fileunix.tex index 40d0228..56e7043 100644 --- a/fileunix.tex +++ b/fileunix.tex @@ -221,7 +221,7 @@ sempre il file descriptor con il valore pi \hline % modalità di accesso al file \macro{O\_RDONLY} & apre il file in sola lettura. \\ \macro{O\_WRONLY} & apre il file in sola scrittura. \\ - \macro{O\_RDWR} & apre il file lettura/scrittura. \\ + \macro{O\_RDWR} & apre il file in lettura/scrittura. \\ \hline % modalità di apertura del file \hline \macro{O\_CREAT} & se il file non esiste verrà creato, con le regole di @@ -232,8 +232,8 @@ sempre il file descriptor con il valore pi \func{open} con \macro{EEXIST}. \\ \macro{O\_NONBLOCK} & apre il file in modalità non bloccante. Questo valore specifica anche una modalità di operazione (vedi sotto), e - comporta che \func{open} ritorni immediatamente (torneremo su - questo in \secref{sec:file_noblocking}). \\ + comporta che \func{open} ritorni immediatamente (l'opzione ha senso + solo per le fifo, torneremo questo in \secref{sec:ipc_named_pipe}). \\ \macro{O\_NOCTTY} & se \var{pathname} si riferisce ad un device di terminale, questo non diventerà il terminale di controllo, anche se il processo non ne ha ancora uno (si veda \secref{sec:sess_xxx}). \\ @@ -265,10 +265,11 @@ sempre il file descriptor con il valore pi file. Può causare corruzione del file con NFS se più di un processo scrive allo stesso tempo.\footnotemark\\ \macro{O\_NONBLOCK} & il file viene aperto in modalità non bloccante per - le operazioni di I/O: questo significa il fallimento di \func{read} in - assenza di dati da leggere e quello di \func{write} in caso di - impossibilità di scrivere immediatamente. L'opzione è effettiva solo per - le fifo e per alcuni file di dispositivo. \\ + le operazioni di I/O (che tratteremo in \secref{sec:file_noblocking}): + questo significa il fallimento di \func{read} in assenza di dati da + leggere e quello di \func{write} in caso di impossibilità di scrivere + immediatamente. Questa modalità ha senso solo per le fifo e per alcuni + file di dispositivo. \\ \macro{O\_NDELAY} & in Linux\footnotemark\ è sinonimo di \macro{O\_NONBLOCK}.\\ \macro{O\_ASYNC} & apre il file per l'I/O in modalità @@ -295,9 +296,9 @@ sempre il file descriptor con il valore pi di usare un file con un nome univoco e la funzione \func{link} per verificarne l'esistenza.} -\footnotetext[3]{Denial of Service, si chiamano così attacchi miranti ad - impedire un servizio causando una qualche forma di carico eccessivo per il - sistema, che resta bloccato nelle risposte all'attacco.} +\footnotetext[3]{\textit{Denial of Service}, si chiamano così attacchi miranti + ad impedire un servizio causando una qualche forma di carico eccessivo per + il sistema, che resta bloccato nelle risposte all'attacco.} \footnotetext[4]{il problema è che NFS non supporta la scrittura in append, ed il kernel deve simularla, ma questo comporta la possibilità di una race 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}