X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=blobdiff_plain;f=ipc.tex;h=45917ebbbcd0505757b571501488b615e99ab410;hb=1eb95e2a35acc78407e7d988604719bb92da7253;hp=81ad3cf624dc3e73c0c3ddc8f23e3614bc778272;hpb=ffb12837c5ed8ccc095bc9c88349cd19b5e6b472;p=gapil.git diff --git a/ipc.tex b/ipc.tex index 81ad3cf..45917eb 100644 --- a/ipc.tex +++ b/ipc.tex @@ -1,6 +1,6 @@ %% ipc.tex %% -%% Copyright (C) 2000-2012 Simone Piccardi. Permission is granted to +%% Copyright (C) 2000-2013 Simone Piccardi. Permission is granted to %% copy, distribute and/or modify this document under the terms of the GNU Free %% Documentation License, Version 1.1 or any later version published by the %% Free Software Foundation; with the Invariant Sections being "Un preambolo", @@ -22,9 +22,9 @@ diversi, come quelli tradizionali che coinvolgono \textit{pipe} e Tralasceremo invece tutte le problematiche relative alla comunicazione attraverso la rete (e le relative interfacce) che saranno affrontate in dettaglio in un secondo tempo. Non affronteremo neanche meccanismi più -complessi ed evoluti come le RPC (\textit{Remote Procedure Calls}) e CORBA -(\textit{Common Object Request Brocker Architecture}) che in genere sono -implementati con un ulteriore livello sopra i meccanismi elementari. +complessi ed evoluti come le RPC (\textit{Remote Procedure Calls}) che in +genere sono implementati da un ulteriore livello di librerie sopra i +meccanismi elementari. \section{L'intercomunicazione fra processi tradizionale} @@ -42,155 +42,212 @@ ne gestiscono l'uso e le varie forme in cui si è 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 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 \funcd{pipe}, ed il suo prototipo è: -\begin{prototype}{unistd.h} -{int pipe(int filedes[2])} - -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 \errval{EMFILE}, - \errval{ENFILE} e \errval{EFAULT}.} -\end{prototype} +sostanza di una coppia di file descriptor connessi fra di loro in modo che +quanto scrive su di uno si può rileggere dall'altro. Si viene così a +costituire un canale di comunicazione realizzato tramite i due file +descriptor, che costituisce appunto una sorta di \textsl{tubo} (che appunto il +significato del termine inglese \textit{pipe}) attraverso cui si possono far +passare i dati. + +In pratica si tratta di un buffer circolare in memoria in cui il kernel +appoggia i dati immessi nel file descriptor su cui si scrive per farli poi +riemergere dal file descriptor da cui si legge. Si tenga ben presente che in +questo passaggio di dati non è previsto nessun tipo di accesso al disco e che +nonostante l'uso dei file descriptor le \textit{pipe} non han nulla a che fare +con i file di dati di cui si è parlato al cap.~\ref{cha:file_IO_interface}. + +La funzione di sistema che permette di creare questa speciale coppia di file +descriptor associati ad una \textit{pipe} è appunto \funcd{pipe}, ed il suo +prototipo è: + +\begin{funcproto}{ +\fhead{unistd.h} +\fdecl{int pipe(int filedes[2])} +\fdesc{Crea la coppia di file descriptor di una \textit{pipe}.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EFAULT}] \param{filedes} non è un indirizzo valido. + \end{errlist} + ed inoltre \errval{EMFILE} e \errval{ENFILE} nel loro significato generico.} +\end{funcproto} La funzione restituisce la coppia di file descriptor nel vettore -\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. I file descriptor infatti non sono -connessi a nessun file reale, ma, come accennato in -sez.~\ref{sec:file_sendfile_splice}, ad un buffer nel kernel, la cui -dimensione è specificata dal parametro di sistema \const{PIPE\_BUF}, (vedi -sez.~\ref{sec:sys_file_limits}). Lo schema di funzionamento di una pipe è -illustrato in fig.~\ref{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. +\param{filedes}, il primo è aperto in lettura ed il secondo in scrittura. Come +accennato concetto di funzionamento di una \textit{pipe} è semplice: quello +che si scrive nel file descriptor aperto in scrittura viene ripresentato tale +e quale nel file descriptor aperto in lettura. + +I file descriptor infatti non sono connessi a nessun file reale, ma, come +accennato, ad un buffer nel kernel la cui dimensione è specificata dal +parametro di sistema \const{PIPE\_BUF}, (vedi +sez.~\ref{sec:sys_file_limits}). Lo schema di funzionamento di una +\textit{pipe} è illustrato in fig.~\ref{fig:ipc_pipe_singular}, in cui sono +indicati i due capi della \textit{pipe}, associati a ciascun file descriptor, +con le frecce che indicano la direzione del flusso dei dati. \begin{figure}[!htb] \centering \includegraphics[height=5cm]{img/pipe} - \caption{Schema della struttura di una pipe.} + \caption{Schema della struttura di una \textit{pipe}.} \label{fig:ipc_pipe_singular} \end{figure} -Chiaramente creare una pipe all'interno di un singolo processo non serve a -niente; se però ricordiamo quanto esposto in sez.~\ref{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 +Della funzione di sistema esiste una seconda versione, \funcd{pipe2}, +introdotta con il kernel 2.6.27 e le \acr{glibc} 2.9 e specifica di Linux +(utilizzabile solo definendo la macro \macro{\_GNU\_SOURCE}), che consente di +impostare atomicamente le caratteristiche dei file descriptor restituiti, il +suo prototipo è: + +\begin{funcproto}{ +\fhead{unistd.h} +\fhead{fcntl.h} +\fdecl{int pipe2(int pipefd[2], int flags)} +\fdesc{Crea la coppia di file descriptor di una \textit{pipe}.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} + \item[\errcode{EINVAL}] il valore di \param{flags} non valido. + \end{errlist} + e gli altri già visti per \func{pipe} con lo stesso significato.} +\end{funcproto} + +Utilizzando un valore nullo per \param{flags} la funzione è identica a +\func{pipe}, si può però passare come valore l'OR aritmetico di uno qualunque +fra \const{O\_NONBLOCK} o \const{O\_CLOEXEC} che hanno l'effetto di impostare +su entrambi i file descriptor restituiti dalla funzione i relativi flag, già +descritti per \func{open} in tab.~\ref{tab:open_operation_flag}, che attivano +rispettivamente la modalità di accesso \textsl{non-bloccante} ed il +\textit{close-on-exec} \itindex{close-on-exec}. + +Chiaramente creare una \textit{pipe} all'interno di un singolo processo non +serve a niente; se però ricordiamo quanto esposto in +sez.~\ref{sec:file_shared_access} riguardo al comportamento dei file +descriptor nei processi figli, è immediato capire come una \textit{pipe} possa +diventare un meccanismo di intercomunicazione. Un processo figlio infatti +condivide gli stessi file descriptor del padre, compresi quelli associati ad +una \textit{pipe} (secondo la situazione illustrata in fig.~\ref{fig:ipc_pipe_fork}). In questo modo se uno dei processi scrive su un -capo della pipe, l'altro può leggere. +capo della \textit{pipe}, l'altro può leggere. \begin{figure}[!htb] \centering \includegraphics[height=5cm]{img/pipefork} - \caption{Schema dei collegamenti ad una pipe, condivisi fra processo padre e - figlio dopo l'esecuzione \func{fork}.} + \caption{Schema dei collegamenti ad una \textit{pipe}, condivisi fra + processo padre e figlio dopo l'esecuzione \func{fork}.} \label{fig:ipc_pipe_fork} \end{figure} Tutto ciò ci mostra come sia immediato realizzare un meccanismo di -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, 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 essere \textsl{parenti} (dall'inglese \textit{siblings}), cioè -o 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ò -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 \signal{SIGPIPE}, e la funzione di scrittura -restituirà un errore di \errcode{EPIPE} (al ritorno del gestore, o qualora il -segnale sia ignorato o bloccato). - -La dimensione del buffer della pipe (\const{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} +comunicazione fra processi attraverso una \textit{pipe}, utilizzando le +proprietà ordinarie dei file, ma ci mostra anche qual è il principale limite +nell'uso delle \textit{pipe}.\footnote{Stevens in \cite{APUE} riporta come + limite anche il fatto che la comunicazione è unidirezionale, ma in realtà + questo è un limite superabile usando una coppia di \textit{pipe}, anche se + al costo di una maggiore complessità di gestione.} È necessario infatti che +i processi possano condividere i file descriptor della \textit{pipe}, e per +questo essi devono comunque essere \textsl{parenti} (dall'inglese +\textit{siblings}), cioè o derivare da uno stesso processo padre in cui è +avvenuta la creazione della \textit{pipe}, o, più comunemente, essere nella +relazione padre/figlio. + +A differenza di quanto avviene con i file normali, la lettura da una +\textit{pipe} può essere bloccante (qualora non siano presenti dati), inoltre +se si legge da una \textit{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 \textit{pipe} il cui +capo in lettura non è aperto il processo riceverà il segnale \signal{SIGPIPE}, +e la funzione di scrittura restituirà un errore di \errcode{EPIPE} (al ritorno +del gestore, o qualora il segnale sia ignorato o bloccato). + +La dimensione del buffer della \textit{pipe} (\const{PIPE\_BUF}) ci dà inoltre +un'altra importante informazione riguardo il comportamento delle operazioni di +lettura e scrittura su di una \textit{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. + +La dimensione originale del buffer era di 4096 byte (uguale ad una pagina di +memoria) fino al kernel 2.6.11, ed è stata portata in seguito a 64kb; ma a +partire dal kernel 2.6.35 è stata resa disponibile l'operazione di controllo +\const{F\_SETPIPE\_SZ} (vedi sez.~\ref{sec:ipc_pipes}) che consente di +modificarne la dimensione. + + + +\subsection{Un esempio dell'uso delle \textit{pipe}} \label{sec:ipc_pipe_use} -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. 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 argomento in ingresso. +Per capire meglio il funzionamento delle \textit{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. Realizzeremo il programma di esempio nella forma di un +\textit{CGI}\footnote{quella dei CGI (\textit{Common Gateway Interface}) è una + interfaccia che consente ad un server web di eseguire un programma il cui + output (che deve essere opportunamente formattato seguendo le specifiche + dell'interfaccia) può essere presentato come risposta ad una richiesta HTTP + al posto del contenuto di un file, e che ha costituito probabilmente la + prima modalità con cui sono state create pagine HTML dinamiche.} che genera +una immagine JPEG di un codice a barre, specificato come argomento in +ingresso. Un programma che deve essere eseguito come \textit{CGI} deve rispondere a delle caratteristiche specifiche, esso infatti non viene lanciato da una shell, ma dallo stesso web server, alla richiesta di una specifica URL, che di solito ha la forma: -\begin{verbatim} - http://www.sito.it/cgi-bin/programma?argomento -\end{verbatim} +\begin{Verbatim} +http://www.sito.it/cgi-bin/programma?argomento +\end{Verbatim} ed il risultato dell'elaborazione deve essere presentato (con una intestazione -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 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 fig.~\ref{fig:ipc_pipe_use}, in cui la -direzione del flusso dei dati è data dalle frecce continue. +che ne descrive il \textit{mime-type}) sullo \textit{standard output}, in modo +che il server web possa reinviarlo al browser che ha effettuato la richiesta, +che in questo modo è in grado di visualizzarlo opportunamente. \begin{figure}[!htb] \centering \includegraphics[height=5cm]{img/pipeuse} - \caption{Schema dell'uso di una pipe come mezzo di comunicazione fra + \caption{Schema dell'uso di una \textit{pipe} come mezzo di comunicazione fra due processi attraverso l'esecuzione una \func{fork} e la chiusura dei capi non utilizzati.} \label{fig:ipc_pipe_use} \end{figure} +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 \textit{pipe} potremo inviare l'output del primo sull'input del +secondo, secondo lo schema mostrato in fig.~\ref{fig:ipc_pipe_use}, in cui la +direzione del flusso dei dati è data dalle frecce continue. + Si potrebbe obiettare che sarebbe molto più semplice salvare il risultato intermedio su un file temporaneo. Questo però non tiene conto del fatto che un -\textit{CGI} deve poter gestire più richieste in concorrenza, e si avrebbe una +\textit{CGI} può essere eseguito più volte in contemporanea, e si avrebbe una evidente \itindex{race~condition} \textit{race condition} in caso di accesso -simultaneo a detto 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 punto le cose non sarebbero più tanto - semplici.} L'uso di una pipe invece permette di risolvere il problema in -maniera semplice ed elegante, oltre ad essere molto più efficiente, dato che -non si deve scrivere su disco. +simultaneo a detto file da istanze diverse. Il problema potrebbe essere +superato utilizzando un sempre diverso per il file temporaneo, che verrebbe +creato all'avvio di ogni istanza, utilizzato dai sottoprocessi, e cancellato +alla fine della sua esecuzione; ma a questo punto le cose non sarebbero più +tanto semplici. L'uso di una \textit{pipe} invece permette 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 sez.~\ref{sec:file_dup}, in particolare di \func{dup2}. È attraverso queste funzioni infatti che è possibile dirottare gli stream standard dei processi -(che abbiamo visto in sez.~\ref{sec:file_std_descr} e -sez.~\ref{sec:file_std_stream}) sulla pipe. In +(che abbiamo visto in tab.~\ref{tab:file_std_files} e +sez.~\ref{sec:file_stream}) sulla \textit{pipe}. In fig.~\ref{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. -\begin{figure}[!htbp] +\begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{\codesamplewidth} \includecodesample{listati/BarCodePage.c} @@ -202,180 +259,200 @@ trova nella directory dei sorgenti. \end{figure} La prima operazione del programma (\texttt{\small 4--12}) è quella di creare -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 - fig.~\ref{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 -\cmd{barcode}. Quest'ultimo legge dallo standard input una stringa di -caratteri, la converte nell'immagine PostScript del codice a barre ad essa -corrispondente, e poi scrive il risultato direttamente sullo standard output. +le due \textit{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. La funzione \func{WriteMess} non è riportata in +fig.~\ref{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 \textit{pipe}, il programma può creare (\texttt{\small + 13-17}) il primo processo figlio, che si incaricherà (\texttt{\small + 19--25}) di eseguire \cmd{barcode}. Quest'ultimo legge dallo standard input +una stringa di caratteri, la converte nell'immagine PostScript del codice a +barre ad essa corrispondente, e poi scrive il risultato direttamente sullo +standard output. 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}. 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}). +chiude (\texttt{\small 20}) il capo aperto in scrittura della prima +\textit{pipe}, e se ne collega (\texttt{\small 21}) il capo in lettura allo +\textit{standard input} usando \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 \textit{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 -leggerà dalla prima pipe la stringa da codificare che gli sarà inviata dal -padre, e scriverà l'immagine PostScript del codice a barre sulla seconda. +leggerà dalla prima \textit{pipe} la stringa da codificare che gli sarà +inviata dal padre, e scriverà l'immagine PostScript del codice a barre sulla +seconda. Al contempo una volta lanciato il primo figlio, il processo padre prima chiude -(\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 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. +(\texttt{\small 26}) il capo inutilizzato della prima \textit{pipe} (quello in +ingresso) e poi scrive (\texttt{\small 27}) la stringa da convertire sul capo +in uscita, così che \cmd{barcode} possa riceverla dallo \textit{standard + input}. A questo punto l'uso della prima \textit{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 -questo punto si può eseguire la seconda conversione, da PS a JPEG, usando il -programma \cmd{gs}. Per questo si crea (\texttt{\small 30--34}) un secondo -processo figlio, che poi (\texttt{\small 35--42}) eseguirà questo programma -leggendo l'immagine PostScript creata da \cmd{barcode} dallo standard input, -per convertirla in JPEG. +PostScript del codice a barre sul capo in scrittura della seconda +\textit{pipe}; a questo punto si può eseguire la seconda conversione, da PS a +JPEG, usando il programma \cmd{gs}. Per questo si crea (\texttt{\small + 30--34}) un secondo processo figlio, che poi (\texttt{\small 35--42}) +eseguirà questo programma leggendo l'immagine PostScript creata da +\cmd{barcode} dallo \textit{standard input}, per convertirla in JPEG. Per fare tutto ciò anzitutto si chiude (\texttt{\small 37}) il capo in -scrittura della seconda pipe, e se ne collega (\texttt{\small 38}) il capo in -lettura allo standard input. Per poter formattare l'output del programma in -maniera utilizzabile da un browser, si provvede anche \texttt{\small 40}) alla -scrittura dell'apposita stringa di identificazione del mime-type in testa allo -standard output. A questo punto si può invocare \texttt{\small 41}) \cmd{gs}, -provvedendo gli appositi switch che consentono di leggere il file da -convertire dallo standard input e di inviare la conversione sullo standard -output. +scrittura della seconda \textit{pipe}, e se ne collega (\texttt{\small 38}) il +capo in lettura allo \textit{standard input}. Per poter formattare l'output +del programma in maniera utilizzabile da un browser, si provvede anche +\texttt{\small 40}) alla scrittura dell'apposita stringa di identificazione +del \textit{mime-type} in testa allo \textit{standard output}. A questo punto +si può invocare \texttt{\small 41}) \cmd{gs}, provvedendo le opportune opzioni +del comando che consentono di leggere il file da convertire dallo +\textit{standard input} e di inviare la conversione sullo \textit{standard + output}. 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}) 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. +capo in scrittura della seconda \textit{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 \textit{pipe} è necessaria, infatti, se non venisse chiusa, \cmd{gs}, +che legge il suo \textit{standard input} da detta \textit{pipe}, resterebbe +bloccato in attesa di ulteriori dati in ingresso (l'unico modo che un +programma ha per sapere che i dati in ingresso sono terminati è rilevare che +lo \textit{standard input} è stato chiuso), e la \func{wait} non ritornerebbe. \subsection{Le funzioni \func{popen} e \func{pclose}} \label{sec:ipc_popen} -Come si è visto la modalità più comune di utilizzo di una pipe è quella di -utilizzarla per fare da tramite fra output ed input di due programmi invocati -in sequenza; per questo motivo lo standard POSIX.2 ha introdotto due funzioni -che permettono di sintetizzare queste operazioni. La prima di esse si chiama -\funcd{popen} ed il suo prototipo è: -\begin{prototype}{stdio.h} -{FILE *popen(const char *command, const char *type)} - -Esegue il programma \param{command}, di cui, a seconda di \param{type}, -restituisce, lo standard input o lo standard output nella pipe collegata allo -stream restituito come valore di ritorno. - -\bodydesc{La funzione restituisce l'indirizzo dello stream associato alla pipe - in caso di successo e \val{NULL} per un errore, nel qual caso \var{errno} - potrà assumere i valori relativi alle sottostanti invocazioni di \func{pipe} - e \func{fork} o \errcode{EINVAL} se \param{type} non è valido.} -\end{prototype} +Come si è visto la modalità più comune di utilizzo di una \textit{pipe} è +quella di utilizzarla per fare da tramite fra output ed input di due programmi +invocati in sequenza; per questo motivo lo standard POSIX.2 ha introdotto due +funzioni che permettono di sintetizzare queste operazioni. La prima di esse si +chiama \funcd{popen} ed il suo prototipo è: -La funzione crea una pipe, esegue una \func{fork}, ed invoca il programma -\param{command} attraverso la shell (in sostanza esegue \file{/bin/sh} con il -flag \code{-c}); l'argomento \param{type} deve essere una delle due stringhe -\verb|"w"| o \verb|"r"|, per indicare se la pipe sarà collegata allo standard -input o allo standard output del comando invocato. - -La funzione restituisce il puntatore allo stream associato alla pipe creata, -che sarà aperto in sola lettura (e quindi associato allo standard output del -programma indicato) in caso si sia indicato \code{"r"}, o in sola scrittura (e -quindi associato allo standard input) in caso di \code{"w"}. - -Lo stream restituito da \func{popen} è identico a tutti gli effetti ai file -stream visti in cap.~\ref{cha:files_std_interface}, anche se è collegato ad -una pipe e non ad un file, e viene sempre aperto in modalità -\textit{fully-buffered} (vedi sez.~\ref{sec:file_buffering}); l'unica + +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{FILE *popen(const char *command, const char *type)} +\fdesc{Esegue un programma dirottando l'uscita su una \textit{pipe}.} +} + +{La funzione ritorna l'indirizzo dello stream associato alla \textit{pipe} in + caso di successo e \val{NULL} per un errore, nel qual caso \var{errno} potrà + assumere i valori relativi alle sottostanti invocazioni di \func{pipe} e + \func{fork} o \errcode{EINVAL} se \param{type} non è valido.} +\end{funcproto} + +La funzione crea una \textit{pipe}, esegue una \func{fork} creando un nuovo +processe nel quale invoca il programma \param{command} attraverso la shell (in +sostanza esegue \file{/bin/sh} con il flag \code{-c}). +L'argomento \param{type} deve essere una delle due stringhe \verb|"w"| o +\verb|"r"|, per richiedere che la \textit{pipe} restituita come valore di +ritorno sia collegata allo \textit{standard input} o allo \textit{standard + output} del comando invocato. + +La funzione restituisce il puntatore ad uno stream associato alla +\textit{pipe} creata, che sarà aperto in sola lettura (e quindi associato allo +\textit{standard output} del programma indicato) in caso si sia indicato +\code{r}, o in sola scrittura (e quindi associato allo \textit{standard + input}) in caso di \code{w}. A partire dalla versione 2.9 delle \acr{glibc} +(questa è una estensione specifica di Linux) all'argomento \param{type} può +essere aggiunta la lettera ``\texttt{e}'' per impostare automaticamente il +flag di \textit{close-on-exec} \itindex{close-on-exec} sul file descriptor +sottostante (si ricordi quanto spiegato in sez.~\ref{sec:file_open_close}). + +Lo \textit{stream} restituito da \func{popen} è identico a tutti gli effetti +ai \textit{file stream} visti in sez.~\ref{sec:files_std_interface}, anche se +è collegato ad una \textit{pipe} e non ad un file, e viene sempre aperto in +modalità \textit{fully-buffered} (vedi sez.~\ref{sec:file_buffering}); l'unica differenza con gli usuali stream è che dovrà essere chiuso dalla seconda delle due nuove funzioni, \funcd{pclose}, il cui prototipo è: -\begin{prototype}{stdio.h} -{int pclose(FILE *stream)} -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 - errore; nel quel caso il valore di \var{errno} deriva dalle sottostanti - chiamate.} -\end{prototype} -\noindent che oltre alla chiusura dello stream si incarica anche di attendere -(tramite \func{wait4}) la conclusione del processo creato dalla precedente -\func{popen}. +\begin{funcproto}{ +\fhead{stdio.h} +\fdecl{int pclose(FILE *stream)} +\fdesc{Chiude una \textit{pipe} creata con \func{popen}.} +} + +{La funzione ritorna lo stato del processo creato da \func{popen} in caso di + successo e $-1$ per un errore, nel qual caso \var{errno} assumerà i valori + derivanti dalle sottostanti funzioni \func{fclose} e \func{wait4}.} +\end{funcproto} + +La funzione chiude il file \param{stream} associato ad una \textit{pipe} +creato da una precedente \func{popen}, ed oltre alla chiusura dello stream si +incarica anche di attendere (tramite \func{wait4}) la conclusione del processo +creato dalla precedente \func{popen}. Se lo stato di uscita non può essere +letto la funzione restituirà per \var{errno} un errore di \errval{ECHILD}. Per illustrare l'uso di queste due funzioni riprendiamo il problema precedente: il programma mostrato in fig.~\ref{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 -il PostScript e tutte le volte viene generata una pagina intera, invece che -una immagine delle dimensioni corrispondenti al codice a barre. +quanto funzionante, è volutamente codificato in maniera piuttosto complessa, +inoltre doveva scontare un problema di \cmd{gs} che non era in grado di +riconoscere correttamente l'Encapsulated PostScript,\footnote{si fa + riferimento alla versione di GNU Ghostscript 6.53 (2002-02-13), usata quando + l'esempio venne scritto per la prima volta.} per cui si era utilizzato il +PostScript semplice, generando 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 +generato da \cmd{barcode} utilizzando l'opzione \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 di dimensioni corrette. -Questo approccio però non funziona, per via di una delle caratteristiche -principali delle pipe. Per poter effettuare la conversione di un PDF infatti è -necessario, per la struttura del formato, potersi spostare (con \func{lseek}) -all'interno del file da convertire; se si esegue la conversione con \cmd{gs} -su un file regolare non ci sono problemi, una pipe però è rigidamente -sequenziale, e l'uso di \func{lseek} su di essa fallisce sempre con un errore -di \errcode{ESPIPE}, rendendo impossibile la conversione. Questo ci dice che -in generale la concatenazione di vari programmi funzionerà soltanto quando -tutti prevedono una lettura sequenziale del loro input. +Questo approccio però non può funzionare per via di una delle caratteristiche +principali delle \textit{pipe}. Per poter effettuare la conversione di un PDF +infatti è necessario, per la struttura del formato, potersi spostare (con +\func{lseek}) all'interno del file da convertire. Se si esegue la conversione +con \cmd{gs} su un file regolare non ci sono problemi, una \textit{pipe} però +è rigidamente sequenziale, e l'uso di \func{lseek} su di essa fallisce sempre +con un errore di \errcode{ESPIPE}, rendendo impossibile la conversione. +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 un procedimento diverso, eseguendo prima la conversione (sempre con \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, è infatti molto facile da manipolare, dato che usa caratteri ASCII per - memorizzare le immagini, anche se per questo è estremamente inefficiente.} -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 (con \cmd{pnm2png}). + memorizzare le immagini, anche se per questo è estremamente inefficiente + come formato di archiviazione.} 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 (con +\cmd{pnm2png}). 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 -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 +inviando l'uscita di ciascuno all'ingresso del successivo, per poi ottenere il +risultato finale sullo \textit{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 la sua uscita sullo +\textit{standard input} del successivo, occorrerà usare \func{popen} aprendo +la \textit{pipe} in scrittura. Il codice del nuovo programma è riportato in fig.~\ref{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. +lettura su una \textit{pipe} è bloccante, per cui un processo, anche se +lanciato per primo, se non ottiene i dati che gli servono si bloccherà in +attesa sullo \textit{standard input} finché non otterrà il risultato +dell'elaborazione del processo che li deve creare, che pur essendo logicamente +precedente, viene lanciato dopo di lui. -\begin{figure}[!htbp] +\begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{\codesamplewidth} \includecodesample{listati/BarCode.c} @@ -385,28 +462,31 @@ dopo. \label{fig:ipc_barcode_code} \end{figure} -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. +Nel nostro caso il primo passo (\texttt{\small 14}) è scrivere il +\textit{mime-type} sullo \textit{standard output}; a questo punto il processo +padre non necessita più di eseguire ulteriori operazioni sullo +\textit{standard output} e può tranquillamente 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. +sequenza: prima crea una \textit{pipe} (\texttt{\small 17}) per la scrittura +eseguendo il programma con \func{popen}, in modo che essa sia collegata allo +\textit{standard input}, e poi redirige (\texttt{\small 18}) lo +\textit{standard output} su detta \textit{pipe}. 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. +catena) scriverà ancora sullo \textit{standard output} del processo padre, ma +i successivi, a causa di questa redirezione, scriveranno sulla \textit{pipe} +associata allo \textit{standard input} del processo invocato nel ciclo +precedente. 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}. +(\texttt{\small 23}) la stringa del codice a barre sulla \textit{pipe}, che è +collegata al suo \textit{standard input}, infine si può eseguire +(\texttt{\small 24--27}) un ciclo che chiuda con \func{pclose}, nell'ordine +inverso rispetto a quello in cui le si sono create, tutte le \textit{pipe} +create in precedenza. \subsection{Le \textit{pipe} con nome, o \textit{fifo}} @@ -414,87 +494,96 @@ create, tutte le pipe create con \func{pclose}. Come accennato in sez.~\ref{sec:ipc_pipes} il problema delle \textit{pipe} è che 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 che invece di essere strutture interne del -kernel, visibili solo attraverso un file descriptor, sono accessibili -attraverso un \itindex{inode} 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; -\itindex{inode} 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 sez.~\ref{sec:ipc_pipes}. - -Abbiamo già visto in sez.~\ref{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 \errcode{ENXIO} fintanto che non verrà aperto il capo in lettura. - -In Linux è possibile aprire le fifo anche in lettura/scrittura,\footnote{lo - standard POSIX lascia indefinito il comportamento in questo caso.} -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 situazioni di -stallo.\footnote{se si cerca di leggere da una fifo che non contiene dati si - avrà un \itindex{deadlock} deadlock immediato, dato che il processo si - blocca e non potrà quindi mai eseguire le funzioni di scrittura.} +o nella relazione padre/figlio. Per superare questo problema lo standard +POSIX.1 ha introdotto le \textit{fifo}, che hanno le stesse caratteristiche +delle \textit{pipe}, ma che invece di essere visibili solo attraverso un file +descriptor creato all'interno di un processo da una \textit{system call} +apposita, costituiscono un oggetto che risiede sul filesystem (si rammenti +quanto detto in sez.~\ref{sec:file_file_types}) che può essere aperto come un +qualunque file, 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 +\textit{pipe}, attraverso un buffer nel kernel, senza transitare dal +filesystem. Il fatto che siano associate ad un \itindex{inode} +\textit{inode} presente sul filesystem serve infatti solo a fornire un punto +di accesso per i processi, che permetta a questi ultimi di accedere alla +stessa \textit{fifo} senza avere nessuna relazione, con una semplice +\func{open}. Il comportamento delle funzioni di lettura e scrittura è identico +a quello illustrato per le \textit{pipe} in sez.~\ref{sec:ipc_pipes}. + +Abbiamo già trattato in sez.~\ref{sec:file_mknod} le funzioni \func{mknod} e +\func{mkfifo} che permettono di creare una \textit{fifo}. Per utilizzarne una +un processo non avrà che da aprire il relativo \index{file!speciali} file +speciale o in lettura o scrittura; nel primo caso il processo sarà collegato +al capo di uscita della \textit{fifo}, e dovrà leggere, nel secondo al capo di +ingresso, e dovrà scrivere. + +Il kernel alloca un singolo buffer per ciascuna \textit{fifo} che sia stata +aperta, e questa potrà 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 \textit{fifo} la funzione \func{open} di norma +si blocca se viene eseguita quando l'altro capo non è aperto. + +Le \textit{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 \errcode{ENXIO} fintanto che non verrà +aperto il capo in lettura. + +In Linux è possibile aprire le \textit{fifo} anche in lettura/scrittura (lo +standard POSIX lascia indefinito il comportamento in questo caso) operazione +che avrà sempre successo immediato qualunque sia la modalità di apertura, +bloccante e non bloccante. Questo può essere utilizzato per aprire comunque +una \textit{fifo} in scrittura anche se non ci sono ancora processi il +lettura. Infine è possibile anche usare la \textit{fifo} all'interno di un +solo processo, nel qual caso però occorre stare molto attenti alla possibili +situazioni di stallo: se si cerca di leggere da una \textit{fifo} che non +contiene dati si avrà infatti un \itindex{deadlock} \textit{deadlock} +immediato, dato che il processo si blocca e quindi non potrà 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 da 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 \const{PIPE\_BUF} (si ricordi quanto detto in -sez.~\ref{sec:ipc_pipes}). +piuttosto frequente l'utilizzo di una \textit{fifo} come canale di +comunicazione nelle situazioni un processo deve ricevere informazioni da +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 \const{PIPE\_BUF} (si +ricordi quanto detto in sez.~\ref{sec:ipc_pipes}). A parte il caso precedente, che resta probabilmente il più comune, Stevens riporta in \cite{APUE} altre due casistiche principali per l'uso delle fifo: -\begin{itemize} +\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 client ed server (il modello - \textit{client-server} è illustrato in sez.~\ref{sec:net_cliserv}). -\end{itemize} + sull'input di parecchi altri (attraverso l'uso del comando \cmd{tee}). +\item Come canale di comunicazione fra un \textit{client} ed un + \textit{server} (il modello \textit{client-server} è illustrato in + sez.~\ref{sec:net_cliserv}). +\end{itemize*} -Nel primo caso quello che si fa è creare tante fifo, da usare come standard -input, quanti sono i processi a cui i vogliono inviare i dati, questi ultimi -saranno stati posti in esecuzione ridirigendo lo standard input dalle fifo, si -potrà poi eseguire il processo che fornisce l'output replicando quest'ultimo, -con il comando \cmd{tee}, sulle varie fifo. +Nel primo caso quello che si fa è creare tante \textit{fifo} da usare come +\textit{standard input} quanti sono i processi a cui i vogliono inviare i +dati; questi ultimi saranno stati posti in esecuzione ridirigendo lo +\textit{standard input} dalle \textit{fifo}, si potrà poi eseguire il processo +che fornisce l'output replicando quest'ultimo, con il comando \cmd{tee}, sulle +varie \textit{fifo}. Il secondo caso è relativamente semplice qualora si debba comunicare con un -processo alla volta (nel qual caso basta usare due fifo, 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 -``\textsl{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. +processo alla volta, nel qual caso basta usare due \textit{fifo}, una per +leggere ed una per scrivere. Le cose diventano invece molto più complesse +quando si vuole effettuare una comunicazione fra un \textit{server} ed un +numero imprecisato di \textit{client}. Se il primo infatti può ricevere le +richieste attraverso una fifo ``\textsl{nota}'', per le risposte non si può +fare altrettanto, dato che, per la struttura sequenziale delle \textit{fifo}, +i \textit{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 in fig.~\ref{fig:ipc_fifo_server_arch} in cui i client inviano le -richieste al server su una fifo nota mentre le risposte vengono reinviate dal -server a ciascuno di essi su una fifo temporanea creata per l'occasione. +illustrata in fig.~\ref{fig:ipc_fifo_server_arch} in cui i \textit{client} +inviano le richieste al \textit{server} su una \textit{fifo} nota mentre le +risposte vengono reinviate dal \textit{server} a ciascuno di essi su una +\textit{fifo} temporanea creata per l'occasione. \begin{figure}[!htb] \centering @@ -510,7 +599,7 @@ un detto a caso estratto da un insieme di frasi; sia il numero delle frasi dell'insieme, che i file da cui esse vengono lette all'avvio, sono importabili da riga di comando. Il corpo principale del server è riportato in fig.~\ref{fig:ipc_fifo_server}, dove si è tralasciata la parte che tratta la -gestione delle opzioni a riga di comando, che effettua il settaggio delle +gestione delle opzioni a riga di comando, che effettua l'impostazione delle variabili \var{fortunefilename}, che indica il file da cui leggere le frasi, ed \var{n}, che indica il numero di frasi tenute in memoria, ad un valore diverso da quelli preimpostati. Il codice completo è nel file @@ -649,12 +738,12 @@ state raccolte nella libreria \file{libgapil.so}, per poter usare quest'ultima occorrerà definire la variabile di ambiente \envvar{LD\_LIBRARY\_PATH} in modo che il linker dinamico possa accedervi. -In generale questa variabile indica il \itindex{pathname} \textit{pathname} -della directory contenente la libreria. Nell'ipotesi (che daremo sempre per -verificata) che si facciano le prove direttamente nella directory dei sorgenti -(dove di norma vengono creati sia i programmi che la libreria), il comando da -dare sarà \code{export LD\_LIBRARY\_PATH=./}; a questo punto potremo lanciare -il server, facendogli leggere una decina di frasi, con: +In generale questa variabile indica il \textit{pathname} della directory +contenente la libreria. Nell'ipotesi (che daremo sempre per verificata) che si +facciano le prove direttamente nella directory dei sorgenti (dove di norma +vengono creati sia i programmi che la libreria), il comando da dare sarà +\code{export LD\_LIBRARY\_PATH=./}; a questo punto potremo lanciare il server, +facendogli leggere una decina di frasi, con: \begin{Verbatim} [piccardi@gont sources]$ ./fortuned -n10 \end{Verbatim} @@ -727,20 +816,20 @@ dei socket in cap.~\ref{cha:socket_intro},\footnote{si tratta comunque di oggetti di comunicazione che, come le pipe, sono utilizzati attraverso dei file descriptor.} nell'ambito dell'interfaccia generale che essi forniscono per la programmazione di rete; e vedremo anche -(in~sez.~\ref{sec:sock_sa_local}) come si possono definire dei file speciali -(di tipo socket, analoghi a quello associati alle fifo) cui si accede però -attraverso quella medesima interfaccia; vale però la pena esaminare qui una -modalità di uso dei socket locali\footnote{la funzione \func{socketpair} è - stata introdotta in BSD4.4, ma è supportata in genere da qualunque sistema - che fornisca l'interfaccia dei socket.} che li rende sostanzialmente -identici ad una pipe bidirezionale. +(in~sez.~\ref{sec:sock_sa_local}) come si possono definire dei +\index{file!speciali} file speciali (di tipo socket, analoghi a quello +associati alle fifo) cui si accede però attraverso quella medesima +interfaccia; vale però la pena esaminare qui una modalità di uso dei socket +locali\footnote{la funzione \func{socketpair} è stata introdotta in BSD4.4, ma + è supportata in genere da qualunque sistema che fornisca l'interfaccia dei + socket.} che li rende sostanzialmente identici ad una pipe bidirezionale. La funzione \funcd{socketpair} infatti consente di creare una coppia di file descriptor connessi fra di loro (tramite un socket, appunto), senza dover -ricorrere ad un file speciale sul filesystem, i descrittori sono del tutto -analoghi a quelli che si avrebbero con una chiamata a \func{pipe}, con la sola -differenza è che in questo caso il flusso dei dati può essere effettuato in -entrambe le direzioni. Il prototipo della funzione è: +ricorrere ad un \index{file!speciali} file speciale sul filesystem, i +descrittori sono del tutto analoghi a quelli che si avrebbero con una chiamata +a \func{pipe}, con la sola differenza è che in questo caso il flusso dei dati +può essere effettuato in entrambe le direzioni. Il prototipo della funzione è: \begin{functions} \headdecl{sys/types.h} \headdecl{sys/socket.h} @@ -882,13 +971,13 @@ nome di un file ed un numero di versione; il suo prototipo è: \end{functions} La funzione determina un valore della chiave sulla base di \param{pathname}, -che deve specificare il \itindex{pathname} \textit{pathname} di un file -effettivamente esistente e di un numero di progetto \param{proj\_id)}, che di -norma viene specificato come carattere, dato che ne vengono utilizzati solo -gli 8 bit meno significativi.\footnote{nelle libc4 e libc5, come avviene in - SunOS, l'argomento \param{proj\_id} è dichiarato tipo \ctyp{char}, la - \acr{glibc} usa il prototipo specificato da XPG4, ma vengono lo stesso - utilizzati gli 8 bit meno significativi.} +che deve specificare il \textit{pathname} di un file effettivamente esistente +e di un numero di progetto \param{proj\_id)}, che di norma viene specificato +come carattere, dato che ne vengono utilizzati solo gli 8 bit meno +significativi.\footnote{nelle libc4 e libc5, come avviene in SunOS, + l'argomento \param{proj\_id} è dichiarato tipo \ctyp{char}, la \acr{glibc} + usa il prototipo specificato da XPG4, ma vengono lo stesso utilizzati gli 8 + bit meno significativi.} Il problema è che anche così non c'è la sicurezza che il valore della chiave sia univoco, infatti esso è costruito combinando il byte di \param{proj\_id)} @@ -1222,7 +1311,7 @@ cui queste strutture vengono mantenute dal kernel.\footnote{lo schema \label{fig:ipc_msqid_ds} \end{figure} -A ciascuna coda è associata una struttura \struct{msgid\_ds}, la cui +A ciascuna coda è associata una struttura \struct{msqid\_ds}, la cui definizione, è riportata in fig.~\ref{fig:ipc_msqid_ds}. In questa struttura il kernel mantiene le principali informazioni riguardo lo stato corrente della coda.\footnote{come accennato questo vale fino ai kernel della serie 2.2.x, @@ -2064,6 +2153,10 @@ vengono effettuate con la funzione \funcd{semop}, il cui prototipo è: } \end{functions} + +%TODO manca semtimedop, trattare qui, referenziata in +%sez.~\ref{sec:sig_gen_beha}. + La funzione permette di eseguire operazioni multiple sui singoli semafori di un insieme. La funzione richiede come primo argomento l'identificatore \param{semid} dell'insieme su cui si vuole operare. Il numero di operazioni da @@ -2167,7 +2260,7 @@ Dato che, come già accennato in precedenza, in caso di uscita inaspettata i semafori possono restare occupati, abbiamo visto come \func{semop} permetta di attivare un meccanismo di ripristino attraverso l'uso del flag \const{SEM\_UNDO}. Il meccanismo è implementato tramite una apposita struttura -\struct{sem\_undo}, associata ad ogni processo per ciascun semaforo che esso +\kstruct{sem\_undo}, associata ad ogni processo per ciascun semaforo che esso ha modificato; all'uscita i semafori modificati vengono ripristinati, e le strutture disallocate. Per mantenere coerente il comportamento queste strutture non vengono ereditate attraverso una \func{fork} (altrimenti si @@ -2193,7 +2286,7 @@ Alla creazione di un nuovo insieme viene allocata una nuova strutture \struct{semid\_ds} ed il relativo vettore di strutture \struct{sem}. Quando si richiede una operazione viene anzitutto verificato che tutte le operazioni possono avere successo; se una di esse comporta il blocco del processo il -kernel crea una struttura \struct{sem\_queue} che viene aggiunta in fondo alla +kernel crea una struttura \kstruct{sem\_queue} che viene aggiunta in fondo alla coda di attesa associata a ciascun insieme di semafori\footnote{che viene referenziata tramite i campi \var{sem\_pending} e \var{sem\_pending\_last} di \struct{semid\_ds}.}. @@ -2208,23 +2301,25 @@ Se invece tutte le operazioni possono avere successo queste vengono eseguite immediatamente, dopo di che il kernel esegue una scansione della coda di attesa (a partire da \var{sem\_pending}) per verificare se qualcuna delle operazioni sospese in precedenza può essere eseguita, nel qual caso la -struttura \struct{sem\_queue} viene rimossa e lo stato del processo associato +struttura \kstruct{sem\_queue} viene rimossa e lo stato del processo associato all'operazione (\var{sleeper}) viene riportato a \textit{running}; il tutto viene ripetuto fin quando non ci sono più operazioni eseguibili o si è svuotata la coda. Per gestire il meccanismo del ripristino tutte le volte che per un'operazione si è specificato il flag \const{SEM\_UNDO} viene mantenuta -per ciascun insieme di semafori una apposita struttura \struct{sem\_undo} che +per ciascun insieme di semafori una apposita struttura \kstruct{sem\_undo} che contiene (nel vettore puntato dal campo \var{semadj}) un valore di aggiustamento per ogni semaforo cui viene sommato l'opposto del valore usato per l'operazione. +%TODO verificare queste strutture \kstruct{sem\_queue} e \kstruct{sem\_undo} + Queste strutture sono mantenute in due liste,\footnote{rispettivamente attraverso i due campi \var{id\_next} e \var{proc\_next}.} una associata all'insieme di cui fa parte il semaforo, che viene usata per invalidare le strutture se questo viene cancellato o per azzerarle se si è eseguita una operazione con \func{semctl}; l'altra associata al processo che ha eseguito l'operazione;\footnote{attraverso il campo \var{semundo} di - \struct{task\_struct}, come mostrato in \ref{fig:ipc_sem_schema}.} quando un + \kstruct{task\_struct}, come mostrato in \ref{fig:ipc_sem_schema}.} quando un processo termina, la lista ad esso associata viene scandita e le operazioni applicate al semaforo. Siccome un processo può accumulare delle richieste di ripristino per semafori differenti chiamate attraverso diverse chiamate a @@ -2360,6 +2455,8 @@ ripeteremo quanto detto al proposito in sez.~\ref{sec:ipc_sysv_mq}. L'argomento \param{size} specifica invece la dimensione, in byte, del segmento, che viene comunque arrotondata al multiplo superiore di \const{PAGE\_SIZE}. +% TODO aggiungere l'uso di SHM_HUGETLB introdotto con il kernel 2.6.0 + La memoria condivisa è la forma più veloce di comunicazione fra due processi, in quanto permette agli stessi di vedere nel loro spazio di indirizzi una stessa sezione di memoria. Pertanto non è necessaria nessuna operazione di @@ -2832,12 +2929,12 @@ condivisa (la funzione si bloccherà automaticamente se qualche client sta leggendo), poi (\texttt{\small 44}) si cancellano i valori precedentemente immagazzinati nella memoria condivisa con \func{memset}, e si esegue (\texttt{\small 45}) un nuovo calcolo degli stessi utilizzando la funzione -\func{DirScan}; infine (\texttt{\small 46}) si sblocca il mutex con +\myfunc{dir\_scan}; infine (\texttt{\small 46}) si sblocca il mutex con \func{MutexUnlock}, e si attende (\texttt{\small 47}) per il periodo di tempo specificato a riga di comando con l'opzione \code{-p} con una \func{sleep}. Si noti come per il calcolo dei valori da mantenere nella memoria condivisa si -sia usata ancora una volta la funzione \func{DirScan}, già utilizzata (e +sia usata ancora una volta la funzione \myfunc{dir\_scan}, già utilizzata (e descritta in dettaglio) in sez.~\ref{sec:file_dir_read}, che ci permette di effettuare la scansione delle voci della directory, chiamando per ciascuna di esse la funzione \func{ComputeValues}, che esegue tutti i calcoli necessari. @@ -2849,10 +2946,10 @@ ciascuna voce, per ottenerne i dati, che poi utilizza per incrementare i vari contatori nella memoria condivisa, cui accede grazie alla \index{variabili!globali} variabile globale \var{shmptr}. -Dato che la funzione è chiamata da \func{DirScan}, si è all'interno del ciclo -principale del programma, con un mutex acquisito, perciò non è necessario -effettuare nessun controllo e si può accedere direttamente alla memoria -condivisa usando \var{shmptr} per riempire i campi della struttura +Dato che la funzione è chiamata da \myfunc{dir\_scan}, si è all'interno del +ciclo principale del programma, con un mutex acquisito, perciò non è +necessario effettuare nessun controllo e si può accedere direttamente alla +memoria condivisa usando \var{shmptr} per riempire i campi della struttura \struct{DirProp}; così prima (\texttt{\small 6--7}) si sommano le dimensioni dei file ed il loro numero, poi, utilizzando le macro di tab.~\ref{tab:file_type_macro}, si contano (\texttt{\small 8--14}) quanti ce @@ -3050,7 +3147,7 @@ La prima possibilità, utilizzata fin dalle origini di Unix, è quella di usare dei \textsl{file di lock} (per i quali esiste anche una opportuna directory, \file{/var/lock}, nel filesystem standard). Per questo si usa la caratteristica della funzione \func{open} (illustrata in -sez.~\ref{sec:file_open}) che prevede\footnote{questo è quanto dettato dallo +sez.~\ref{sec:file_open_close}) che prevede\footnote{questo è quanto dettato dallo standard POSIX.1, ciò non toglie che in alcune implementazioni questa tecnica possa non funzionare; in particolare per Linux, nel caso di NFS, si è comunque soggetti alla possibilità di una \itindex{race~condition} @@ -3082,7 +3179,7 @@ cancella con \func{unlink}. \end{figure} Uno dei limiti di questa tecnica è che, come abbiamo già accennato in -sez.~\ref{sec:file_open}, questo comportamento di \func{open} può non +sez.~\ref{sec:file_open_close}, questo comportamento di \func{open} può non funzionare (la funzione viene eseguita, ma non è garantita l'atomicità dell'operazione) se il filesystem su cui si va ad operare è su NFS; in tal caso si può adottare una tecnica alternativa che prevede l'uso della @@ -3252,7 +3349,12 @@ più avanti, quando realizzeremo una nuova versione del monitor visto in sez.~\ref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete. \itindend{memory~mapping} -% TODO fare esempio di mmap anonima +% TODO: fare esempio di mmap anonima + +% TODO: con il kernel 3.2 è stata introdotta un nuovo meccanismo di +% intercomunicazione veloce chiamato Cross Memory Attach, da capire se e come +% trattarlo qui, vedi http://lwn.net/Articles/405346/ +% https://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=fcf634098c00dd9cd247447368495f0b79be12d1 \section{L'intercomunicazione fra processi di POSIX} \label{sec:ipc_posix} @@ -3284,8 +3386,8 @@ possono avere o meno una corrispondenza sul filesystem; tutto quello che è richiesto è che: \begin{itemize*} \item i nomi devono essere conformi alle regole che caratterizzano i - \itindex{pathname} \textit{pathname}, in particolare non essere più lunghi di - \const{PATH\_MAX} byte e terminati da un carattere nullo. + \textit{pathname}, in particolare non essere più lunghi di \const{PATH\_MAX} + byte e terminati da un carattere nullo. \item se il nome inizia per una \texttt{/} chiamate differenti allo stesso nome fanno riferimento allo stesso oggetto, altrimenti l'interpretazione del nome dipende dall'implementazione. @@ -3411,7 +3513,7 @@ diversi. La funzione è del tutto analoga ad \func{open} ed analoghi sono i valori che possono essere specificati per \param{oflag}, che deve essere specificato come maschera binaria; i valori possibili per i vari bit sono quelli visti in -tab.~\ref{tab:file_open_flags} dei quali però \func{mq\_open} riconosce solo i +sez.~\ref{sec:file_open_close} dei quali però \func{mq\_open} riconosce solo i seguenti: \begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} \item[\const{O\_RDONLY}] Apre la coda solo per la ricezione di messaggi. Il @@ -3658,7 +3760,7 @@ Se la dimensione specificata da \param{msg\_len} non è sufficiente a contenere il messaggio, entrambe le funzioni, al contrario di quanto avveniva nelle code di messaggi di SysV, ritornano un errore di \errcode{EMSGSIZE} senza estrarre il messaggio. È pertanto opportuno eseguire sempre una chiamata a -\func{mq\_getaddr} prima di eseguire una ricezione, in modo da ottenere la +\func{mq\_getattr} prima di eseguire una ricezione, in modo da ottenere la dimensione massima dei messaggi sulla coda, per poter essere in grado di allocare dei buffer sufficientemente ampi per la lettura. @@ -3729,7 +3831,7 @@ valori di tab.~\ref{tab:sigevent_sigev_notify}.\footnote{la pagina di manuale \const{SIGEV\_SIGNAL}).} Il metodo consigliato è quello di usare \const{SIGEV\_SIGNAL} usando il campo \var{sigev\_signo} per indicare il quale segnale deve essere inviato al processo. Inoltre il campo \var{sigev\_value} è -un puntatore ad una struttura \struct{sigval\_t} (definita in +un puntatore ad una struttura \struct{sigval} (definita in fig.~\ref{fig:sig_sigval}) che permette di restituire al gestore del segnale un valore numerico o un indirizzo,\footnote{per il suo uso si riveda la trattazione fatta in sez.~\ref{sec:sig_real_time} a proposito dei segnali @@ -3841,7 +3943,7 @@ La funzione è del tutto analoga ad \func{open} ed analoghi sono i valori che possono essere specificati per \param{oflag}, che deve essere specificato come maschera binaria comprendente almeno uno dei due valori \const{O\_RDONLY} e \const{O\_RDWR}; i valori possibili per i vari bit sono quelli visti in -tab.~\ref{tab:file_open_flags} dei quali però \func{shm\_open} riconosce solo +sez.~\ref{sec:file_open_close} dei quali però \func{shm\_open} riconosce solo i seguenti: \begin{basedescript}{\desclabelwidth{2.0cm}\desclabelstyle{\nextlinelabel}} \item[\const{O\_RDONLY}] Apre il file descriptor associato al segmento di @@ -3863,7 +3965,7 @@ In caso di successo la funzione restituisce un file descriptor associato al segmento di memoria condiviso con le stesse modalità di \func{open}\footnote{in realtà, come accennato, \func{shm\_open} è un semplice wrapper per \func{open}, usare direttamente quest'ultima avrebbe lo stesso - effetto.} viste in sez.~\ref{sec:file_open}; in particolare viene impostato + effetto.} viste in sez.~\ref{sec:file_open_close}; in particolare viene impostato il flag \const{FD\_CLOEXEC}. Chiamate effettuate da diversi processi usando lo stesso nome, restituiranno file descriptor associati allo stesso segmento (così come, nel caso di file di dati, essi sono associati allo stesso @@ -4018,18 +4120,18 @@ esistente o per crearne uno nuovi, i relativi prototipi sono: L'argomento \param{name} definisce il nome del semaforo che si vuole utilizzare, ed è quello che permette a processi diversi di accedere allo -stesso semaforo. Questo deve essere specificato con un pathname nella forma -\texttt{/qualchenome}, che non ha una corrispondenza diretta con un pathname -reale; con Linux infatti i file associati ai semafori sono mantenuti nel -filesystem virtuale \texttt{/dev/shm}, e gli viene assegnato automaticamente -un nome nella forma \texttt{sem.qualchenome}.\footnote{si ha cioè una - corrispondenza per cui \texttt{/qualchenome} viene rimappato, nella +stesso semaforo. Questo deve essere specificato con un \textit{pathname} nella +forma \texttt{/qualchenome}, che non ha una corrispondenza diretta con un +\textit{pathname} reale; con Linux infatti i file associati ai semafori sono +mantenuti nel filesystem virtuale \texttt{/dev/shm}, e gli viene assegnato +automaticamente un nome nella forma \texttt{sem.qualchenome}.\footnote{si ha + cioè una corrispondenza per cui \texttt{/qualchenome} viene rimappato, nella creazione tramite \func{sem\_open}, su \texttt{/dev/shm/sem.qualchenome}.} L'argomento \param{oflag} è quello che controlla le modalità con cui opera la funzione, ed è passato come maschera binaria; i bit corrispondono a quelli utilizzati per l'analogo argomento di \func{open}, anche se dei possibili -valori visti in sez.~\ref{sec:file_open} sono utilizzati soltanto +valori visti in sez.~\ref{sec:file_open_close} sono utilizzati soltanto \const{O\_CREAT} e \const{O\_EXCL}. Se si usa \const{O\_CREAT} si richiede la creazione del semaforo qualora @@ -4129,7 +4231,7 @@ programma possa proseguire. La seconda variante di \func{sem\_wait} è una estensione specifica che può essere utilizzata soltanto se viene definita la macro \macro{\_XOPEN\_SOURCE} ad un valore di 600 prima di includere \headfile{semaphore.h}, la funzione è -\func{sem\_timedwait}, ed il suo prototipo è: +\funcd{sem\_timedwait}, ed il suo prototipo è: \begin{functions} \headdecl{semaphore.h} @@ -4275,7 +4377,7 @@ prende un valore identico a quello usato per creare il semaforo stesso con il semaforo viene effettivamente cancellato dal sistema soltanto quando tutti i processi che lo avevano aperto lo chiudono. Si segue cioè la stessa semantica usata con \func{unlink} per i file, trattata in dettaglio in -sez.~\ref{sec:file_link}. +sez.~\ref{sec:link_symlink_rename}. Una delle caratteristiche peculiari dei semafori POSIX è che questi possono anche essere utilizzati anche in forma anonima, senza necessità di fare @@ -4607,7 +4709,7 @@ testo alla terminazione di quest'ultimo. % LocalWords: dtime lpid cpid nattac shmall shmmax SHMLBA SHMSEG EOVERFLOW brk % LocalWords: memory shmat shmdt void shmaddr shmflg SVID RND RDONLY rounded % LocalWords: SIGSEGV nattch exit SharedMem ShmCreate memset fill ShmFind home -% LocalWords: ShmRemove DirMonitor DirProp chdir GaPiL shmptr DirScan ipcs NFS +% LocalWords: ShmRemove DirMonitor DirProp chdir GaPiL shmptr ipcs NFS % LocalWords: ComputeValues ReadMonitor touch SIGTERM dirmonitor unlink fcntl % LocalWords: LockFile UnlockFile CreateMutex FindMutex LockMutex SETLKW GETLK % LocalWords: UnlockMutex RemoveMutex ReadMutex UNLCK WRLCK RDLCK mapping MAP