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}
\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.
\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.
\end{lstlisting}
\end{minipage}
\normalsize
- \caption{Codice del \textit{CGI} \cmd{BarCodePage}.}
- \label{fig:ipc_barcode_code}
+ \caption{Sezione principale del codice del \textit{CGI}
+ \file{BarCodePage.c}.}
+ \label{fig:ipc_barcodepage_code}
\end{figure}
La prima operazione del programma (\texttt{\small 4--12}) è quella di creare
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
Per poter utilizzare queste caratteristiche prima di eseguire \cmd{barcode} si
chiude (\texttt{\small 20}) il capo aperto in scrittura della prima pipe, e se
ne collega (\texttt{\small 21}) il capo in lettura allo standard input, usando
-\func{dup2}. Dato che \cmd{barcode} scrive l'immagine postscript del codice a
-barre sullo standard output, per poter effettuare una ulteriore redirezione il
-capo in lettura della seconda pipe viene chiuso (\texttt{\small 22}) mentre il
-capo in scrittura viene collegato allo standard output (\texttt{\small 23}).
+\func{dup2}. Si ricordi che invocando \func{dup2} il secondo file, qualora
+risulti aperto, viene, come nel caso corrente, chiuso prima di effettuare la
+duplicazione. Allo stesso modo, dato che \cmd{barcode} scrive l'immagine
+postscript del codice a barre sullo standard output, per poter effettuare una
+ulteriore redirezione il capo in lettura della seconda pipe viene chiuso
+(\texttt{\small 22}) mentre il capo in scrittura viene collegato allo standard
+output (\texttt{\small 23}).
In questo modo all'esecuzione (\texttt{\small 25}) di \cmd{barcode} (cui si
passa in \var{size} la dimensione della pagina per l'immagine) quest'ultimo
(\texttt{\small 26}) il capo inutilizzato della prima pipe (quello in input) e
poi scrive (\texttt{\small 27}) la stringa da convertire sul capo in output,
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 28}), si attende poi (\texttt{\small 29}) che l'esecuzione di
-\cmd{barcode} sia completata.
+l'uso della prima pipe da parte del padre è finito ed essa può essere
+definitivamente chiusa (\texttt{\small 28}), si attende poi (\texttt{\small
+ 29}) che l'esecuzione di \cmd{barcode} sia completata.
Alla conclusione della sua esecuzione \cmd{barcode} avrà inviato l'immagine
postscript del codice a barre sul capo in scrittura della seconda pipe; a
convertire dallo standard input e di inviare la conversione sullo standard
output.
-Per completare le operazioni il processo padre chiude \texttt{\small 44}) il
+Per completare le operazioni il processo padre chiude (\texttt{\small 44}) il
capo in scrittura della seconda pipe, e attende la conclusione del figlio
-\texttt{\small 45}); a questo punto può \texttt{\small 46}). 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 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.
+(\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
+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.
\subsection{Le funzioni \func{popen} e \func{pclose}}
\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
(tramite \func{wait4}) la conclusione del processo creato dalla precedente
\func{popen}.
-Per illustrare l'uso di queste due funzioni riprenderemo il problema
-precedente; il programma mostrato in \figref{fig:ipc_barcode_code} per quanto
-funzionante, è (volutamente) codificato in maniera piuttosto complesso;
+Per illustrare l'uso di queste due funzioni riprendiamo il problema
+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 tutte le volte
-generata una pagina intera, invece che semplice figura delle dimensioni
-corrispondenti al codice a barre.
-
-Se si vuole generare una immagine di dimensioni corrette si deve usare un
-approccio diverso; una possibilità sarebbe quella di ricorrere ad ulteriore
-programma, \cmd{epstopsf}, per convertire in PDF il file EPS generato da
-\cmd{barcode} (utilizzando lo switch \cmd{-E} di quest'ultimo). Utilizzando un
-PDF al posto di un EPS \cmd{gs} esegue la conversione rispettando le
-dimensioni originarie del codice a barre e produce un JPEG delle dimensioni
-adeguate.
+riconoscere correttamente l'encapsulated postscript, per cui deve essere usato
+il postscript e tutte le volte viene generata una pagina intera, invece che
+una immagine delle dimensioni corrispondenti al codice a barre.
+
+Se si vuole generare una immagine di dimensioni appropriate si deve usare un
+approccio diverso. Una possibilità sarebbe quella di ricorrere ad ulteriore
+programma, \cmd{epstopsf}, per convertire in PDF un file EPS (che può essere
+generato da \cmd{barcode} utilizzando lo switch \cmd{-E}). Utilizzando un PDF
+al posto di un EPS \cmd{gs} esegue la conversione rispettando le dimensioni
+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; una pipe però è rigidamente sequenziale,
-ed il tentativo di eseguire detta funzioni su un file descriptor associato ad
-una pipe comporta l'immediato fallimento con un errore di \macro{ESPIPE}.
-
-Per questo motivo si è utilizzata una strada diversa, che prevede la
+\func{lseek} sul file da convertire; se si esegue \cmd{gs} su un file normale
+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
+concatenazione di vari programmi funzionerà soltanto quando tutti prevedono
+una lettura sequenziale del loro input.
+
+Per questo motivo si è dovuto utilizzare una strada diversa, che prevede la
conversione attraverso \cmd{gs} del PS in un altro formato intermedio, il
PPM,\footnote{il \textit{Portable PixMap file format} è un formato usato
spesso come formato intermedio per effettuare conversioni, è estremamente
inefficiente, ma molto facile da manipolare dato che usa caratteri ASCII per
memorizzare le immagini.} dal quale poi si può ottenere un'immagine di
dimensioni corrette attraverso vari programmi di manipolazione (\cmd{pnmcrop},
-\cmd{pnmmargin}) che può essere infine trasformata in PNG.
+\cmd{pnmmargin}) che può essere infine trasformata in PNG (con \cmd{pnm2png}).
-In questo caso però occorre eseguire sequenza ben quattro comandi diversi,
+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, il caso più classico dell'uso delle
-pipe.
-
+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.
-Dato che questo caso ciascun processo deve scrivere il suo output sullo
+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 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 invocato dopo.
+scrittura. Il codice del nuovo programma è riportato in
+\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 precedente, benchè quest'ultimo venga
+invocato dopo.
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
\begin{lstlisting}{}
int main(int argc, char *argv[], char *envp[])
-{
-int main(int argc, char *argv[], char *envp[])
{
FILE *pipe[4];
FILE *pipein;
}
exit(0);
}
-/*
- * Routine to produce an HTML error message on output
- */
-void WriteMess(char *mess)
-{
- printf("Content-type: text/html\n\n");
- perror(mess);
- printf("<br>\n");
-}
-}
-
\end{lstlisting}
\end{minipage}
\normalsize
- \caption{Codice del \textit{cgi-bin} \cmd{BarCode2}.}
- \label{fig:ipc_barcode2_code}
+ \caption{Codice completo del \textit{CGI} \file{BarCode.c}.}
+ \label{fig:ipc_barcode_code}
\end{figure}
-Nel nostro caso il primo passo (\texttt{\small 12}) è scrivere il mime-type
+Nel nostro caso il primo passo (\texttt{\small 14}) è scrivere il mime-type
sullo standard output; a questo punto il processo padre non necessita più di
eseguire ulteriori operazioni sullo standard output e può tranquillamente
-provvedere alla redirezione. Il primo processo figlio ad essere invocato
-(\texttt{\small 14}) è necessariamente l'ultimo della sequenza, in quanto è
-lui che deve uscire sullo standard output, gli altri saranno tutti rediretti.
+provvedere alla redirezione.
+
+Dato che i vari programmi devono essere lanciati in successione, si è
+approntato un ciclo (\texttt{\small 15--19}) che esegue le operazioni in
+sequenza: prima crea una pipe (\texttt{\small 17}) per la scrittura eseguendo
+il programma con \func{popen}, in modo che essa sia collegata allo standard
+input, e poi redirige (\texttt{\small 18}) lo standard output su detta pipe.
-Una volta lanciato il processo finale si può iniziare la catena delle
-redirezioni; ogni volta (\texttt{\small 16} e \texttt{\small 20}) duplicheremo
-il file restituito dalla chiamata precedente a \func{popen} sullo standard
-output, in questo modo alla successiva chiamata di \func{popen} il processo
-eseguito scriverà il suo standard output sulla pipe collegata allo standard
-input del precedente.
+In questo modo il primo processo ad essere invocato (che è l'ultimo della
+catena) scriverà ancora sullo standard output del processo padre, ma i
+successivi, a causa di questa redirezione, scriveranno sulla pipe associata
+allo standard input del processo invocato nel ciclo precedente.
-Alla fine tutto quello che resta da fare è scrivere (\texttt{\small 22}) la
-stringa del codice a barre sulla pipe collegata allo standard input
-dell'ultimo processo lanciato, e poi chiudere tutte le pipe create con
-\func{pclose}.
+Alla fine tutto quello che resta da fare è lanciare (\texttt{\small 21}) il
+primo processo della catena, che nel caso è \cmd{barcode}, e scrivere
+(\texttt{\small 23}) la stringa del codice a barre sulla pipe, che è collegata
+al suo standard input, infine si può eseguire (\texttt{\small 24--27}) un
+ciclo, che chiuda, nell'ordine inverso rispetto a quello in cui le si sono
+create, tutte le pipe create con \func{pclose}.
\subsection{Le \textit{pipe} con nome, o \textit{fifo}}
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.
-
-
-
+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.}
+
+L'impiego più comune per le fifo è quello che le vede impegnate con un
+processo in
-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.
-
-
-
-
-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}.
+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.
+
+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}
-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.
%%% Local Variables: