-\chapter{La comunicazione fra processi}
+%% ipc.tex
+%%
+%% Copyright (C) 2000-2015 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",
+%% with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the
+%% license is included in the section entitled "GNU Free Documentation
+%% License".
+%%
+
+\chapter{L'intercomunicazione fra processi}
\label{cha:IPC}
-Uno degli aspetti fondamentali della programmazione in un sistema unix-like è
+Uno degli aspetti fondamentali della programmazione in un sistema unix-like è
la comunicazione fra processi. In questo capitolo affronteremo solo i
-meccanismi più elementari che permettono di mettere in comunicazione processi
+meccanismi più elementari che permettono di mettere in comunicazione processi
diversi, come quelli tradizionali che coinvolgono \textit{pipe} e
\textit{fifo} e i meccanismi di intercomunicazione di System V e quelli POSIX.
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.
+dettaglio in un secondo tempo. Non affronteremo neanche meccanismi più
+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{La comunicazione fra processi tradizionale}
+\section{L'intercomunicazione fra processi tradizionale}
\label{sec:ipc_unix}
Il primo meccanismo di comunicazione fra processi introdotto nei sistemi Unix,
-è quello delle cosiddette \textit{pipe}; esse costituiscono una delle
+è quello delle cosiddette \textit{pipe}; esse costituiscono una delle
caratteristiche peculiari del sistema, in particolar modo dell'interfaccia a
linea di comando. In questa sezione descriveremo le sue basi, le funzioni che
-ne gestiscono l'uso e le varie forme in cui si è evoluto.
+ne gestiscono l'uso e le varie forme in cui si è evoluto.
\subsection{Le \textit{pipe} standard}
\label{sec:ipc_pipes}
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 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 \func{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 \macro{EMFILE},
- \macro{ENFILE} e \macro{EFAULT}.}
-\end{prototype}
+uno dei più usati, meccanismi di comunicazione fra processi. Si tratta in
+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 ad un buffer nel kernel, la cui dimensione è
-specificata dal parametro di sistema \macro{PIPE\_BUF}, (vedi
-\secref{sec:sys_file_limits}). Lo schema di funzionamento di una pipe è
-illustrato in \figref{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.
-
-\begin{figure}[htb]
+\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 \secref{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
-\figref{fig:ipc_pipe_fork}). In questo modo se uno dei processi scrive su un
-capo della pipe, l'altro può leggere.
+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}.}
+}
-\begin{figure}[htb]
+{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}.
+
+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 \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 \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}
+Tutto ciò ci mostra come sia immediato realizzare un meccanismo di
+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 parametro di input.
+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?parametro
-\end{verbatim}
+\begin{Example}
+http://www.sito.it/cgi-bin/programma?argomento
+\end{Example}
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.
+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.
-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 \figref{fig:ipc_pipe_use}, in cui la
-direzione del flusso dei dati è data dalle frecce continue.
-
-\begin{figure}[htb]
+\begin{figure}[!htb]
\centering
\includegraphics[height=5cm]{img/pipeuse}
- \caption{Schema dell'uso di una pipe come mezzo di comunicazione fra
- due processi attraverso attraverso l'esecuzione una \func{fork} e la
- chiusura dei capi non utilizzati.}
+ \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}
-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
-evidente 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 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.
-
-Il programma ci servirà anche come esempio dell'uso delle funzioni di
+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} può essere eseguito più volte in contemporanea, e si avrebbe una
+evidente \textit{race condition} in caso di accesso 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
-\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_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.
-
+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 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}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-int main(int argc, char *argv[], char *envp[])
-{
- ...
- /* create two pipes, pipein and pipeout, to handle communication */
- if ( (retval = pipe(pipein)) ) {
- WriteMess("input pipe creation error");
- exit(0);
- }
- if ( (retval = pipe(pipeout)) ) {
- WriteMess("output pipe creation error");
- exit(0);
- }
- /* First fork: use child to run barcode program */
- if ( (pid = fork()) == -1) { /* on error exit */
- WriteMess("child creation error");
- exit(0);
- }
- /* if child */
- if (pid == 0) {
- close(pipein[1]); /* close pipe write end */
- dup2(pipein[0], STDIN_FILENO); /* remap stdin to pipe read end */
- close(pipeout[0]);
- dup2(pipeout[1], STDOUT_FILENO); /* remap stdout in pipe output */
- execlp("barcode", "barcode", size, NULL);
- }
- close(pipein[0]); /* close input side of input pipe */
- write(pipein[1], argv[1], strlen(argv[1])); /* write parameter to pipe */
- close(pipein[1]); /* closing write end */
- waitpid(pid, NULL, 0); /* wait child completion */
- /* Second fork: use child to run ghostscript */
- if ( (pid = fork()) == -1) {
- WriteMess("child creation error");
- exit(0);
- }
- /* second child, convert PS to JPEG */
- if (pid == 0) {
- close(pipeout[1]); /* close write end */
- dup2(pipeout[0], STDIN_FILENO); /* remap read end to stdin */
- /* send mime type */
- write(STDOUT_FILENO, content, strlen(content));
- execlp("gs", "gs", "-q", "-sDEVICE=jpeg", "-sOutputFile=-", "-", NULL);
- }
- /* still parent */
- close(pipeout[1]);
- waitpid(pid, NULL, 0);
- exit(0);
-}
- \end{lstlisting}
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/BarCodePage.c}
\end{minipage}
\normalsize
\caption{Sezione principale del codice del \textit{CGI}
\label{fig:ipc_barcodepage_code}
\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
- \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
-\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.
+La prima operazione del programma (\texttt{\small 4-12}) è quella di creare
+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.
-
-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.
-
-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.
+(\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
+\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 \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
-\func{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 \macro{NULL} per un errore, nel qual caso \var{errno}
- potrà assumere i valori relativi alle sottostanti invocazioni di \func{pipe}
- e \func{fork} o \macro{EINVAL} se \param{type} non è valido.}
-\end{prototype}
-
-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 \secref{cha:files_std_interface}, anche se è collegato ad una
-pipe e non ad un inode, e viene sempre aperto in modalità
-\textit{fully-buffered} (vedi \secref{sec:file_buffering}); l'unica differenza
-con gli usuali stream è che dovrà essere chiuso dalla seconda delle due nuove
-funzioni, \func{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 \func{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}.
+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 è:
+
+
+\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
+processo 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} 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{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 \figref{fig:ipc_barcodepage_code} per
-quanto funzionante, è (volutamente) codificato in maniera piuttosto complessa,
-inoltre nella pratica sconta un problema di \cmd{gs} che non è in
-grado\footnote{nella versione GNU Ghostscript 6.53 (2002-02-13).} di
-riconoscere correttamente l'encapsulated postscript, per cui deve essere usato
-il postscript e tutte le volte viene generata una pagina intera, invece che
-una immagine delle dimensioni corrispondenti al codice a barre.
+precedente: il programma mostrato in fig.~\ref{fig:ipc_barcodepage_code} per
+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
+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 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 \macro{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
+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, è
+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}).
-
-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
-\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
+ 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'uscita di ciascuno all'ingresso del successivo, per poi ottenere il
+risultato finale sullo \textit{standard output}: un caso classico di
+utilizzazione delle \textit{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}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-int main(int argc, char *argv[], char *envp[])
-{
- FILE *pipe[4];
- FILE *pipein;
- char *cmd_string[4]={
- "pnmtopng",
- "pnmmargin -white 10",
- "pnmcrop",
- "gs -sDEVICE=ppmraw -sOutputFile=- -sNOPAUSE -q - -c showpage -c quit"
- };
- char content[]="Content-type: image/png\n\n";
- int i;
- /* write mime-type to stout */
- write(STDOUT_FILENO, content, strlen(content));
- /* execute chain of command */
- for (i=0; i<4; i++) {
- pipe[i] = popen(cmd_string[i], "w");
- dup2(fileno(pipe[i]), STDOUT_FILENO);
- }
- /* create barcode (in PS) */
- pipein = popen("barcode", "w");
- /* send barcode string to barcode program */
- write(fileno(pipein), argv[1], strlen(argv[1]));
- /* close all pipes (in reverse order) */
- for (i=4; i==0; i--) {
- pclose((pipe[i]));
- }
- exit(0);
-}
- \end{lstlisting}
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/BarCode.c}
\end{minipage}
\normalsize
\caption{Codice completo del \textit{CGI} \file{BarCode.c}.}
\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.
-
-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.
-
-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 è 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}.
+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 \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 \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 \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}}
\label{sec:ipc_named_pipe}
-Come accennato in \secref{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 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 è 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 deadlock immediato, dato che il processo si blocca e non potrà
- quindi mai eseguire le funzioni di scrittura.}
-
-Per la loro caratteristica di essere accessibili attraverso il filesystem, è
-piuttosto frequente l'utilizzo di una fifo come canale di comunicazione nelle
-situazioni un processo deve ricevere informazioni 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 \macro{PIPE\_BUF} (si ricordi quanto detto in
-\secref{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}
+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 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 \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 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 \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 \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
+\textit{fifo}:
+\begin{itemize*}
\item Da parte dei comandi di shell, per evitare la creazione di file
temporanei quando si devono inviare i dati di uscita di un processo
- sull'input di parecchi altri (attraverso l'uso del comando \cmd{tee}).
-
-\item Come canale di comunicazione fra client ed server (il modello
- \textit{client-server} è illustrato in \secref{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.
-
-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
-``nota'', per le risposte non si può fare altrettanto, dato che, per la
-struttura sequenziale delle fifo, i client dovrebbero sapere, prima di
-leggerli, quando i dati inviati sono destinati a loro.
-
-Per risolvere questo problema, si può usare un'architettura come quella
-illustrata in \figref{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.
-
-\begin{figure}[htb]
+ sull'input di parecchi altri (attraverso l'uso del comando \cmd{tee}).
+\item Come canale di comunicazione fra un client ed un
+ server (il modello \textit{client-server} è illustrato in
+ sez.~\ref{sec:net_cliserv}).
+\end{itemize*}
+
+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 \textit{fifo}, una per
+leggere ed una per scrivere. Le cose diventano invece molto più complesse
+quando si vuole effettuare una comunicazione fra un server ed un numero
+imprecisato di client. Se il primo infatti può ricevere le richieste
+attraverso una \textit{fifo} ``\textsl{nota}'', per le risposte non si può
+fare altrettanto, dato che, per la struttura sequenziale delle \textit{fifo},
+i client dovrebbero sapere prima di leggerli quando i dati inviati sono
+destinati a loro.
+
+Per risolvere questo problema, si può usare un'architettura come quella
+illustrata in fig.~\ref{fig:ipc_fifo_server_arch} in cui i client
+inviano le richieste al server su una \textit{fifo} nota mentre le
+risposte vengono reinviate dal server a ciascuno di essi su una
+\textit{fifo} temporanea creata per l'occasione.
+
+\begin{figure}[!htb]
\centering
\includegraphics[height=9cm]{img/fifoserver}
- \caption{Schema dell'utilizzo delle fifo nella realizzazione di una
- architettura di comunicazione client/server.}
+ \caption{Schema dell'utilizzo delle \textit{fifo} nella realizzazione di una
+ architettura di comunicazione client/server.}
\label{fig:ipc_fifo_server_arch}
\end{figure}
-Come esempio di uso questa architettura e dell'uso delle fifo, abbiamo scritto
-un server di \textit{fortunes}, che restituisce, alle richieste di un client,
-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
-\figref{fig:ipc_fifo_server}, dove si è tralasciata la parte che tratta la
-gestione delle opzioni a riga di comando, che effettua il settaggio 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
-\file{FortuneServer.c}.
-
-\begin{figure}[!htb]
+Come esempio di uso questa architettura e dell'uso delle \textit{fifo},
+abbiamo scritto un server di \textit{fortunes}, che restituisce, alle
+richieste di un client, 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 impostabili 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 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 \file{FortuneServer.c}.
+
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-char *fifoname = "/tmp/fortune.fifo";
-int main(int argc, char *argv[])
-{
-/* Variables definition */
- int i, n = 0;
- char *fortunefilename = "/usr/share/games/fortunes/italia";
- char **fortune;
- char line[80];
- int fifo_server, fifo_client;
- int nread;
- ...
- if (n==0) usage(); /* if no pool depth exit printing usage info */
- Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
- Signal(SIGINT, HandSIGTERM);
- Signal(SIGQUIT, HandSIGTERM);
- i = FortuneParse(fortunefilename, fortune, n); /* parse phrases */
- if (mkfifo(fifoname, 0622)) { /* create well known fifo if does't exist */
- if (errno!=EEXIST) {
- perror("Cannot create well known fifo");
- exit(1);
- }
- }
- /* open fifo two times to avoid EOF */
- fifo_server = open(fifoname, O_RDONLY);
- if (fifo_server < 0) {
- perror("Cannot open read only well known fifo");
- exit(1);
- }
- if (open(fifoname, O_WRONLY) < 0) {
- perror("Cannot open write only well known fifo");
- exit(1);
- }
- /* Main body: loop over requests */
- while (1) {
- nread = read(fifo_server, line, 79); /* read request */
- if (nread < 0) {
- perror("Read Error");
- exit(1);
- }
- line[nread] = 0; /* terminate fifo name string */
- n = random() % i; /* select random value */
- fifo_client = open(line, O_WRONLY); /* open client fifo */
- if (fifo_client < 0) {
- perror("Cannot open");
- exit(1);
- }
- nread = write(fifo_client, /* write phrase */
- fortune[n], strlen(fortune[n])+1);
- close(fifo_client); /* close client fifo */
- }
-}
- \end{lstlisting}
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/FortuneServer.c}
\end{minipage}
\normalsize
\caption{Sezione principale del codice del server di \textit{fortunes}
- basato sulle fifo.}
+ basato sulle \textit{fifo}.}
\label{fig:ipc_fifo_server}
\end{figure}
dell'insieme delle frasi non nulla, dato che l'inizializzazione del vettore
\var{fortune} avviene solo quando questa dimensione viene specificata, la
presenza di un valore nullo provoca l'uscita dal programma attraverso la
-routine (non riportata) che ne stampa le modalità d'uso. Dopo di che installa
-(\texttt{\small 13--15}) la funzione che gestisce i segnali di interruzione
-(anche questa non è riportata in \figref{fig:ipc_fifo_server}) che si limita a
-rimuovere dal filesystem la fifo usata dal server per comunicare.
+funzione (non riportata) che ne stampa le modalità d'uso. Dopo di che
+installa (\texttt{\small 13-15}) la funzione che gestisce i segnali di
+interruzione (anche questa non è riportata in fig.~\ref{fig:ipc_fifo_server})
+che si limita a rimuovere dal filesystem la \textit{fifo} usata dal server per
+comunicare.
Terminata l'inizializzazione (\texttt{\small 16}) si effettua la chiamata alla
funzione \code{FortuneParse} che legge dal file specificato in
\var{fortunefilename} le prime \var{n} frasi e le memorizza (allocando
dinamicamente la memoria necessaria) nel vettore di puntatori \var{fortune}.
-Anche il codice della funzione non è riportato, in quanto non direttamente
+Anche il codice della funzione non è riportato, in quanto non direttamente
attinente allo scopo dell'esempio.
-Il passo successivo (\texttt{\small 17--22}) è quello di creare con
-\func{mkfifo} la fifo nota sulla quale il server ascolterà le richieste,
-qualora si riscontri un errore il server uscirà (escludendo ovviamente il caso
-in cui la funzione \func{mkfifo} fallisce per la precedente esistenza della
-fifo).
-
-Una volta che si è certi che la fifo di ascolto esiste si procede
-(\texttt{\small 23--32}) alla sua apertura. Questo viene fatto due volte
-per evitare di dover gestire all'interno del ciclo principale il caso in cui
-il server è in ascolto ma non ci sono client che effettuano richieste.
-Si ricordi infatti che quando una fifo è aperta solo dal capo in lettura,
-l'esecuzione di \func{read} ritorna con zero byte (si ha cioè una condizione
-di end-of-file).
-
-Nel nostro caso la prima apertura si bloccherà fintanto che un qualunque
-client non apre a sua volta la fifo nota in scrittura per effettuare la sua
-richiesta. Pertanto all'inizio non ci sono problemi, il client però, una volta
-ricevuta la risposta, uscirà, chiudendo tutti i file aperti, compresa la fifo.
-A questo punto il server resta (se non ci sono altri client che stanno
-effettuando richieste) con la fifo chiusa sul lato in lettura e a questo punto
-\func{read} non si bloccherà in attesa di input, ma ritornerà in continuazione
-restituendo un end-of-file.\footnote{Si è usata questa tecnica per
- compatibilità, Linux infatti supporta l'apertura delle fifo in
- lettura/scrittura, per cui si sarebbe potuto effettuare una singola apertura
- con \macro{O\_RDWR}, la doppia apertura comunque ha il vantaggio che non si
- può scrivere per errore sul capo aperto in sola lettura.}
+Il passo successivo (\texttt{\small 17-22}) è quello di creare con
+\func{mkfifo} la \textit{fifo} nota sulla quale il server ascolterà le
+richieste, qualora si riscontri un errore il server uscirà (escludendo
+ovviamente il caso in cui la funzione \func{mkfifo} fallisce per la precedente
+esistenza della \textit{fifo}).
+
+Una volta che si è certi che la \textit{fifo} di ascolto esiste la procedura
+di inizializzazione è completata. A questo punto (\texttt{\small 23}) si può
+chiamare la funzione \func{daemon} per far proseguire l'esecuzione del
+programma in background come demone. Si può quindi procedere (\texttt{\small
+ 24-33}) alla apertura della \textit{fifo}: si noti che questo viene fatto
+due volte, prima in lettura e poi in scrittura, per evitare di dover gestire
+all'interno del ciclo principale il caso in cui il server è in ascolto ma non
+ci sono client che effettuano richieste. Si ricordi infatti che quando una
+\textit{fifo} è aperta solo dal capo in lettura, l'esecuzione di \func{read}
+ritorna con zero byte (si ha cioè una condizione di end-of-file).
+
+Nel nostro caso la prima apertura si bloccherà fintanto che un qualunque
+client non apre a sua volta la \textit{fifo} nota in scrittura per effettuare
+la sua richiesta. Pertanto all'inizio non ci sono problemi, il client però,
+una volta ricevuta la risposta, uscirà, chiudendo tutti i file aperti,
+compresa la \textit{fifo}. A questo punto il server resta (se non ci sono
+altri client che stanno effettuando richieste) con la \textit{fifo} chiusa sul
+lato in lettura, ed in questo stato la funzione \func{read} non si bloccherà
+in attesa di dati in ingresso, ma ritornerà in continuazione, restituendo una
+condizione di \textit{end-of-file}.
+
+Si è usata questa tecnica per compatibilità, Linux infatti supporta l'apertura
+delle \textit{fifo} in lettura/scrittura, per cui si sarebbe potuto effettuare
+una singola apertura con \const{O\_RDWR}; la doppia apertura comunque ha il
+vantaggio che non si può scrivere per errore sul capo aperto in sola lettura.
Per questo motivo, dopo aver eseguito l'apertura in lettura (\texttt{\small
- 24--28}),\footnote{di solito si effettua l'apertura del capo in lettura in
- modalità non bloccante, per evitare il rischio di uno stallo (se nessuno
- apre la fifo in scrittura il processo non ritornerà mai dalla \func{open})
- che nel nostro caso non esiste, mentre è necessario potersi bloccare in
- lettura in attesa di una richiesta.} si esegue una seconda apertura in
-scrittura (\texttt{\small 29--32}), scartando il relativo file descriptor che
-non sarà mai usato, ma lasciando la fifo comunque aperta anche in scrittura,
-cosicché le successive possano bloccarsi.
-
-A questo punto si può entrare nel ciclo principale del programma che fornisce
-le risposte ai client (\texttt{\small 34--50}), che viene eseguito
+ 24-28}),\footnote{di solito si effettua l'apertura del capo in lettura di
+ una \textit{fifo} in modalità non bloccante, per evitare il rischio di uno
+ stallo: se infatti nessuno apre la \textit{fifo} in scrittura il processo
+ non ritornerà mai dalla \func{open}. Nel nostro caso questo rischio non
+ esiste, mentre è necessario potersi bloccare in lettura in attesa di una
+ richiesta.} si esegue una seconda apertura in scrittura (\texttt{\small
+ 29-32}), scartando il relativo file descriptor, che non sarà mai usato, in
+questo modo però la \textit{fifo} resta comunque aperta anche in scrittura,
+cosicché le successive chiamate a \func{read} possono bloccarsi.
+
+A questo punto si può entrare nel ciclo principale del programma che fornisce
+le risposte ai client (\texttt{\small 34-50}); questo viene eseguito
indefinitamente (l'uscita del server viene effettuata inviando un segnale, in
-modo da passare attraverso la routine di chiusura che cancella la fifo).
-
-Il server è progettato per accettare come richieste dai client delle stringhe
-che contengono il nome della fifo sulla quale deve essere inviata la risposta.
-Per cui prima (\texttt{\small 35--39}) si esegue la lettura dalla stringa di
-richiesta dalla fifo nota (che a questo punto si bloccherà tutte le volte che
-non ci sono richieste). Dopo di che, una volta terminata la stringa
-(\texttt{\small 40}) e selezionato (\texttt{\small 41}) un numero casuale per
-ricavare la frase da inviare, si procederà (\texttt{\small 42--46})
-all'apertura della fifo per la risposta, che \texttt{\small 47--48}) poi vi
-sarà scritta. Infine (\texttt{\small 49}) si chiude la fifo di risposta che
-non serve più.
-
-Il codice del client è invece riportato in \figref{fig:ipc_fifo_client}, anche
-in questo caso si è omessa la gestione delle opzioni e la funzione che stampa
-a video le informazioni di utilizzo ed esce, riportando solo la sezione
+modo da passare attraverso la funzione di chiusura che cancella la
+\textit{fifo}).
+
+Il server è progettato per accettare come richieste dai client delle stringhe
+che contengono il nome della \textit{fifo} sulla quale deve essere inviata la
+risposta. Per cui prima (\texttt{\small 35-39}) si esegue la lettura dalla
+stringa di richiesta dalla \textit{fifo} nota (che a questo punto si bloccherà
+tutte le volte che non ci sono richieste). Dopo di che, una volta terminata la
+stringa (\texttt{\small 40}) e selezionato (\texttt{\small 41}) un numero
+casuale per ricavare la frase da inviare, si procederà (\texttt{\small
+ 42-46}) all'apertura della \textit{fifo} per la risposta, che poi
+(\texttt{\small 47-48}) vi sarà scritta. Infine (\texttt{\small 49}) si
+chiude la \textit{fifo} di risposta che non serve più.
+
+Il codice del client è invece riportato in fig.~\ref{fig:ipc_fifo_client},
+anche in questo caso si è omessa la gestione delle opzioni e la funzione che
+stampa a video le informazioni di utilizzo ed esce, riportando solo la sezione
principale del programma e le definizioni delle variabili. Il codice completo
-è nel file \file{FortuneClient.c} dei sorgenti allegati.
+è nel file \file{FortuneClient.c} dei sorgenti allegati.
-\begin{figure}[!htb]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-int main(int argc, char *argv[])
-{
-/* Variables definition */
- int n = 0;
- char *fortunefilename = "/tmp/fortune.fifo";
- char line[80];
- int fifo_server, fifo_client;
- char fifoname[80];
- int nread;
- char buffer[PIPE_BUF];
- ...
- snprintf(fifoname, 80, "/tmp/fortune.%d", getpid()); /* compose name */
- if (mkfifo(fifoname, 0622)) { /* open client fifo */
- if (errno!=EEXIST) {
- perror("Cannot create well known fifo");
- exit(-1);
- }
- }
- fifo_server = open(fortunefilename, O_WRONLY); /* open server fifo */
- if (fifo_server < 0) {
- perror("Cannot open well known fifo");
- exit(-1);
- }
- nread = write(fifo_server, fifoname, strlen(fifoname)+1); /* write name */
- close(fifo_server); /* close server fifo */
- fifo_client = open(fifoname, O_RDONLY); /* open client fifo */
- if (fifo_client < 0) {
- perror("Cannot open well known fifo");
- exit(-1);
- }
- nread = read(fifo_client, buffer, sizeof(buffer)); /* read answer */
- printf("%s", buffer); /* print fortune */
- close(fifo_client); /* close client */
- close(fifo_server); /* close server */
- unlink(fifoname); /* remove client fifo */
-}
- \end{lstlisting}
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/FortuneClient.c}
\end{minipage}
\normalsize
\caption{Sezione principale del codice del client di \textit{fortunes}
- basato sulle fifo.}
+ basato sulle \textit{fifo}.}
\label{fig:ipc_fifo_client}
\end{figure}
-La prima istruzione (\texttt{\small 12}) compone il nome della fifo che dovrà
-essere utilizzata per ricevere la risposta dal server. Si usa il \acr{pid}
-del processo per essere sicuri di avere un nome univoco; dopo di che
+La prima istruzione (\texttt{\small 12}) compone il nome della \textit{fifo}
+che dovrà essere utilizzata per ricevere la risposta dal server. Si usa il
+\ids{PID} del processo per essere sicuri di avere un nome univoco; dopo di che
(\texttt{\small 13-18}) si procede alla creazione del relativo file, uscendo
-in caso di errore (a meno che il file non sia già presente sul filesystem).
-
-A questo punto il client può effettuare l'interrogazione del server, per
-questo prima si apre la fifo nota (\texttt{\small 19--23}), e poi ci si scrive
-(\texttt{\small 24}) la stringa composta in precedenza, che contiene il nome
-della fifo da utilizzare per la risposta. Infine si richiude la fifo del
-server che a questo punto non serve più (\texttt{\small 25}).
-
-Inoltrata la richiesta si può passare alla lettura della risposta; anzitutto
-si apre (\texttt{\small 26--30}) la fifo appena creata, da cui si deve
-riceverla, dopo di che si effettua una lettura (\texttt{\small 31})
-nell'apposito buffer; si è supposto, come è ragionevole, che le frasi inviate
-dal server siano sempre di dimensioni inferiori a \macro{PIPE\_BUF},
-tralasciamo la gestione del caso in cui questo non è vero. Infine si stampa
+in caso di errore (a meno che il file non sia già presente sul filesystem).
+
+A questo punto il client può effettuare l'interrogazione del server, per
+questo prima si apre la \textit{fifo} nota (\texttt{\small 19-23}), e poi ci
+si scrive (\texttt{\small 24}) la stringa composta in precedenza, che contiene
+il nome della \textit{fifo} da utilizzare per la risposta. Infine si richiude
+la \textit{fifo} del server che a questo punto non serve più (\texttt{\small
+ 25}).
+
+Inoltrata la richiesta si può passare alla lettura della risposta; anzitutto
+si apre (\texttt{\small 26-30}) la \textit{fifo} appena creata, da cui si
+deve riceverla, dopo di che si effettua una lettura (\texttt{\small 31})
+nell'apposito buffer; si è supposto, come è ragionevole, che le frasi inviate
+dal server siano sempre di dimensioni inferiori a \const{PIPE\_BUF},
+tralasciamo la gestione del caso in cui questo non è vero. Infine si stampa
(\texttt{\small 32}) a video la risposta, si chiude (\texttt{\small 33}) la
-fifo e si cancella (\texttt{\small 34}) il relativo file.
-Si noti come la fifo per la risposta sia stata aperta solo dopo aver inviato
-la richiesta, se non si fosse fatto così si avrebbe avuto uno stallo, in
+\textit{fifo} e si cancella (\texttt{\small 34}) il relativo file. Si noti
+come la \textit{fifo} per la risposta sia stata aperta solo dopo aver inviato
+la richiesta, se non si fosse fatto così si avrebbe avuto uno stallo, in
quanto senza la richiesta, il server non avrebbe potuto aprirne il capo in
scrittura e l'apertura si sarebbe bloccata indefinitamente.
-Benché il nostro sistema client-server funzioni, la sua struttura è piuttosto
+Verifichiamo allora il comportamento dei nostri programmi, in questo, come in
+altri esempi precedenti, si fa uso delle varie funzioni di servizio, che sono
+state raccolte nella libreria \file{libgapil.so}, e per poterla usare
+occorrerà definire la variabile di ambiente \envvar{LD\_LIBRARY\_PATH} in modo
+che il linker dinamico possa accedervi.
+
+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{Console}
+[piccardi@gont sources]$ \textbf{./fortuned -n10}
+\end{Console}
+%$
+
+Avendo usato \func{daemon} per eseguire il server in background il comando
+ritornerà immediatamente, ma potremo verificare con \cmd{ps} che in effetti il
+programma resta un esecuzione in background, e senza avere associato un
+terminale di controllo (si ricordi quanto detto in sez.~\ref{sec:sess_daemon}):
+\begin{Console}
+[piccardi@gont sources]$ \textbf{ps aux}
+...
+piccardi 27489 0.0 0.0 1204 356 ? S 01:06 0:00 ./fortuned -n10
+piccardi 27492 3.0 0.1 2492 764 pts/2 R 01:08 0:00 ps aux
+\end{Console}
+%$
+e si potrà verificare anche che in \file{/tmp} è stata creata la \textit{fifo}
+di ascolto \file{fortune.fifo}. A questo punto potremo interrogare il server
+con il programma client; otterremo così:
+\begin{Console}
+[piccardi@gont sources]$ \textbf{./fortune}
+Linux ext2fs has been stable for a long time, now it's time to break it
+ -- Linuxkongreß '95 in Berlin
+[piccardi@gont sources]$ \textbf{./fortune}
+Let's call it an accidental feature.
+ --Larry Wall
+[piccardi@gont sources]$ \textbf{./fortune}
+......... Escape the 'Gates' of Hell
+ `:::' ....... ......
+ ::: * `::. ::'
+ ::: .:: .:.::. .:: .:: `::. :'
+ ::: :: :: :: :: :: :::.
+ ::: .::. .:: ::. `::::. .:' ::.
+...:::.....................::' .::::..
+ -- William E. Roadcap
+[piccardi@gont sources]$ ./fortune
+Linux ext2fs has been stable for a long time, now it's time to break it
+ -- Linuxkongreß '95 in Berlin
+\end{Console}
+%$
+e ripetendo varie volte il comando otterremo, in ordine casuale, le dieci
+frasi tenute in memoria dal server.
+
+Infine per chiudere il server basterà inviargli un segnale di terminazione (ad
+esempio con \cmd{killall fortuned}) e potremo verificare che il gestore del
+segnale ha anche correttamente cancellato la \textit{fifo} di ascolto da
+\file{/tmp}.
+
+Benché il nostro sistema client-server funzioni, la sua struttura è piuttosto
complessa e continua ad avere vari inconvenienti\footnote{lo stesso Stevens,
che esamina questa architettura in \cite{APUE}, nota come sia impossibile
- per il server sapere se un client è andato in crash, con la possibilità di
- far restare le fifo temporanee sul filesystem, di come sia necessario
- intercettare \macro{SIGPIPE} dato che un client può terminare dopo aver
- fatto una richiesta, ma prima che la risposta sia inviata (cosa che nel
- nostro esempio non è stata fatta).}; in generale infatti l'interfaccia delle
-fifo non è adatta a risolvere questo tipo di problemi, che possono essere
-affrontati in maniera più semplice ed efficace o usando i
-\textit{socket}\index{socket} (che tratteremo in dettaglio a partire da
-\capref{cha:socket_intro}) o ricorrendo a meccanismi di comunicazione diversi,
-come quelli che esamineremo in seguito.
+ per il server sapere se un client è andato in crash, con la possibilità di
+ far restare le \textit{fifo} temporanee sul filesystem, di come sia
+ necessario intercettare \signal{SIGPIPE} dato che un client può terminare
+ dopo aver fatto una richiesta, ma prima che la risposta sia inviata (cosa
+ che nel nostro esempio non è stata fatta).}; in generale infatti
+l'interfaccia delle \textit{fifo} non è adatta a risolvere questo tipo di
+problemi, che possono essere affrontati in maniera più semplice ed efficace o
+usando i socket (che tratteremo in dettaglio a partire da
+cap.~\ref{cha:socket_intro}) o ricorrendo a meccanismi di comunicazione
+diversi, come quelli che esamineremo in seguito.
\subsection{La funzione \func{socketpair}}
\label{sec:ipc_socketpair}
-Un meccanismo di comunicazione molto simile alle pipe, ma che non presenta il
-problema della unidirezionalità del flusso dei dati, è quello dei cosiddetti
-\textsl{socket locali} (o \textit{Unix domain socket}). Tratteremo l'argomento
-dei \textit{socket} in \capref{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~\secref{sec:sock_sa_local}) come si possono definire dei file speciali (di
-tipo \textit{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 \func{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 è:
-\begin{functions}
- \headdecl{sys/types.h}
- \headdecl{sys/socket.h}
-
- \funcdecl{int socketpair(int domain, int type, int protocol, int sv[2])}
-
- Crea una coppia di socket connessi fra loro.
-
- \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
- errore, nel qual caso \var{errno} assumerà uno dei valori:
+Un meccanismo di comunicazione molto simile alle \textit{pipe}, ma che non
+presenta il problema della unidirezionalità del flusso dei dati, è quello dei
+cosiddetti \textsl{socket locali} (o \textit{Unix domain socket}). Tratteremo
+in generale i socket in cap.~\ref{cha:socket_intro}, nell'ambito
+dell'interfaccia che essi forniscono per la programmazione di rete, e vedremo
+anche (in~sez.~\ref{sec:sock_sa_local}) come si possono utilizzare i file
+speciali di tipo socket, analoghi a quelli associati alle \textit{fifo} (si
+rammenti sez.~\ref{sec:file_file_types}) cui si accede però attraverso quella
+medesima interfaccia; vale però la pena esaminare qui una modalità di uso dei
+socket locali che li rende sostanzialmente identici ad una \textit{pipe}
+bidirezionale.
+
+La funzione di sistema \funcd{socketpair}, introdotta da BSD ma supportata in
+genere da qualunque sistema che fornisca l'interfaccia dei socket ed inclusa
+in POSIX.1-2001, consente infatti di creare una coppia di file descriptor
+connessi fra 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 è:
+
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/socket.h}
+\fdecl{int socketpair(int domain, int type, int protocol, int sv[2])}
+\fdesc{Crea una coppia di socket connessi fra loro.}
+}
+
+{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[\macro{EAFNOSUPPORT}] I socket locali non sono supportati.
- \item[\macro{EPROTONOSUPPORT}] Il protocollo specificato non è supportato.
- \item[\macro{EOPNOTSUPP}] Il protocollo specificato non supporta la
+ \item[\errcode{EAFNOSUPPORT}] i socket locali non sono supportati.
+ \item[\errcode{EOPNOTSUPP}] il protocollo specificato non supporta la
creazione di coppie di socket.
+ \item[\errcode{EPROTONOSUPPORT}] il protocollo specificato non è supportato.
\end{errlist}
- ed inoltre \macro{EMFILE}, \macro{EFAULT}.
-}
-\end{functions}
+ ed inoltre \errval{EFAULT}, \errval{EMFILE} e \errval{ENFILE} nel loro
+ significato generico.}
+\end{funcproto}
La funzione restituisce in \param{sv} la coppia di descrittori connessi fra di
-loro: quello che si scrive su uno di essi sarà ripresentato in input
-sull'altro e viceversa. I parametri \param{domain}, \param{type} e
-\param{protocol} derivano dall'interfaccia dei socket (che è quella che
-fornisce il substrato per connettere i due descrittori), ma in questo caso i
-soli valori validi che possono essere specificati sono rispettivamente
-\macro{AF\_UNIX}, \macro{SOCK\_STREAM} e \macro{0}.
-
-L'utilità di chiamare questa funzione per evitare due chiamate a \func{pipe}
-può sembrare limitata; in realtà l'utilizzo di questa funzione (e dei socket
+loro: quello che si scrive su uno di essi sarà ripresentato in input
+sull'altro e viceversa. Gli argomenti \param{domain}, \param{type} e
+\param{protocol} derivano dall'interfaccia dei socket (vedi
+sez.~\ref{sec:sock_creation}) che è quella che fornisce il substrato per
+connettere i due descrittori, ma in questo caso i soli valori validi che
+possono essere specificati sono rispettivamente \const{AF\_UNIX},
+\const{SOCK\_STREAM} e \val{0}.
+
+A partire dal kernel 2.6.27 la funzione supporta nell'indicazione del tipo di
+socket anche i due flag \const{SOCK\_NONBLOCK} e \const{SOCK\_CLOEXEC}
+(trattati in sez.~\ref{sec:sock_type}), con effetto identico agli analoghi
+\const{O\_CLOEXEC} e \const{O\_NONBLOCK} di una \func{open} (vedi
+tab.~\ref{tab:open_operation_flag}).
+
+L'utilità di chiamare questa funzione per evitare due chiamate a \func{pipe}
+può sembrare limitata; in realtà l'utilizzo di questa funzione (e dei socket
locali in generale) permette di trasmettere attraverso le linea non solo dei
-dati, ma anche dei file descriptor: si può cioè passare da un processo ad un
+dati, ma anche dei file descriptor: si può cioè passare da un processo ad un
altro un file descriptor, con una sorta di duplicazione dello stesso non
all'interno di uno stesso processo, ma fra processi distinti (torneremo su
-questa funzionalità in \secref{sec:xxx_fd_passing}).
+questa funzionalità in sez.~\ref{sec:sock_fd_passing}).
-\section{La comunicazione fra processi di System V}
+\section{L'intercomunicazione fra processi di System V}
\label{sec:ipc_sysv}
-Benché le pipe e le fifo siano ancora ampiamente usate, esse scontano il
-limite fondamentale che il meccanismo di comunicazione che forniscono è
-rigidamente sequenziale: una situazione in cui un processo scrive qualcosa che
-molti altri devono poter leggere non può essere implementata con una pipe.
+Benché le \textit{pipe} e le \textit{fifo} siano ancora ampiamente usate, esse
+scontano il limite fondamentale che il meccanismo di comunicazione che
+forniscono è rigidamente sequenziale: una situazione in cui un processo scrive
+qualcosa che molti altri devono poter leggere non può essere implementata con
+una \textit{pipe}.
Per questo nello sviluppo di System V vennero introdotti una serie di nuovi
oggetti per la comunicazione fra processi ed una nuova interfaccia di
-programmazione, che fossero in grado di garantire una maggiore flessibilità.
-In questa sezione esamineremo come Linux supporta quello che viene chiamato il
-\textsl{Sistema di comunicazione inter-processo} di System V, cui da qui in
-avanti faremo riferimento come \textit{SysV IPC} (dove IPC è la sigla di
-\textit{Inter-Process Comunication}).
+programmazione, poi inclusa anche in POSIX.1-2001, che fossero in grado di
+garantire una maggiore flessibilità. In questa sezione esamineremo come Linux
+supporta quello che viene chiamato il \textsl{Sistema di comunicazione fra
+ processi} di System V, cui da qui in avanti faremo riferimento come
+\textit{SysV-IPC} (dove IPC è la sigla di \textit{Inter-Process
+ Comunication}).
\subsection{Considerazioni generali}
\label{sec:ipc_sysv_generic}
-La principale caratteristica del \textit{SysV IPC} è quella di essere basato
+La principale caratteristica del \textit{SysV-IPC} è quella di essere basato
su oggetti permanenti che risiedono nel kernel. Questi, a differenza di quanto
avviene per i file descriptor, non mantengono un contatore dei riferimenti, e
-non vengono cancellati dal sistema una volta che non sono più in uso.
-
-Questo comporta due problemi: il primo è che, al contrario di quanto avviene
-per pipe e fifo, la memoria allocata per questi oggetti non viene rilasciata
-automaticamente quando non c'è più nessuno che li utilizzi, ed essi devono
-essere cancellati esplicitamente, se non si vuole che restino attivi fino al
-riavvio del sistema. Il secondo problema è che, dato che non c'è, come per i
-file, un contatore del numero di riferimenti che ne indichi l'essere in uso,
-essi possono essere cancellati anche se ci sono dei processi che li stanno
-utilizzando, con tutte le conseguenze (negative) del caso.
-
-Un'ulteriore caratteristica negativa è che gli oggetti usati nel \textit{SysV
- IPC} vengono creati direttamente dal kernel, e sono accessibili solo
-specificando il relativo \textsl{identificatore}. Questo è un numero
-progressivo (un po' come il \acr{pid} dei processi) che il kernel assegna a
+non vengono cancellati dal sistema una volta che non sono più in uso. Questo
+comporta due problemi: il primo è che, al contrario di quanto avviene per
+\textit{pipe} e \textit{fifo}, la memoria allocata per questi oggetti non
+viene rilasciata automaticamente quando non c'è più nessuno che li utilizzi ed
+essi devono essere cancellati esplicitamente, se non si vuole che restino
+attivi fino al riavvio del sistema. Il secondo problema è, dato che non c'è
+come per i file un contatore del numero di riferimenti che ne indichi l'essere
+in uso, che essi possono essere cancellati anche se ci sono dei processi che
+li stanno utilizzando, con tutte le conseguenze (ovviamente assai sgradevoli)
+del caso.
+
+Un'ulteriore caratteristica negativa è che gli oggetti usati nel
+\textit{SysV-IPC} vengono creati direttamente dal kernel, e sono accessibili
+solo specificando il relativo \textsl{identificatore}. Questo è un numero
+progressivo (un po' come il \ids{PID} dei processi) che il kernel assegna a
ciascuno di essi quanto vengono creati (sul procedimento di assegnazione
-torneremo in \secref{sec:ipc_sysv_id_use}). L'identificatore viene restituito
-dalle funzioni che creano l'oggetto, ed è quindi locale al processo che le ha
-eseguite. Dato che l'identificatore viene assegnato dinamicamente dal kernel
-non è possibile prevedere quale sarà, né utilizzare un qualche valore statico,
-si pone perciò il problema di come processi diversi possono accedere allo
-stesso oggetto.
-
-Per risolvere il problema nella struttura \var{ipc\_perm} che il kernel
+torneremo in sez.~\ref{sec:ipc_sysv_id_use}). L'identificatore viene
+restituito dalle funzioni che creano l'oggetto, ed è quindi locale al processo
+che le ha eseguite. Dato che l'identificatore viene assegnato dinamicamente
+dal kernel non è possibile prevedere quale sarà, né utilizzare un qualche
+valore statico, si pone perciò il problema di come processi diversi possono
+accedere allo stesso oggetto.
+
+Per risolvere il problema nella struttura \struct{ipc\_perm} che il kernel
associa a ciascun oggetto, viene mantenuto anche un campo apposito che
contiene anche una \textsl{chiave}, identificata da una variabile del tipo
primitivo \type{key\_t}, da specificare in fase di creazione dell'oggetto, e
-tramite la quale è possibile ricavare l'identificatore.\footnote{in sostanza
+tramite la quale è possibile ricavare l'identificatore.\footnote{in sostanza
si sposta il problema dell'accesso dalla classificazione in base
all'identificatore alla classificazione in base alla chiave, una delle tante
- complicazioni inutili presenti nel \textit{SysV IPC}.} Oltre la chiave, la
-struttura, la cui definizione è riportata in \figref{fig:ipc_ipc_perm},
-mantiene varie proprietà ed informazioni associate all'oggetto.
+ complicazioni inutili presenti nel \textit{SysV-IPC}.} Oltre la chiave, la
+struttura, la cui definizione è riportata in fig.~\ref{fig:ipc_ipc_perm},
+mantiene varie proprietà ed informazioni associate all'oggetto.
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm ]{}
-struct ipc_perm
-{
- key_t key; /* Key. */
- uid_t uid; /* Owner's user ID. */
- gid_t gid; /* Owner's group ID. */
- uid_t cuid; /* Creator's user ID. */
- gid_t cgid; /* Creator's group ID. */
- unsigned short int mode; /* Read/write permission. */
- unsigned short int seq; /* Sequence number. */
-};
- \end{lstlisting}
+ \begin{minipage}[c]{0.80\textwidth}
+ \includestruct{listati/ipc_perm.h}
\end{minipage}
\normalsize
- \caption{La struttura \var{ipc\_perm}, come definita in \file{sys/ipc.h}.}
+ \caption{La struttura \structd{ipc\_perm}, come definita in
+ \headfiled{sys/ipc.h}.}
\label{fig:ipc_ipc_perm}
\end{figure}
Usando la stessa chiave due processi diversi possono ricavare l'identificatore
-associato ad un oggetto ed accedervi. Il problema che sorge a questo punto è
+associato ad un oggetto ed accedervi. Il problema che sorge a questo punto è
come devono fare per accordarsi sull'uso di una stessa chiave. Se i processi
-sono \textsl{parenti} la soluzione è relativamente semplice, in tal caso
-infatti si può usare il valore speciale \texttt{IPC\_PRIVATE} per creare un
-nuovo oggetto nel processo padre, l'identificatore così ottenuto sarà
-disponibile in tutti i figli, e potrà essere passato come parametro attraverso
+sono \textsl{imparentati} la soluzione è relativamente semplice, in tal caso
+infatti si può usare il valore speciale \texttt{IPC\_PRIVATE} per creare un
+nuovo oggetto nel processo padre, l'identificatore così ottenuto sarà
+disponibile in tutti i figli, e potrà essere passato come argomento attraverso
una \func{exec}.
-Però quando i processi non sono \textsl{parenti} (come capita tutte le volte
-che si ha a che fare con un sistema client-server) tutto questo non è
+Però quando i processi non sono \textsl{imparentati} (come capita tutte le
+volte che si ha a che fare con un sistema client-server) tutto questo non è
possibile; si potrebbe comunque salvare l'identificatore su un file noto, ma
questo ovviamente comporta lo svantaggio di doverselo andare a rileggere. Una
-alternativa più efficace è quella che i programmi usino un valore comune per
-la chiave (che ad esempio può essere dichiarato in un header comune), ma c'è
-sempre il rischio che questa chiave possa essere stata già utilizzata da
+alternativa più efficace è quella che i programmi usino un valore comune per
+la chiave (che ad esempio può essere dichiarato in un header comune), ma c'è
+sempre il rischio che questa chiave possa essere stata già utilizzata da
qualcun altro. Dato che non esiste una convenzione su come assegnare queste
-chiavi in maniera univoca l'interfaccia mette a disposizione una funzione,
-\func{ftok}, che permette di ottenere una chiave specificando il nome di un
-file ed un numero di versione; il suo prototipo è:
-\begin{functions}
- \headdecl{sys/types.h}
- \headdecl{sys/ipc.h}
-
- \funcdecl{key\_t ftok(const char *pathname, int proj\_id)}
-
- Restituisce una chiave per identificare un oggetto del \textit{SysV IPC}.
-
- \bodydesc{La funzione restituisce la chiave in caso di successo e -1
- altrimenti, nel qual caso \var{errno} sarà uno dei possibili codici di
- errore di \func{stat}.}
-\end{functions}
+chiavi in maniera univoca l'interfaccia mette a disposizione una funzione
+apposita, \funcd{ftok}, che permette di ottenere una chiave specificando il
+nome di un file ed un numero di versione; il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/ipc.h}
+\fdecl{key\_t ftok(const char *pathname, int proj\_id)}
+\fdesc{Restituisce una chiave per identificare un oggetto del \textit{SysV
+ IPC}.}}
+
+{La funzione ritorna la chiave in caso di successo e $-1$ per un errore, nel
+ qual caso \var{errno} assumerà uno dei possibili codici di errore di
+ \func{stat}.}
+\end{funcproto}
La funzione determina un valore della chiave sulla base di \param{pathname},
-che deve specificare il 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}, le \acr{glibc}
- usano 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)}
+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. Nelle \acr{libc4} e \acr{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)}
con i 16 bit meno significativi dell'inode del file \param{pathname} (che
vengono ottenuti attraverso \func{stat}, da cui derivano i possibili errori),
-e gli 8 bit meno significativi del numero del dispositivo su cui è il file.
-Diventa perciò relativamente facile ottenere delle collisioni, specie se i
+e gli 8 bit meno significativi del numero del dispositivo su cui è il file.
+Diventa perciò relativamente facile ottenere delle collisioni, specie se i
file sono su dispositivi con lo stesso \textit{minor number}, come
\file{/dev/hda1} e \file{/dev/sda1}.
-In genere quello che si fa è utilizzare un file comune usato dai programmi che
+In genere quello che si fa è utilizzare un file comune usato dai programmi che
devono comunicare (ad esempio un header comune, o uno dei programmi che devono
usare l'oggetto in questione), utilizzando il numero di progetto per ottenere
le chiavi che interessano. In ogni caso occorre sempre controllare, prima di
-creare un oggetto, che la chiave non sia già stata utilizzata. Se questo va
+creare un oggetto, che la chiave non sia già stata utilizzata. Se questo va
bene in fase di creazione, le cose possono complicarsi per i programmi che
devono solo accedere, in quanto, a parte gli eventuali controlli sugli altri
-attributi di \var{ipc\_perm}, non esiste una modalità semplice per essere
+attributi di \struct{ipc\_perm}, non esiste una modalità semplice per essere
sicuri che l'oggetto associato ad una certa chiave sia stato effettivamente
creato da chi ci si aspetta.
-Questo è, insieme al fatto che gli oggetti sono permanenti e non mantengono un
+Questo è, insieme al fatto che gli oggetti sono permanenti e non mantengono un
contatore di riferimenti per la cancellazione automatica, il principale
-problema del \textit{SysV IPC}. Non esiste infatti una modalità chiara per
+problema del \textit{SysV-IPC}. Non esiste infatti una modalità chiara per
identificare un oggetto, come sarebbe stato se lo si fosse associato ad in
-file, e tutta l'interfaccia è inutilmente complessa. Per questo ne è stata
-effettuata una revisione completa nello standard POSIX.1b, che tratteremo in
-\secref{sec:ipc_posix}.
+file, e tutta l'interfaccia è inutilmente complessa. Per questo se ne
+sconsiglia assolutamente l'uso nei nuovi programmi, considerato che è ormai
+disponibile una revisione completa dei meccanismi di IPC fatta secondo quanto
+indicato dallo standard POSIX.1b, che presenta una realizzazione più sicura ed
+una interfaccia più semplice, che tratteremo in sez.~\ref{sec:ipc_posix}.
\subsection{Il controllo di accesso}
\label{sec:ipc_sysv_access_control}
-Oltre alle chiavi, abbiamo visto che ad ogni oggetto sono associate in
-\var{ipc\_perm} ulteriori informazioni, come gli identificatori del creatore
-(nei campi \var{cuid} e \var{cgid}) e del proprietario (nei campi \var{uid} e
-\var{gid}) dello stesso, e un insieme di permessi (nel campo \var{mode}). In
-questo modo è possibile definire un controllo di accesso sugli oggetti di IPC,
-simile a quello che si ha per i file (vedi \secref{sec:file_perm_overview}).
-
-Benché questo controllo di accesso sia molto simile a quello dei file, restano
-delle importanti differenze. La prima è che il permesso di esecuzione non
-esiste (e se specificato viene ignorato), per cui si può parlare solo di
-permessi di lettura e scrittura (nel caso dei semafori poi quest'ultimo è più
+Oltre alle chiavi, abbiamo visto in fig.~\ref{fig:ipc_ipc_perm} che ad ogni
+oggetto sono associate in \struct{ipc\_perm} ulteriori informazioni, come gli
+identificatori del creatore (nei campi \var{cuid} e \var{cgid}) e del
+proprietario (nei campi \var{uid} e \var{gid}) dello stesso, e un insieme di
+permessi (nel campo \var{mode}). In questo modo è possibile definire un
+controllo di accesso sugli oggetti di IPC, simile a quello che si ha per i
+file (vedi sez.~\ref{sec:file_perm_overview}).
+
+Benché questo controllo di accesso sia molto simile a quello dei file, restano
+delle importanti differenze. La prima è che il permesso di esecuzione non
+esiste (e se specificato viene ignorato), per cui si può parlare solo di
+permessi di lettura e scrittura (nel caso dei semafori poi quest'ultimo è più
propriamente un permesso di modifica). I valori di \var{mode} sono gli stessi
ed hanno lo stesso significato di quelli riportati in
-\secref{tab:file_mode_flags}\footnote{se però si vogliono usare le costanti
- simboliche ivi definite occorrerà includere il file \file{sys/stat.h},
- alcuni sistemi definiscono le costanti \macro{MSG\_R} (\texttt{0400}) e
- \macro{MSG\_W} (\texttt{0200}) per indicare i permessi base di lettura e
- scrittura per il proprietario, da utilizzare, con gli opportuni shift, pure
- per il gruppo e gli altri, in Linux, visto la loro scarsa utilità, queste
- costanti non sono definite.} e come per i file definiscono gli accessi per
-il proprietario, il suo gruppo e tutti gli altri.
+tab.~\ref{tab:file_mode_flags} e come per i file definiscono gli accessi per
+il proprietario, il suo gruppo e tutti gli altri.
+
+Se però si vogliono usare le costanti simboliche di
+tab.~\ref{tab:file_mode_flags} occorrerà includere anche il file
+\headfile{sys/stat.h}; alcuni sistemi definiscono le costanti \const{MSG\_R}
+(il valore ottale \texttt{0400}) e \const{MSG\_W} (il valore ottale
+\texttt{0200}) per indicare i permessi base di lettura e scrittura per il
+proprietario, da utilizzare, con gli opportuni shift, pure per il gruppo e gli
+altri. In Linux, visto la loro scarsa utilità, queste costanti non sono
+definite.
Quando l'oggetto viene creato i campi \var{cuid} e \var{uid} di
-\var{ipc\_perm} ed i campi \var{cgid} e \var{gid} vengono settati
-rispettivamente al valore dell'userid e del groupid effettivo del processo che
-ha chiamato la funzione, ma, mentre i campi \var{uid} e \var{gid} possono
+\struct{ipc\_perm} ed i campi \var{cgid} e \var{gid} vengono impostati
+rispettivamente al valore dell'\ids{UID} e del \ids{GID} effettivo del processo
+che ha chiamato la funzione, ma, mentre i campi \var{uid} e \var{gid} possono
essere cambiati, i campi \var{cuid} e \var{cgid} restano sempre gli stessi.
-Il controllo di accesso è effettuato a due livelli. Il primo livello è nelle
+Il controllo di accesso è effettuato a due livelli. Il primo livello è nelle
funzioni che richiedono l'identificatore di un oggetto data la chiave. Queste
specificano tutte un argomento \param{flag}, in tal caso quando viene
effettuata la ricerca di una chiave, qualora \param{flag} specifichi dei
permessi, questi vengono controllati e l'identificatore viene restituito solo
se corrispondono a quelli dell'oggetto. Se ci sono dei permessi non presenti
-in \var{mode} l'accesso sarà negato. Questo controllo però è di utilità
-indicativa, dato che è sempre possibile specificare per \param{flag} un valore
-nullo, nel qual caso l'identificatore sarà restituito comunque.
+in \var{mode} l'accesso sarà negato. Questo controllo però è di utilità
+indicativa, dato che è sempre possibile specificare per \param{flag} un valore
+nullo, nel qual caso l'identificatore sarà restituito comunque.
-Il secondo livello di controllo è quello delle varie funzioni che accedono
+Il secondo livello di controllo è quello delle varie funzioni che accedono
direttamente (in lettura o scrittura) all'oggetto. In tal caso lo schema dei
-controlli è simile a quello dei file, ed avviene secondo questa sequenza:
-\begin{itemize}
-\item se il processo ha i privilegi di amministratore l'accesso è sempre
- consentito.
-\item se l'userid effettivo del processo corrisponde o al valore del campo
+controlli è simile a quello dei file, ed avviene secondo questa sequenza:
+\begin{itemize*}
+\item se il processo ha i privilegi di amministratore (più precisamente la
+ capacità \const{CAP\_IPC\_OWNER}) l'accesso è sempre consentito.
+\item se l'\ids{UID} effettivo del processo corrisponde o al valore del campo
\var{cuid} o a quello del campo \var{uid} ed il permesso per il proprietario
- in \var{mode} è appropriato\footnote{per appropriato si intende che è
- settato il permesso di scrittura per le operazioni di scrittura e quello
- di lettura per le operazioni di lettura.} l'accesso è consentito.
-\item se il groupid effettivo del processo corrisponde o al
+ in \var{mode} è appropriato\footnote{per appropriato si intende che è
+ impostato il permesso di scrittura per le operazioni di scrittura e quello
+ di lettura per le operazioni di lettura.} l'accesso è consentito.
+\item se il \ids{GID} effettivo del processo corrisponde o al
valore del campo \var{cgid} o a quello del campo \var{gid} ed il permesso
- per il gruppo in \var{mode} è appropriato l'accesso è consentito.
-\item se il permesso per gli altri è appropriato l'accesso è consentito.
-\end{itemize}
-solo se tutti i controlli elencati falliscono l'accesso è negato. Si noti che
+ per il gruppo in \var{mode} è appropriato l'accesso è consentito.
+\item se il permesso per gli altri è appropriato l'accesso è consentito.
+\end{itemize*}
+solo se tutti i controlli elencati falliscono l'accesso è negato. Si noti che
a differenza di quanto avviene per i permessi dei file, fallire in uno dei
passi elencati non comporta il fallimento dell'accesso. Un'ulteriore
-differenza rispetto a quanto avviene per i file è che per gli oggetti di IPC
-il valore di \var{umask} (si ricordi quanto esposto in
-\secref{sec:file_umask}) non ha alcun significato.
+differenza rispetto a quanto avviene per i file è che per gli oggetti di IPC
+il valore di \itindex{umask} \textit{umask} (si ricordi quanto esposto in
+sez.~\ref{sec:file_perm_management}) non ha alcun significato.
\subsection{Gli identificatori ed il loro utilizzo}
\label{sec:ipc_sysv_id_use}
-L'unico campo di \var{ipc\_perm} del quale non abbiamo ancora parlato è
-\var{seq}, che in \figref{fig:ipc_ipc_perm} è qualificato con un criptico
-``\textsl{numero di sequenza}'', ne parliamo adesso dato che esso è
-strettamente attinente alle modalità con cui il kernel assegna gli
+L'unico campo di \struct{ipc\_perm} del quale non abbiamo ancora parlato è
+\var{seq}, che in fig.~\ref{fig:ipc_ipc_perm} è qualificato con un criptico
+``\textsl{numero di sequenza}'', ne parliamo adesso dato che esso è
+strettamente attinente alle modalità con cui il kernel assegna gli
identificatori degli oggetti del sistema di IPC.
Quando il sistema si avvia, alla creazione di ogni nuovo oggetto di IPC viene
Questo va benissimo nel caso dei file descriptor, che sono locali ad un
processo, ma qui il comportamento varrebbe per tutto il sistema, e per
-processi del tutto scorrelati fra loro. Così si potrebbero avere situazioni
+processi del tutto scorrelati fra loro. Così si potrebbero avere situazioni
come quella in cui un server esce e cancella le sue code di messaggi, ed il
relativo identificatore viene immediatamente assegnato a quelle di un altro
-server partito subito dopo, con la possibilità che i client del primo non
+server partito subito dopo, con la possibilità che i client del primo non
facciano in tempo ad accorgersi dell'avvenuto, e finiscano con l'interagire
con gli oggetti del secondo, con conseguenze imprevedibili.
Proprio per evitare questo tipo di situazioni il sistema usa il valore di
-\var{req} per provvedere un meccanismo che porti gli identificatori ad
-assumere tutti i valori possibili, rendendo molto più lungo il periodo in cui
-un identificatore può venire riutilizzato.
-
-Il sistema dispone sempre di un numero fisso di oggetti di IPC,\footnote{fino
- al kernel 2.2.x questi valori, definiti dalle costanti \macro{MSGMNI},
- \macro{SEMMNI} e \macro{SHMMNI}, potevano essere cambiati (come tutti gli
- altri limiti relativi al \textit{SysV IPC}) solo con una ricompilazione del
- kernel, andando a modificarne la definizione nei relativi header file. A
- partire dal kernel 2.4.x è possibile cambiare questi valori a sistema attivo
- scrivendo sui file \file{shmmni}, \file{msgmni} e \file{sem} di
- \file{/proc/sys/kernel} o con l'uso di \texttt{syscntl}.} e per ciascuno di
-essi viene mantenuto in \var{seq} un numero di sequenza progressivo che viene
-incrementato di uno ogni volta che l'oggetto viene cancellato. Quando
-l'oggetto viene creato usando uno spazio che era già stato utilizzato in
-precedenza per restituire l'identificatore al numero di oggetti presenti viene
-sommato il valore di \var{seq} moltiplicato per il numero massimo di oggetti
-di quel tipo,\footnote{questo vale fino ai kernel della serie 2.2.x, dalla
- serie 2.4.x viene usato lo stesso fattore per tutti gli oggetti, esso è dato
- dalla costante \macro{IPCMNI}, definita in \file{include/linux/ipc.h}, che
- indica il limite massimo per il numero di tutti oggetti di IPC, ed il cui
- valore è 32768.} si evita così il riutilizzo degli stessi numeri, e si fa
-sì che l'identificatore assuma tutti i valori possibili.
+\var{seq} per provvedere un meccanismo che porti gli identificatori ad
+assumere tutti i valori possibili, rendendo molto più lungo il periodo in cui
+un identificatore può venire riutilizzato.
+
+Il sistema dispone sempre di un numero fisso di oggetti di IPC, fino al kernel
+2.2.x questi erano definiti dalle costanti \const{MSGMNI}, \const{SEMMNI} e
+\const{SHMMNI}, e potevano essere cambiati (come tutti gli altri limiti
+relativi al \textit{SysV-IPC}) solo con una ricompilazione del kernel. A
+partire dal kernel 2.4.x è possibile cambiare questi valori a sistema attivo
+scrivendo sui file \sysctlrelfile{kernel}{shmmni},
+\sysctlrelfile{kernel}{msgmni} e \sysctlrelfile{kernel}{sem} di
+\file{/proc/sys/kernel} o con l'uso di \func{sysctl}.
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-int main(int argc, char *argv[])
-{
- ...
- switch (type) {
- case 'q': /* Message Queue */
- debug("Message Queue Try\n");
- for (i=0; i<n; i++) {
- id = msgget(IPC_PRIVATE, IPC_CREAT|0666);
- printf("Identifier Value %d \n", id);
- msgctl(id, IPC_RMID, NULL);
- }
- break;
- case 's': /* Semaphore */
- debug("Semaphore\n");
- for (i=0; i<n; i++) {
- id = semget(IPC_PRIVATE, 1, IPC_CREAT|0666);
- printf("Identifier Value %d \n", id);
- semctl(id, 0, IPC_RMID);
- }
- break;
- case 'm': /* Shared Memory */
- debug("Shared Memory\n");
- for (i=0; i<n; i++) {
- id = shmget(IPC_PRIVATE, 1000, IPC_CREAT|0666);
- printf("Identifier Value %d \n", id);
- shmctl(id, IPC_RMID, NULL);
- }
- break;
- default: /* should not reached */
- return -1;
- }
- return 0;
-}
- \end{lstlisting}
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/IPCTestId.c}
\end{minipage}
\normalsize
\caption{Sezione principale del programma di test per l'assegnazione degli
\label{fig:ipc_sysv_idtest}
\end{figure}
-In \figref{fig:ipc_sysv_idtest} è riportato il codice di un semplice programma
-di test che si limita a creare un oggetto (specificato a riga di comando),
-stamparne il numero di identificatore e cancellarlo per un numero specificato
-di volte. Al solito non si è riportato il codice della gestione delle opzioni
-a riga di comando, che permette di specificare quante volte effettuare il
-ciclo \var{n}, e su quale tipo di oggetto eseguirlo.
-
-La figura non riporta il codice di selezione delle opzioni, che permette di
-inizializzare i valori delle variabili \var{type} al tipo di oggetto voluto, e
-\var{n} al numero di volte che si vuole effettuare il ciclo di creazione,
-stampa, cancellazione. I valori di default sono per l'uso delle code di
-messaggi e un ciclo di 5 volte. Se si lancia il comando si otterrà qualcosa
-del tipo:
-\begin{verbatim}
-piccardi@gont sources]$ ./ipctestid
+Per ciascun tipo di oggetto di IPC viene mantenuto in \var{seq} un numero di
+sequenza progressivo che viene incrementato di uno ogni volta che l'oggetto
+viene cancellato. Quando l'oggetto viene creato usando uno spazio che era già
+stato utilizzato in precedenza, per restituire il nuovo identificatore al
+numero di oggetti presenti viene sommato il valore corrente del campo
+\var{seq}, moltiplicato per il numero massimo di oggetti di quel tipo.
+
+Questo in realtà è quanto avveniva fino ai kernel della serie 2.2, dalla serie
+2.4 viene usato lo stesso fattore di moltiplicazione per qualunque tipo di
+oggetto, utilizzando il valore dalla costante \const{IPCMNI} (definita in
+\file{include/linux/ipc.h}), che indica il limite massimo complessivo per il
+numero di tutti gli oggetti presenti nel \textit{SysV-IPC}, ed il cui default
+è 32768. Si evita così il riutilizzo degli stessi numeri, e si fa sì che
+l'identificatore assuma tutti i valori possibili.
+
+In fig.~\ref{fig:ipc_sysv_idtest} è riportato il codice di un semplice
+programma di test che si limita a creare un oggetto di IPC (specificato con
+una opzione a riga di comando), stamparne il numero di identificatore, e
+cancellarlo, il tutto un numero di volte specificato tramite una seconda
+opzione. La figura non riporta il codice di selezione delle opzioni, che
+permette di inizializzare i valori delle variabili \var{type} al tipo di
+oggetto voluto, e \var{n} al numero di volte che si vuole effettuare il ciclo
+di creazione, stampa, cancellazione.
+
+I valori di default sono per l'uso delle code di messaggi e per 5 ripetizioni
+del ciclo. Per questo motivo se non si utilizzano opzioni verrà eseguito per
+cinque volte il ciclo (\texttt{\small 7-11}), in cui si crea una coda di
+messaggi (\texttt{\small 8}), se ne stampa l'identificativo (\texttt{\small
+ 9}) e la si rimuove (\texttt{\small 10}). Non stiamo ad approfondire adesso
+il significato delle funzioni utilizzate, che verranno esaminate nelle
+prossime sezioni.
+
+Quello che ci interessa infatti è verificare l'allocazione degli
+identificativi associati agli oggetti; lanciando il comando si otterrà
+pertanto qualcosa del tipo:
+\begin{Console}
+piccardi@gont sources]$ \textbf{./ipctestid}
Identifier Value 0
Identifier Value 32768
Identifier Value 65536
Identifier Value 98304
-Identifier Value 131072
-\end{verbatim}%$
-il che ci mostra che abbiamo un kernel della serie 2.4.x nel quale non avevamo
-ancora usato nessuna coda di messaggi. Se ripetiamo il comando otterremo
-ancora:
-\begin{verbatim}
-[piccardi@gont sources]$ ./ipctestid
-Identifier Value 163840
+Identifier Value 131072
+\end{Console}
+%$
+il che ci mostra che stiamo lavorando con un kernel posteriore alla serie 2.2
+nel quale non avevamo ancora usato nessuna coda di messaggi (il valore nullo
+del primo identificativo indica che il campo \var{seq} era zero). Ripetendo il
+comando, e quindi eseguendolo in un processo diverso, in cui non può esistere
+nessuna traccia di quanto avvenuto in precedenza, otterremo come nuovo
+risultato:
+\begin{Console}
+[piccardi@gont sources]$ \textbf{./ipctestid}
+Identifier Value 163840
Identifier Value 196608
Identifier Value 229376
Identifier Value 262144
Identifier Value 294912
-\end{verbatim}%$
-che ci mostra come il valore di \var{seq} sia in effetti una quantità
-mantenuta staticamente all'interno del sistema.
+\end{Console}
+%$
+in cui la sequenza numerica prosegue, cosa che ci mostra come il valore di
+\var{seq} continui ad essere incrementato e costituisca in effetti una
+quantità mantenuta all'interno del sistema ed indipendente dai processi.
\subsection{Code di messaggi}
\label{sec:ipc_sysv_mq}
-Il primo oggetto introdotto dal \textit{SysV IPC} è quello delle code di
-messaggi. Le code di messaggi sono oggetti analoghi alle pipe o alle fifo,
-anche se la loro struttura è diversa. La funzione che permette di ottenerne
-una è \func{msgget} ed il suo prototipo è:
-\begin{functions}
- \headdecl{sys/types.h}
- \headdecl{sys/ipc.h}
- \headdecl{sys/msg.h}
-
- \funcdecl{int msgget(key\_t key, int flag)}
-
- Restituisce l'identificatore di una coda di messaggi.
-
- \bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
- in caso di errore, nel qual caso \var{errno} assumerà uno dei valori:
+Il primo oggetto introdotto dal \textit{SysV-IPC} è quello delle code di
+messaggi. Le code di messaggi sono oggetti analoghi alle \textit{pipe} o alle
+\textit{fifo} ed il loro scopo principale è quello di fornire a processi
+diversi un meccanismo con cui scambiarsi dei dati in forma di messaggio. Dato
+che le \textit{pipe} e le \textit{fifo} costituiscono una ottima alternativa,
+ed in genere sono molto più semplici da usare, le code di messaggi sono il
+meno utilizzato degli oggetti introdotti dal \textit{SysV-IPC}.
+
+La funzione di sistema che permette di ottenere l'identificativo di una coda
+di messaggi esistente per potervi accedere, oppure di creare una nuova coda
+qualora quella indicata non esista ancora, è \funcd{msgget}, e il suo
+prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/ipc.h}
+\fhead{sys/msg.h}
+\fdecl{int msgget(key\_t key, int flag)}
+\fdesc{Ottiene o crea una coda di messaggi.}
+}
+
+{La funzione ritorna l'identificatore (un intero positivo) in caso di successo
+ e $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori:
\begin{errlist}
- \item[\macro{EACCES}] Il processo chiamante non ha i privilegi per accedere
- alla coda richiesta.
- \item[\macro{EEXIST}] Si è richiesta la creazione di una coda che già
- esiste, ma erano specificati sia \macro{IPC\_CREAT} che \macro{IPC\_EXCL}.
- \item[\macro{EIDRM}] La coda richiesta è marcata per essere cancellata.
- \item[\macro{ENOENT}] Si è cercato di ottenere l'identificatore di una coda
- di messaggi specificando una chiave che non esiste e \macro{IPC\_CREAT}
+ \item[\errcode{EACCES}] il processo chiamante non ha i privilegi per
+ accedere alla coda richiesta.
+ \item[\errcode{EEXIST}] si è richiesta la creazione di una coda che già
+ esiste, ma erano specificati sia \const{IPC\_CREAT} che \const{IPC\_EXCL}.
+ \item[\errcode{EIDRM}] la coda richiesta è marcata per essere cancellata
+ (solo fino al kernel 2.3.20).
+ \item[\errcode{ENOENT}] si è cercato di ottenere l'identificatore di una coda
+ di messaggi specificando una chiave che non esiste e \const{IPC\_CREAT}
non era specificato.
- \item[\macro{ENOSPC}] Si è cercato di creare una coda di messaggi quando è
- stato superato il limite massimo di code (\macro{MSGMNI}).
- \end{errlist}
- ed inoltre \macro{ENOMEM}.
-}
-\end{functions}
+ \item[\errcode{ENOSPC}] si è cercato di creare una coda di messaggi quando è
+ stato superato il limite massimo di code (\const{MSGMNI}).
+ \end{errlist}
+ ed inoltre \errval{ENOMEM} nel suo significato generico.}
+\end{funcproto}
Le funzione (come le analoghe che si usano per gli altri oggetti) serve sia a
ottenere l'identificatore di una coda di messaggi esistente, che a crearne una
-nuova. L'argomento \param{key} specifica la chiave che è associata
+nuova. L'argomento \param{key} specifica la chiave che è associata
all'oggetto, eccetto il caso in cui si specifichi il valore
-\macro{IPC\_PRIVATE}, nel qual caso la coda è creata ex-novo e non vi è
-associata alcuna chiave, il processo (ed i suoi eventuali figli) potranno
-farvi riferimento solo attraverso l'identificatore.
-
-Se invece si specifica un valore diverso da \macro{IPC\_PRIVATE}\footnote{in
- Linux questo significa un valore diverso da zero.} l'effetto della funzione
-dipende dal valore di \param{flag}, se questo è nullo la funzione si limita ad
+\const{IPC\_PRIVATE}, nel qual caso la coda è creata ex-novo e non vi è
+associata alcuna chiave (per questo viene detta \textsl{privata}), ed il
+processo e i suoi eventuali figli potranno farvi riferimento solo attraverso
+l'identificatore.
+
+Se invece si specifica un valore diverso da \const{IPC\_PRIVATE} (in Linux
+questo significa un valore diverso da zero) l'effetto della funzione dipende
+dal valore di \param{flag}, se questo è nullo la funzione si limita ad
effettuare una ricerca sugli oggetti esistenti, restituendo l'identificatore
-se trova una corrispondenza, o fallendo con un errore di \macro{ENOENT} se non
-esiste o di \macro{EACCESS} se si sono specificati dei permessi non validi.
+se trova una corrispondenza, o fallendo con un errore di \errcode{ENOENT} se
+non esiste o di \errcode{EACCES} se si sono specificati dei permessi non
+validi.
-Se invece si vuole creare una nuova coda di messaggi \param{flag} non può
+Se invece si vuole creare una nuova coda di messaggi \param{flag} non può
essere nullo e deve essere fornito come maschera binaria, impostando il bit
-corrispondente al valore \macro{IPC\_CREAT}. In questo caso i nove bit meno
+corrispondente al valore \const{IPC\_CREAT}. In questo caso i nove bit meno
significativi di \param{flag} saranno usati come permessi per il nuovo
-oggetto, secondo quanto illustrato in \secref{sec:ipc_sysv_access_control}.
-Se si imposta anche il bit corrispondente a \macro{IPC\_EXCL} la funzione avrà
-successo solo se l'oggetto non esiste già, fallendo con un errore di
-\macro{EEXIST} altrimenti.
-
-Si tenga conto che l'uso di \macro{IPC\_PRIVATE} non impedisce ad altri
-processi di accedere alla coda (se hanno privilegi sufficienti) una volta che
-questi possano indovinare o ricavare (ad esempio per tentativi)
+oggetto, secondo quanto illustrato in sez.~\ref{sec:ipc_sysv_access_control}.
+Se si imposta anche il bit corrispondente a \const{IPC\_EXCL} la funzione avrà
+successo solo se l'oggetto non esiste già, fallendo con un errore di
+\errcode{EEXIST} altrimenti.
+
+Si tenga conto che l'uso di \const{IPC\_PRIVATE} non impedisce ad altri
+processi di accedere alla coda, se hanno privilegi sufficienti, una volta che
+questi possano indovinare o ricavare, ad esempio per tentativi,
l'identificatore ad essa associato. Per come sono implementati gli oggetti di
-IPC infatti non esiste una maniera che garantisca l'accesso esclusivo ad una
-coda di messaggi. Usare \macro{IPC\_PRIVATE} o macro{IPC\_CREAT} e
-\macro{IPC\_EXCL} per \param{flag} comporta solo la creazione di una nuova
-coda.
+IPC infatti non esiste alcun modo in cui si possa garantire l'accesso
+esclusivo ad una coda di messaggi. Usare \const{IPC\_PRIVATE} o
+\const{IPC\_CREAT} e \const{IPC\_EXCL} per \param{flag} comporta solo la
+creazione di una nuova coda.
\begin{table}[htb]
\footnotesize
\centering
\begin{tabular}[c]{|c|r|l|l|}
\hline
- \textbf{Costante} & \textbf{Valore} & \textbf{File in \texttt{proc}}
+ \textbf{Costante} & \textbf{Valore} & \textbf{File in \file{/proc}}
& \textbf{Significato} \\
\hline
\hline
- \macro{MSGMNI}& 16& \file{msgmni} & Numero massimo di code di
- messaggi. \\
- \macro{MSGMAX}& 8192& \file{msgmax} & Dimensione massima di un singolo
+ \const{MSGMNI}& 16& \file{msgmni} & Numero massimo di code di
+ messaggi.\\
+ \const{MSGMAX}& 8192& \file{msgmax} & Dimensione massima di un singolo
messaggio.\\
- \macro{MSGMNB}&16384& \file{msgmnb} & Dimensione massima del contenuto di
+ \const{MSGMNB}&16384& \file{msgmnb} & Dimensione massima del contenuto di
una coda.\\
\hline
\end{tabular}
\label{tab:ipc_msg_limits}
\end{table}
-Le code di messaggi sono caratterizzate da tre limiti fondamentali, definiti
-negli header e corrispondenti alle prime tre costanti riportate in
-\tabref{tab:ipc_msg_limits}, come accennato però in Linux è possibile
-modificare questi limiti attraverso l'uso di \func{syscntl} o scrivendo nei
-file \file{msgmax}, \file{msgmnb} e \file{msgmni} di \file{/proc/sys/kernel/}.
+Le code di messaggi sono caratterizzate da tre limiti fondamentali, un tempo
+definiti staticamente e corrispondenti alle prime tre costanti riportate in
+tab.~\ref{tab:ipc_msg_limits}. Come accennato però con tutte le versioni più
+recenti del kernel con Linux è possibile modificare questi limiti attraverso
+l'uso di \func{sysctl} o scrivendo nei file \sysctlrelfile{kernel}{msgmax},
+\sysctlrelfile{kernel}{msgmnb} e \sysctlrelfile{kernel}{msgmni} di
+\file{/proc/sys/kernel/}.
+
+\itindbeg{linked~list}
+Una coda di messaggi è costituita da una \textit{linked list}.\footnote{una
+ \textit{linked list} è una tipica struttura di dati, organizzati in una
+ lista in cui ciascun elemento contiene un puntatore al successivo. In questo
+ modo la struttura è veloce nell'estrazione ed immissione dei dati dalle
+ estremità dalla lista (basta aggiungere un elemento in testa o in coda ed
+ aggiornare un puntatore), e relativamente veloce da attraversare in ordine
+ sequenziale (seguendo i puntatori), è invece relativamente lenta
+ nell'accesso casuale e nella ricerca.} I nuovi messaggi vengono inseriti in
+coda alla lista e vengono letti dalla cima, in fig.~\ref{fig:ipc_mq_schema} si
+è riportato uno schema semplificato con cui queste strutture vengono mantenute
+dal kernel. Lo schema illustrato in realtà è una semplificazione di quello
+usato fino ai kernel della serie 2.2. A partire della serie 2.4 la gestione
+delle code di messaggi è effettuata in maniera diversa (e non esiste una
+struttura \struct{msqid\_ds} nel kernel), ma abbiamo mantenuto lo schema
+precedente dato che illustra in maniera più che adeguata i principi di
+funzionamento delle code di messaggi.
+
+\itindend{linked~list}
-\begin{figure}[htb]
- \centering \includegraphics[width=15cm]{img/mqstruct}
+\begin{figure}[!htb]
+ \centering \includegraphics[width=13cm]{img/mqstruct}
\caption{Schema della struttura di una coda messaggi.}
\label{fig:ipc_mq_schema}
\end{figure}
-Una coda di messaggi è costituita da una \textit{linked list};\footnote{una
- \textit{linked list} è una tipica struttura di dati, organizzati in una
- lista in cui ciascun elemento contiene un puntatore al successivo. In questo
- modo la struttura è veloce nell'estrazione ed immissione dei dati dalle
- estremità dalla lista (basta aggiungere un elemento in testa o in coda ed
- aggiornare un puntatore), e relativamente veloce da attraversare in ordine
- sequenziale (seguendo i puntatori), è invece relativamente lenta
- nell'accesso casuale e nella ricerca.} i nuovi messaggi vengono inseriti in
-coda alla lista e vengono letti dalla cima, in \figref{fig:ipc_mq_schema} si è
-riportato lo schema con cui queste strutture vengono mantenute dal
-kernel.\footnote{lo schema illustrato in \figref{fig:ipc_mq_schema} è in
- realtà una semplificazione di quello usato effettivamente fino ai kernel
- della serie 2.2.x, nei kernel della serie 2.4.x la gestione delle code di
- messaggi è stata modificata ed è effettuata in maniera diversa; abbiamo
- mantenuto lo schema precedente in quanto illustra comunque in maniera più
- che adeguata i principi di funzionamento delle code di messaggi.}
+A ciascuna coda è associata una struttura \struct{msqid\_ds} la cui
+definizione è riportata in fig.~\ref{fig:ipc_msqid_ds} ed a cui si accede
+includendo \headfiled{sys/msg.h};
+%
+% INFO: sotto materiale obsoleto e non interessante
+% In questa struttura il
+% kernel mantiene le principali informazioni riguardo lo stato corrente della
+% coda. Come accennato questo vale fino ai kernel della serie 2.2, essa viene
+% usata nei kernel della serie 2.4 solo per compatibilità in quanto è quella
+% restituita dalle funzioni dell'interfaccia; si noti come ci sia una differenza
+% con i campi mostrati nello schema di fig.~\ref{fig:ipc_mq_schema} che sono
+% presi dalla definizione di \file{include/linux/msg.h}, e fanno riferimento
+% alla definizione della omonima struttura usata nel kernel.
+%In fig.~\ref{fig:ipc_msqid_ds} sono elencati i campi definiti in
+%\headfile{sys/msg.h};
+si tenga presente che il campo \var{\_\_msg\_cbytes} non è previsto dallo
+standard POSIX.1-2001 e che alcuni campi fino al kernel 2.2 erano definiti
+come \ctyp{short}.
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}[labelstep=0]{}
-struct msqid_ds {
- struct ipc_perm msg_perm; /* structure for operation permission */
- time_t msg_stime; /* time of last msgsnd command */
- time_t msg_rtime; /* time of last msgrcv command */
- time_t msg_ctime; /* time of last change */
- msgqnum_t msg_qnum; /* number of messages currently on queue */
- msglen_t msg_qbytes; /* max number of bytes allowed on queue */
- pid_t msg_lspid; /* pid of last msgsnd() */
- pid_t msg_lrpid; /* pid of last msgrcv() */
- struct msg *msg_first; /* first message on queue, unused */
- struct msg *msg_last; /* last message in queue, unused */
- unsigned long int msg_cbytes; /* current number of bytes on queue */
-};
- \end{lstlisting}
+ \begin{minipage}[c]{.90\textwidth}
+ \includestruct{listati/msqid_ds.h}
\end{minipage}
\normalsize
- \caption{La struttura \var{msgid\_ds}, associata a ciascuna coda di
+ \caption{La struttura \structd{msqid\_ds}, associata a ciascuna coda di
messaggi.}
- \label{fig:ipc_msgid_ds}
+ \label{fig:ipc_msqid_ds}
\end{figure}
-A ciascuna coda è associata una struttura \var{msgid\_ds}, la cui definizione,
-è riportata in \secref{fig:ipc_msgid_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,
- essa viene usata nei kernel della serie 2.4.x solo per compatibilità in
- quanto è quella restituita dalle funzioni dell'interfaccia. Si noti come ci
- sia una differenza con i campi mostrati nello schema di
- \figref{fig:ipc_mq_schema} che sono presi dalla definizione di
- \file{linux/msg.h}, e fanno riferimento alla definizione della omonima
- struttura usata nel kernel.} In \figref{fig:ipc_msgid_ds} sono elencati i
-campi significativi definiti in \file{sys/msg.h}, a cui si sono aggiunti gli
-ultimi tre campi che sono previsti dalla implementazione originale di System
-V, ma non dallo standard Unix98.
-
Quando si crea una nuova coda con \func{msgget} questa struttura viene
-inizializzata, in particolare il campo \var{msg\_perm} viene inizializzato
-come illustrato in \secref{sec:ipc_sysv_access_control}, per quanto riguarda
-gli altri campi invece:
-\begin{itemize}
+inizializzata,\footnote{in realtà viene inizializzata una struttura interna al
+ kernel, ma i dati citati sono gli stessi.} in particolare il campo
+\var{msg\_perm} che esprime i permessi di accesso viene inizializzato nella
+modalità illustrata in sez.~\ref{sec:ipc_sysv_access_control}. Per quanto
+riguarda gli altri campi invece:
+\begin{itemize*}
\item il campo \var{msg\_qnum}, che esprime il numero di messaggi presenti
sulla coda, viene inizializzato a 0.
\item i campi \var{msg\_lspid} e \var{msg\_lrpid}, che esprimono
- rispettivamente il \acr{pid} dell'ultimo processo che ha inviato o ricevuto
+ rispettivamente il \ids{PID} dell'ultimo processo che ha inviato o ricevuto
un messaggio sulla coda, sono inizializzati a 0.
\item i campi \var{msg\_stime} e \var{msg\_rtime}, che esprimono
- rispettivamente il tempo in cui è stato inviato o ricevuto l'ultimo
+ rispettivamente il tempo in cui è stato inviato o ricevuto l'ultimo
messaggio sulla coda, sono inizializzati a 0.
-\item il campo \var{msg\_ctime}, che esprime il tempo di creazione della coda,
- viene inizializzato al tempo corrente.
-\item il campo \var{msg\_qbytes} che esprime la dimensione massima del
+\item il campo \var{msg\_ctime}, che esprime il tempo di ultima modifica della
+ coda, viene inizializzato al tempo corrente.
+\item il campo \var{msg\_qbytes}, che esprime la dimensione massima del
contenuto della coda (in byte) viene inizializzato al valore preimpostato
- del sistema (\macro{MSGMNB}).
-\item i campi \var{msg\_first} e \var{msg\_last} che esprimono l'indirizzo del
- primo e ultimo messaggio sono inizializzati a \macro{NULL} e
- \var{msg\_cbytes}, che esprime la dimensione in byte dei messaggi presenti è
- inizializzato a zero. Questi campi sono ad uso interno dell'implementazione
- e non devono essere utilizzati da programmi in user space).
-\end{itemize}
+ del sistema (\const{MSGMNB}).
+\item il campo \var{\_\_msg\_cbytes}, che esprime la dimensione in byte dei
+ messaggi presenti sulla coda, viene inizializzato a zero.
+% i campi \var{msg\_first} e \var{msg\_last} che esprimono l'indirizzo del
+% primo e ultimo messaggio sono inizializzati a \val{NULL} e
+% \var{msg\_cbytes}, che esprime la dimensione in byte dei messaggi presenti è
+% inizializzato a zero. Questi campi sono ad uso interno dell'implementazione
+% e non devono essere utilizzati da programmi in user space).
+\end{itemize*}
Una volta creata una coda di messaggi le operazioni di controllo vengono
-effettuate con la funzione \func{msgctl}, che (come le analoghe \func{semctl}
-e \func{shmctl}) fa le veci di quello che \func{ioctl} è per i file; il suo
-prototipo è:
-\begin{functions}
- \headdecl{sys/types.h}
- \headdecl{sys/ipc.h}
- \headdecl{sys/msg.h}
-
- \funcdecl{int msgctl(int msqid, int cmd, struct msqid\_ds *buf)}
-
- Esegue l'operazione specificata da \param{cmd} sulla coda \param{msqid}.
-
- \bodydesc{La funzione restituisce 0 in caso di successo o -1 in caso di
- errore, nel qual caso \var{errno} assumerà uno dei valori:
+effettuate con la funzione di sistema \funcd{msgctl}, che, come le analoghe
+\func{semctl} e \func{shmctl}, fa le veci di quello che \func{ioctl} è per i
+file; il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/ipc.h}
+\fhead{sys/msg.h}
+\fdecl{int msgctl(int msqid, int cmd, struct msqid\_ds *buf)}
+\fdesc{Esegue una operazione su una coda.}
+}
+
+{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[\macro{EACCES}] Si è richiesto \macro{IPC\_STAT} ma processo chiamante
- non ha i privilegi di lettura sulla coda.
- \item[\macro{EIDRM}] La coda richiesta è stata cancellata.
- \item[\macro{EPERM}] Si è richiesto \macro{IPC\_SET} o \macro{IPC\_RMID} ma
- il processo non ha i privilegi, o si è richiesto di aumentare il valore di
- \var{msg\_qbytes} oltre il limite \macro{MSGMNB} senza essere
+ \item[\errcode{EACCES}] si è richiesto \const{IPC\_STAT} ma processo
+ chiamante non ha i privilegi di lettura sulla coda.
+ \item[\errcode{EIDRM}] la coda richiesta è stata cancellata.
+ \item[\errcode{EPERM}] si è richiesto \const{IPC\_SET} o \const{IPC\_RMID} ma
+ il processo non ha i privilegi, o si è richiesto di aumentare il valore di
+ \var{msg\_qbytes} oltre il limite \const{MSGMNB} senza essere
amministratore.
\end{errlist}
- ed inoltre \macro{EFAULT} ed \macro{EINVAL}.
-}
-\end{functions}
-
-La funzione permette di accedere ai valori della struttura \var{msqid\_ds},
-mantenuta all'indirizzo \param{buf}, per la coda specificata
-dall'identificatore \param{msqid}. Il comportamento della funzione dipende dal
-valore dell'argomento \param{cmd}, che specifica il tipo di azione da
-eseguire; i valori possibili sono:
-\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
-\item[\macro{IPC\_STAT}] Legge le informazioni riguardo la coda nella
- struttura indicata da \param{buf}. Occorre avere il permesso di lettura
- sulla coda.
-\item[\macro{IPC\_RMID}] Rimuove la coda, cancellando tutti i dati, con
+ ed inoltre \errval{EFAULT} ed \errval{EINVAL} nel loro significato
+ generico.}
+\end{funcproto}
+
+La funzione permette di eseguire una operazione di controllo per la coda
+specificata dall'identificatore \param{msqid}, utilizzando i valori della
+struttura \struct{msqid\_ds}, mantenuta all'indirizzo \param{buf}. Il
+comportamento della funzione dipende dal valore dell'argomento \param{cmd},
+che specifica il tipo di azione da eseguire. I valori possibili
+per \param{cmd} sono:
+\begin{basedescript}{\desclabelwidth{1.6cm}\desclabelstyle{\nextlinelabel}}
+\item[\const{IPC\_STAT}] Legge le informazioni riguardo la coda nella
+ struttura \struct{msqid\_ds} indicata da \param{buf}. Occorre avere il
+ permesso di lettura sulla coda.
+\item[\const{IPC\_RMID}] Rimuove la coda, cancellando tutti i dati, con
effetto immediato. Tutti i processi che cercheranno di accedere alla coda
- riceveranno un errore di \macro{EIDRM}, e tutti processi in attesa su
- funzioni di di lettura o di scrittura sulla coda saranno svegliati ricevendo
- il medesimo errore. Questo comando può essere eseguito solo da un processo
- con userid effettivo corrispondente al creatore o al proprietario della
+ riceveranno un errore di \errcode{EIDRM}, e tutti processi in attesa su
+ funzioni di lettura o di scrittura sulla coda saranno svegliati ricevendo
+ il medesimo errore. Questo comando può essere eseguito solo da un processo
+ con \ids{UID} effettivo corrispondente al creatore o al proprietario della
coda, o all'amministratore.
-\item[\macro{IPC\_SET}] Permette di modificare i permessi ed il proprietario
+\item[\const{IPC\_SET}] Permette di modificare i permessi ed il proprietario
della coda, ed il limite massimo sulle dimensioni del totale dei messaggi in
essa contenuti (\var{msg\_qbytes}). I valori devono essere passati in una
- struttura \var{msqid\_ds} puntata da \param{buf}. Per modificare i valori
- di \var{msg\_perm.mode}, \var{msg\_perm.uid} e \var{msg\_perm.gid} occorre
- essere il proprietario o il creatore della coda, oppure l'amministratore; lo
- stesso vale per \var{msg\_qbytes}, ma l'amministratore ha la facoltà di
- incrementarne il valore a limiti superiori a \macro{MSGMNB}.
+ struttura \struct{msqid\_ds} puntata da \param{buf}. Per modificare i
+ valori di \var{msg\_perm.mode}, \var{msg\_perm.uid} e \var{msg\_perm.gid}
+ occorre essere il proprietario o il creatore della coda, oppure
+ l'amministratore e lo stesso vale per \var{msg\_qbytes}. Infine solo
+ l'amministratore (più precisamente un processo con la capacità
+ \const{CAP\_IPC\_RESOURCE}) ha la facoltà di incrementarne il valore a
+ limiti superiori a \const{MSGMNB}. Se eseguita con successo la funzione
+ aggiorna anche il campo \var{msg\_ctime}.
\end{basedescript}
+A questi tre valori, che sono quelli previsti dallo standard, su Linux se ne
+affiancano altri tre (\const{IPC\_INFO}, \const{MSG\_STAT} e
+\const{MSG\_INFO}) introdotti ad uso del programma \cmd{ipcs} per ottenere le
+informazioni generali relative alle risorse usate dalle code di
+messaggi. Questi potranno essere modificati o rimossi in favore dell'uso di
+\texttt{/proc}, per cui non devono essere usati e non li tratteremo.
Una volta che si abbia a disposizione l'identificatore, per inviare un
-messaggio su una coda si utilizza la funzione \func{msgsnd}; il suo prototipo
-è:
-\begin{functions}
- \headdecl{sys/types.h}
- \headdecl{sys/ipc.h}
- \headdecl{sys/msg.h}
-
- \funcdecl{int msgsnd(int msqid, struct msgbuf *msgp, size\_t msgsz, int
- msgflg)}
+messaggio su una coda si utilizza la funzione di sistema \funcd{msgsnd}, il
+cui prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/ipc.h}
+\fhead{sys/msg.h}
+\fdecl{int msgsnd(int msqid, struct msgbuf *msgp, size\_t msgsz, int msgflg)}
+\fdesc{Invia un messaggio su una coda.}
+}
- Invia un messaggio sulla coda \param{msqid}.
-
- \bodydesc{La funzione restituisce 0, e -1 in caso di errore, nel qual caso
- \var{errno} assumerà uno dei valori:
+{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[\macro{EACCES}] Non si hanno i privilegi di accesso sulla coda.
- \item[\macro{EIDRM}] La coda è stata cancellata.
- \item[\macro{EAGAIN}] Il messaggio non può essere inviato perché si è
- superato il limite \var{msg\_qbytes} sul numero massimo di byte presenti
- sulla coda, e si è richiesto \macro{IPC\_NOWAIT} in \param{flag}.
- \item[\macro{EINTR}] La funzione è stata interrotta da un segnale.
- \item[\macro{EINVAL}] Si è specificato un \param{msgid} invalido, o un
+ \item[\errcode{EACCES}] non si hanno i privilegi di accesso sulla coda.
+ \item[\errcode{EAGAIN}] il messaggio non può essere inviato perché si è
+ superato il limite \var{msg\_qbytes} sul numero massimo di byte presenti
+ sulla coda, e si è richiesto \const{IPC\_NOWAIT} in \param{flag}.
+ \item[\errcode{EIDRM}] la coda è stata cancellata.
+ \item[\errcode{EINVAL}] si è specificato un \param{msgid} invalido, o un
valore non positivo per \param{mtype}, o un valore di \param{msgsz}
- maggiore di \macro{MSGMAX}.
+ maggiore di \const{MSGMAX}.
\end{errlist}
- ed inoltre \macro{EFAULT} ed \macro{ENOMEM}.
-}
-\end{functions}
+ ed inoltre \errval{EFAULT}, \errval{EINTR} e \errval{ENOMEM} nel loro
+ significato generico.}
+\end{funcproto}
La funzione inserisce il messaggio sulla coda specificata da \param{msqid}; il
-messaggio ha lunghezza specificata da \param{msgsz} ed è passato attraverso il
+messaggio ha lunghezza specificata da \param{msgsz} ed è passato attraverso il
l'argomento \param{msgp}. Quest'ultimo deve venire passato sempre come
-puntatore ad una struttura \var{msgbuf} analoga a quella riportata in
-\figref{fig:ipc_msbuf} che è quella che deve contenere effettivamente il
-messaggio. La dimensione massima per il testo di un messaggio non può
-comunque superare il limite \macro{MSGMAX}.
-
-La struttura di \figref{fig:ipc_msbuf} è comunque solo un modello, tanto che
-la definizione contenuta in \file{sys/msg.h} usa esplicitamente per il secondo
-campo il valore \code{mtext[1]}, che non è di nessuna utilità ai fini pratici.
-La sola cosa che conta è che la struttura abbia come primo membro un campo
-\var{mtype} come nell'esempio; esso infatti serve ad identificare il tipo di
-messaggio e deve essere sempre specificato come intero positivo di tipo
-\ctyp{long}. Il campo \var{mtext} invece può essere di qualsiasi tipo e
-dimensione, e serve a contenere il testo del messaggio.
-
-In generale pertanto per inviare un messaggio con \func{msgsnd} si usa
-ridefinire una struttura simile a quella di \figref{fig:ipc_msbuf}, adattando
-alle proprie esigenze il campo \var{mtype}, (o ridefinendo come si vuole il
-corpo del messaggio, anche con più campi o con strutture più complesse) avendo
-però la cura di mantenere nel primo campo un valore di tipo \ctyp{long} che ne
-indica il tipo.
-
-Si tenga presente che la lunghezza che deve essere indicata in questo
-argomento è solo quella del messaggio, non quella di tutta la struttura, se
-cioè \var{message} è una propria struttura che si passa alla funzione,
-\param{msgsz} dovrà essere uguale a \code{sizeof(message)-sizeof(long)}, (se
-consideriamo il caso dell'esempio in \figref{fig:ipc_msbuf}, \param{msgsz}
-dovrà essere pari a \macro{LENGTH}).
+puntatore ad una struttura \struct{msgbuf} analoga a quella riportata in
+fig.~\ref{fig:ipc_msbuf} che è quella che deve contenere effettivamente il
+messaggio. La dimensione massima per il testo di un messaggio non può
+comunque superare il limite \const{MSGMAX}.
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}[labelstep=0]{}
- struct msgbuf {
- long mtype; /* message type, must be > 0 */
- char mtext[LENGTH]; /* message data */
- };
- \end{lstlisting}
+ \begin{minipage}[c]{0.8\textwidth}
+ \includestruct{listati/msgbuf.h}
\end{minipage}
\normalsize
- \caption{Schema della struttura \var{msgbuf}, da utilizzare come argomento
- per inviare/ricevere messaggi.}
+ \caption{Schema della struttura \structd{msgbuf}, da utilizzare come
+ argomento per inviare/ricevere messaggi.}
\label{fig:ipc_msbuf}
\end{figure}
+La struttura di fig.~\ref{fig:ipc_msbuf} è comunque solo un modello, tanto che
+la definizione contenuta in \headfile{sys/msg.h} usa esplicitamente per il
+secondo campo il valore \code{mtext[1]}, che non è di nessuna utilità ai fini
+pratici. La sola cosa che conta è che la struttura abbia come primo membro un
+campo \var{mtype} come nell'esempio; esso infatti serve ad identificare il
+tipo di messaggio e deve essere sempre specificato come intero positivo di
+tipo \ctyp{long}. Il campo \var{mtext} invece può essere di qualsiasi tipo e
+dimensione, e serve a contenere il testo del messaggio.
+
+In generale pertanto per inviare un messaggio con \func{msgsnd} si usa
+ridefinire una struttura simile a quella di fig.~\ref{fig:ipc_msbuf}, adattando
+alle proprie esigenze il campo \var{mtype}, (o ridefinendo come si vuole il
+corpo del messaggio, anche con più campi o con strutture più complesse) avendo
+però la cura di mantenere nel primo campo un valore di tipo \ctyp{long} che ne
+indica il tipo.
+
+Si tenga presente che la lunghezza che deve essere indicata in questo
+argomento è solo quella del messaggio, non quella di tutta la struttura, se
+cioè \var{message} è una propria struttura che si passa alla funzione,
+\param{msgsz} dovrà essere uguale a \code{sizeof(message)-sizeof(long)}, (se
+consideriamo il caso dell'esempio in fig.~\ref{fig:ipc_msbuf}, \param{msgsz}
+dovrà essere pari a \const{LENGTH}).
+
Per capire meglio il funzionamento della funzione riprendiamo in
considerazione la struttura della coda illustrata in
-\figref{fig:ipc_mq_schema}. Alla chiamata di \func{msgsnd} il nuovo messaggio
-sarà aggiunto in fondo alla lista inserendo una nuova struttura \var{msg}, il
-puntatore \var{msg\_last} di \var{msqid\_ds} verrà aggiornato, come pure il
-puntatore al messaggio successivo per quello che era il precedente ultimo
-messaggio; il valore di \var{mtype} verrà mantenuto in \var{msg\_type} ed il
-valore di \param{msgsz} in \var{msg\_ts}; il testo del messaggio sarà copiato
+fig.~\ref{fig:ipc_mq_schema}. Alla chiamata di \func{msgsnd} il nuovo messaggio
+sarà aggiunto in fondo alla lista inserendo una nuova struttura \struct{msg},
+il puntatore \var{msg\_last} di \struct{msqid\_ds} verrà aggiornato, come pure
+il puntatore al messaggio successivo per quello che era il precedente ultimo
+messaggio; il valore di \var{mtype} verrà mantenuto in \var{msg\_type} ed il
+valore di \param{msgsz} in \var{msg\_ts}; il testo del messaggio sarà copiato
all'indirizzo specificato da \var{msg\_spot}.
Il valore dell'argomento \param{flag} permette di specificare il comportamento
della funzione. Di norma, quando si specifica un valore nullo, la funzione
ritorna immediatamente a meno che si sia ecceduto il valore di
\var{msg\_qbytes}, o il limite di sistema sul numero di messaggi, nel qual
-caso si blocca mandando il processo in stato di \textit{sleep}. Se si
-specifica per \param{flag} il valore \macro{IPC\_NOWAIT} la funzione opera in
-modalità non bloccante, ed in questi casi ritorna immediatamente con un errore
-di \macro{EAGAIN}.
+caso si blocca. Se si specifica per \param{flag} il valore
+\const{IPC\_NOWAIT} la funzione opera in modalità non-bloccante, ed in questi
+casi ritorna immediatamente con un errore di \errcode{EAGAIN}.
-Se non si specifica \macro{IPC\_NOWAIT} la funzione resterà bloccata fintanto
+Se non si specifica \const{IPC\_NOWAIT} la funzione resterà bloccata fintanto
che non si liberano risorse sufficienti per poter inserire nella coda il
-messaggio, nel qual caso ritornerà normalmente. La funzione può ritornare, con
+messaggio, nel qual caso ritornerà normalmente. La funzione può ritornare con
una condizione di errore anche in due altri casi: quando la coda viene rimossa
-(nel qual caso si ha un errore di \macro{EIDRM}) o quando la funzione viene
-interrotta da un segnale (nel qual caso si ha un errore di \macro{EINTR}).
+(nel qual caso si ha un errore di \errcode{EIDRM}) o quando la funzione viene
+interrotta da un segnale (nel qual caso si ha un errore di \errcode{EINTR}).
Una volta completato con successo l'invio del messaggio sulla coda, la
-funzione aggiorna i dati mantenuti in \var{msqid\_ds}, in particolare vengono
-modificati:
+funzione aggiorna i dati mantenuti in \struct{msqid\_ds}, in particolare
+vengono modificati:
\begin{itemize*}
-\item Il valore di \var{msg\_lspid}, che viene impostato al \acr{pid} del
+\item Il valore di \var{msg\_lspid}, che viene impostato al \ids{PID} del
processo chiamante.
\item Il valore di \var{msg\_qnum}, che viene incrementato di uno.
\item Il valore \var{msg\_stime}, che viene impostato al tempo corrente.
\end{itemize*}
-La funzione che viene utilizzata per estrarre un messaggio da una coda è
-\func{msgrcv}; il suo prototipo è:
-\begin{functions}
- \headdecl{sys/types.h}
- \headdecl{sys/ipc.h}
- \headdecl{sys/msg.h}
+La funzione di sistema che viene utilizzata per estrarre un messaggio da una
+coda è \funcd{msgrcv}, ed il suo prototipo è:
- \funcdecl{ssize\_t msgrcv(int msqid, struct msgbuf *msgp, size\_t msgsz,
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/ipc.h}
+\fhead{sys/msg.h}
+\fdecl{ssize\_t msgrcv(int msqid, struct msgbuf *msgp, size\_t msgsz,
long msgtyp, int msgflg)}
-
- Legge un messaggio dalla coda \param{msqid}.
-
- \bodydesc{La funzione restituisce il numero di byte letti in caso di
- successo, e -1 in caso di errore, nel qual caso \var{errno} assumerà uno
- dei valori:
+\fdesc{Legge un messaggio da una coda.}
+}
+
+{La funzione ritorna il numero di byte letti in caso di successo e $-1$ per un
+ errore, nel qual caso \var{errno} assumerà uno dei valori:
\begin{errlist}
- \item[\macro{EACCES}] Non si hanno i privilegi di accesso sulla coda.
- \item[\macro{EIDRM}] La coda è stata cancellata.
- \item[\macro{E2BIG}] Il testo del messaggio è più lungo di \param{msgsz} e
- non si è specificato \macro{MSG\_NOERROR} in \param{msgflg}.
- \item[\macro{EINTR}] La funzione è stata interrotta da un segnale mentre era
- in attesa di ricevere un messaggio.
- \item[\macro{EINVAL}] Si è specificato un \param{msgid} invalido o un valore
- di \param{msgsz} negativo.
+ \item[\errcode{E2BIG}] il testo del messaggio è più lungo di \param{msgsz} e
+ non si è specificato \const{MSG\_NOERROR} in \param{msgflg}.
+ \item[\errcode{EACCES}] non si hanno i privilegi di accesso sulla coda.
+ \item[\errcode{EIDRM}] la coda è stata cancellata.
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale mentre
+ era in attesa di ricevere un messaggio.
+ \item[\errcode{EINVAL}] si è specificato un \param{msgid} invalido o un
+ valore di \param{msgsz} negativo.
\end{errlist}
- ed inoltre \macro{EFAULT}.
-}
-\end{functions}
+ ed inoltre \errval{EFAULT} nel suo significato generico.}
+\end{funcproto}
-La funzione legge un messaggio dalla coda specificata, scrivendolo sulla
-struttura puntata da \param{msgp}, che dovrà avere un formato analogo a quello
-di \figref{fig:ipc_msbuf}. Una volta estratto, il messaggio sarà rimosso dalla
-coda. L'argomento \param{msgsz} indica la lunghezza massima del testo del
-messaggio (equivalente al valore del parametro \macro{LENGTH} nell'esempio di
-\figref{fig:ipc_msbuf}).
+La funzione legge un messaggio dalla coda specificata da \param{msqid},
+scrivendolo sulla struttura puntata da \param{msgp}, che dovrà avere un
+formato analogo a quello di fig.~\ref{fig:ipc_msbuf}. Una volta estratto, il
+messaggio sarà rimosso dalla coda. L'argomento \param{msgsz} indica la
+lunghezza massima del testo del messaggio (equivalente al valore del parametro
+\const{LENGTH} nell'esempio di fig.~\ref{fig:ipc_msbuf}).
Se il testo del messaggio ha lunghezza inferiore a \param{msgsz} esso viene
-rimosso dalla coda; in caso contrario, se \param{msgflg} è impostato a
-\macro{MSG\_NOERROR}, il messaggio viene troncato e la parte in eccesso viene
+rimosso dalla coda; in caso contrario, se \param{msgflg} è impostato a
+\const{MSG\_NOERROR}, il messaggio viene troncato e la parte in eccesso viene
perduta, altrimenti il messaggio non viene estratto e la funzione ritorna con
-un errore di \macro{E2BIG}.
+un errore di \errcode{E2BIG}.
L'argomento \param{msgtyp} permette di restringere la ricerca ad un
-sottoinsieme dei messaggi presenti sulla coda; la ricerca infatti è fatta con
-una scansione della struttura mostrata in \figref{fig:ipc_mq_schema},
+sottoinsieme dei messaggi presenti sulla coda; la ricerca infatti è fatta con
+una scansione della struttura mostrata in fig.~\ref{fig:ipc_mq_schema},
restituendo il primo messaggio incontrato che corrisponde ai criteri
specificati (che quindi, visto come i messaggi vengono sempre inseriti dalla
-coda, è quello meno recente); in particolare:
+coda, è quello meno recente); in particolare:
\begin{itemize*}
-\item se \param{msgtyp} è 0 viene estratto il messaggio in cima alla coda, cioè
- quello fra i presenti che è stato inserito inserito per primo.
-\item se \param{msgtyp} è positivo viene estratto il primo messaggio il cui
+\item se \param{msgtyp} è 0 viene estratto il messaggio in cima alla coda, cioè
+ quello fra i presenti che è stato inserito per primo.
+\item se \param{msgtyp} è positivo viene estratto il primo messaggio il cui
tipo (il valore del campo \var{mtype}) corrisponde al valore di
\param{msgtyp}.
-\item se \param{msgtyp} è negativo viene estratto il primo fra i messaggi con
- il valore più basso del tipo, fra tutti quelli il cui tipo ha un valore
+\item se \param{msgtyp} è negativo viene estratto il primo fra i messaggi con
+ il valore più basso del tipo, fra tutti quelli il cui tipo ha un valore
inferiore al valore assoluto di \param{msgtyp}.
\end{itemize*}
Il valore di \param{msgflg} permette di controllare il comportamento della
-funzione, esso può essere nullo o una maschera binaria composta da uno o più
-valori. Oltre al precedente \macro{MSG\_NOERROR}, sono possibili altri due
-valori: \macro{MSG\_EXCEPT}, che permette, quando \param{msgtyp} è positivo,
+funzione, esso può essere nullo o una maschera binaria composta da uno o più
+valori. Oltre al precedente \const{MSG\_NOERROR}, sono possibili altri due
+valori: \const{MSG\_EXCEPT}, che permette, quando \param{msgtyp} è positivo,
di leggere il primo messaggio nella coda con tipo diverso da \param{msgtyp}, e
-\macro{IPC\_NOWAIT} che causa il ritorno immediato della funzione quando non
+\const{IPC\_NOWAIT} che causa il ritorno immediato della funzione quando non
ci sono messaggi sulla coda.
Il comportamento usuale della funzione infatti, se non ci sono messaggi
-disponibili per la lettura, è di bloccare il processo in stato di
-\textit{sleep}. Nel caso però si sia specificato \macro{IPC\_NOWAIT} la
-funzione ritorna immediatamente con un errore \macro{ENOMSG}. Altrimenti la
-funzione ritorna normalmente non appena viene inserito un messaggio del tipo
-desiderato, oppure ritorna con errore qualora la coda sia rimossa (con
-\var{errno} impostata a \macro{EIDRM}) o se il processo viene interrotto da un
-segnale (con \var{errno} impostata a \macro{EINTR}).
+disponibili per la lettura, è di bloccare il processo. Nel caso però si sia
+specificato \const{IPC\_NOWAIT} la funzione ritorna immediatamente con un
+errore \errcode{ENOMSG}. Altrimenti la funzione ritorna normalmente non appena
+viene inserito un messaggio del tipo desiderato, oppure ritorna con errore
+qualora la coda sia rimossa (con \var{errno} impostata a \errcode{EIDRM}) o se
+il processo viene interrotto da un segnale (con \var{errno} impostata a
+\errcode{EINTR}).
Una volta completata con successo l'estrazione del messaggio dalla coda, la
-funzione aggiorna i dati mantenuti in \var{msqid\_ds}, in particolare vengono
-modificati:
+funzione aggiorna i dati mantenuti in \struct{msqid\_ds}, in particolare
+vengono modificati:
\begin{itemize*}
-\item Il valore di \var{msg\_lrpid}, che viene impostato al \acr{pid} del
+\item Il valore di \var{msg\_lrpid}, che viene impostato al \ids{PID} del
processo chiamante.
\item Il valore di \var{msg\_qnum}, che viene decrementato di uno.
\item Il valore \var{msg\_rtime}, che viene impostato al tempo corrente.
\end{itemize*}
Le code di messaggi presentano il solito problema di tutti gli oggetti del
-SysV IPC; essendo questi permanenti restano nel sistema occupando risorse
-anche quando un processo è terminato, al contrario delle pipe per le quali
-tutte le risorse occupate vengono rilasciate quanto l'ultimo processo che le
-utilizzava termina. Questo comporta che in caso di errori si può saturare il
-sistema, e che devono comunque essere esplicitamente previste delle funzioni
-di rimozione in caso di interruzioni o uscite dal programma (come vedremo in
-\figref{fig:ipc_mq_fortune_server}).
-
-L'altro problema è non facendo uso di file descriptor le tecniche di
-\textit{I/O multiplexing} descritte in \secref{sec:file_multiplexing} non
+\textit{SysV-IPC} che essendo questi permanenti restano nel sistema occupando
+risorse anche quando un processo è terminato, al contrario delle \textit{pipe}
+per le quali tutte le risorse occupate vengono rilasciate quanto l'ultimo
+processo che le utilizzava termina. Questo comporta che in caso di errori si
+può saturare il sistema, e che devono comunque essere esplicitamente previste
+delle funzioni di rimozione in caso di interruzioni o uscite dal programma
+(come vedremo in fig.~\ref{fig:ipc_mq_fortune_server}).
+
+L'altro problema è che non facendo uso di file descriptor le tecniche di
+\textit{I/O multiplexing} descritte in sez.~\ref{sec:file_multiplexing} non
possono essere utilizzate, e non si ha a disposizione niente di analogo alle
-funzioni \func{select} e \func{poll}. Questo rende molto scomodo usare più di
-una di queste strutture alla volta; ad esempio non si può scrivere un server
-che aspetti un messaggio su più di una coda senza fare ricorso ad una tecnica
-di \textit{polling}\index{polling} che esegua un ciclo di attesa su ciascuna
-di esse.
+funzioni \func{select} e \func{poll}. Questo rende molto scomodo usare più di
+una di queste strutture alla volta; ad esempio non si può scrivere un server
+che aspetti un messaggio su più di una coda senza fare ricorso ad una tecnica
+di \itindex{polling} \textit{polling} che esegua un ciclo di attesa su
+ciascuna di esse.
Come esempio dell'uso delle code di messaggi possiamo riscrivere il nostro
-server di \textit{fortunes} usando queste al posto delle fifo. In questo caso
-useremo una sola coda di messaggi, usando il tipo di messaggio per comunicare
-in maniera indipendente con client diversi.
+server di \textit{fortunes} usando queste al posto delle \textit{fifo}. In
+questo caso useremo una sola coda di messaggi, usando il tipo di messaggio per
+comunicare in maniera indipendente con client diversi.
-\begin{figure}[!bht]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-int msgid; /* Message queue identifier */
-int main(int argc, char *argv[])
-{
-/* Variables definition */
- int i, n = 0;
- char **fortune; /* array of fortune message string */
- char *fortunefilename; /* fortune file name */
- struct msgbuf_read { /* message struct to read request from clients */
- long mtype; /* message type, must be 1 */
- long pid; /* message data, must be the pid of the client */
- } msg_read;
- struct msgbuf_write { /* message struct to write result to clients */
- long mtype; /* message type, will be the pid of the client*/
- char mtext[MSGMAX]; /* message data, will be the fortune */
- } msg_write;
- key_t key; /* Message queue key */
- int size; /* message size */
- ...
- Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
- Signal(SIGINT, HandSIGTERM);
- Signal(SIGQUIT, HandSIGTERM);
- if (n==0) usage(); /* if no pool depth exit printing usage info */
- i = FortuneParse(fortunefilename, fortune, n); /* parse phrases */
- /* Create the queue */
- key = ftok("./MQFortuneServer.c", 1);
- msgid = msgget(key, IPC_CREAT|0666);
- if (msgid < 0) {
- perror("Cannot create message queue");
- exit(1);
- }
- /* Main body: loop over requests */
- while (1) {
- msgrcv(msgid, &msg_read, sizeof(int), 1, MSG_NOERROR);
- n = random() % i; /* select random value */
- strncpy(msg_write.mtext, fortune[n], MSGMAX);
- size = min(strlen(fortune[n])+1, MSGMAX);
- msg_write.mtype=msg_read.pid; /* use request pid as type */
- msgsnd(msgid, &msg_write, size, 0);
- }
-}
-/*
- * Signal Handler to manage termination
- */
-void HandSIGTERM(int signo) {
- msgctl(msgid, IPC_RMID, NULL); /* remove message queue */
- exit(0);
-}
- \end{lstlisting}
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/MQFortuneServer.c}
\end{minipage}
\normalsize
\caption{Sezione principale del codice del server di \textit{fortunes}
\label{fig:ipc_mq_fortune_server}
\end{figure}
-In \figref{fig:ipc_mq_fortune_server} si è riportato un estratto delle parti
-principali del codice del nuovo server (il codice completo è nel file
-\file{MQFortuneServer.c} nei sorgenti allegati). Il programma è basato su un
+In fig.~\ref{fig:ipc_mq_fortune_server} si è riportato un estratto delle parti
+principali del codice del nuovo server (il codice completo è nel file
+\file{MQFortuneServer.c} nei sorgenti allegati). Il programma è basato su un
uso accorto della caratteristica di poter associate un ``tipo'' ai messaggi
per permettere una comunicazione indipendente fra il server ed i vari client,
-usando il \acr{pid} di questi ultimi come identificativo. Questo è possibile
-in quanto, al contrario di una fifo, la lettura di una coda di messaggi può
-non essere sequenziale, proprio grazie alla classificazione dei messaggi sulla
-base del loro tipo.
+usando il \ids{PID} di questi ultimi come identificativo. Questo è possibile
+in quanto, al contrario di una \textit{fifo}, la lettura di una coda di
+messaggi può non essere sequenziale, proprio grazie alla classificazione dei
+messaggi sulla base del loro tipo.
Il programma, oltre alle solite variabili per il nome del file da cui leggere
le \textit{fortunes} e per il vettore di stringhe che contiene le frasi,
definisce due strutture appositamente per la comunicazione; con
-\var{msgbuf\_read} (\texttt{\small 8--11}) vengono passate le richieste mentre
-con \var{msgbuf\_write} (\texttt{\small 12--15}) vengono restituite le frasi.
-
-La gestione delle opzioni si è al solito omessa, essa si curerà di impostare
-in \var{n} il numero di frasi da leggere specificato a linea di comando ed in
-\var{fortunefilename} il file da cui leggerle; dopo aver installato
-(\texttt{\small 19--21}) dei manipolatori per gestire l'uscita dal server,
-viene prima controllato (\texttt{\small 22}) il numero di frasi richieste
-abbia senso (cioè sia maggiore di zero), le quali poi (\texttt{\small 23})
-vengono lette nel vettore in memoria con la stessa funzione
-\code{FortuneParse()} usata anche per il server basato sulle fifo.
+\var{msgbuf\_read} vengono passate (\texttt{\small 8-11}) le richieste mentre
+con \var{msgbuf\_write} vengono restituite (\texttt{\small 12-15}) le frasi.
+
+La gestione delle opzioni si è al solito omessa, essa si curerà di impostare
+nella variabile \var{n} il numero di frasi da leggere specificato a linea di
+comando ed in \var{fortunefilename} il file da cui leggerle. Dopo aver
+installato (\texttt{\small 19-21}) i gestori dei segnali per trattare
+l'uscita dal server, viene prima controllato (\texttt{\small 22}) il numero di
+frasi richieste abbia senso (cioè sia maggiore di zero), le quali poi vengono
+lette (\texttt{\small 23}) nel vettore in memoria con la stessa funzione
+\code{FortuneParse} usata anche per il server basato sulle \textit{fifo}.
Una volta inizializzato il vettore di stringhe coi messaggi presi dal file
delle \textit{fortune} si procede (\texttt{\small 25}) con la generazione di
sorgenti del server) con la quale poi si esegue (\texttt{\small 26}) la
creazione della stessa (si noti come si sia chiamata \func{msgget} con un
valore opportuno per l'argomento \param{flag}), avendo cura di abortire il
-programma (\texttt{\small 27--29}) in caso di errore.
-
-Finita la fase di inizializzazione il server esegue in permanenza il ciclo
-principale (\texttt{\small 32--41}). Questo inizia (\texttt{\small 33}) con il
-porsi in attesa di un messaggio di richiesta da parte di un client; si noti
-infatti come \func{msgrcv} richieda un messaggio con \var{mtype} uguale a 1:
-questo è il valore usato per le richieste dato che corrisponde al \acr{pid} di
-\cmd{init}, che non può essere un client. L'uso del flag \macro{MSG\_NOERROR}
-è solo per sicurezza, dato che i messaggi di richiesta sono di dimensione
-fissa (e contengono solo il \acr{pid} del client).
-
-Se non sono presenti messaggi di richiesta \func{msgrcv} si bloccherà,
+programma (\texttt{\small 27-29}) in caso di errore.
+
+Finita la fase di inizializzazione il server prima (\texttt{\small 32}) chiama
+la funzione \func{daemon} per andare in background e poi esegue in permanenza
+il ciclo principale (\texttt{\small 33-40}). Questo inizia (\texttt{\small
+ 34}) con il porsi in attesa di un messaggio di richiesta da parte di un
+client. Si noti infatti come \func{msgrcv} richieda un messaggio con
+\var{mtype} uguale a 1, questo è il valore usato per le richieste dato che
+corrisponde al \ids{PID} di \cmd{init}, che non può essere un client. L'uso
+del flag \const{MSG\_NOERROR} è solo per sicurezza, dato che i messaggi di
+richiesta sono di dimensione fissa (e contengono solo il \ids{PID} del
+client).
+
+Se non sono presenti messaggi di richiesta \func{msgrcv} si bloccherà,
ritornando soltanto in corrispondenza dell'arrivo sulla coda di un messaggio
di richiesta da parte di un client, in tal caso il ciclo prosegue
-(\texttt{\small 34}) selezionando una frase a caso, copiandola (\texttt{\small
- 35}) nella struttura \var{msgbuf\_write} usata per la risposta e
-calcolandone (\texttt{\small 36}) la dimensione.
+(\texttt{\small 35}) selezionando una frase a caso, copiandola (\texttt{\small
+ 36}) nella struttura \var{msgbuf\_write} usata per la risposta e
+calcolandone (\texttt{\small 37}) la dimensione.
Per poter permettere a ciascun client di ricevere solo la risposta indirizzata
-a lui il tipo del messaggio in uscita viene inizializzato (\texttt{\small 37})
-al valore del \acr{pid} del client ricevuto nel messaggio di richiesta.
-L'ultimo passo del ciclo (\texttt{\small 38}) è inviare sulla coda il
-messaggio di risposta. Si tenga conto che se la coda è piena anche questa
-funzione potrà bloccarsi fintanto che non venga liberato dello spazio.
-
-Si noti che il programma può terminare solo grazie ad una interruzione da
-parte di un segnale; in tal caso verrà eseguito il manipolatore
-\code{HandSIGTERM}, che semplicemente si limita a cancellare la coda
-(\texttt{\small 44}) ed ad uscire (\texttt{\small 45}).
-
-\begin{figure}[!bht]
+a lui il tipo del messaggio in uscita viene inizializzato (\texttt{\small 38})
+al valore del \ids{PID} del client ricevuto nel messaggio di richiesta.
+L'ultimo passo del ciclo (\texttt{\small 39}) è inviare sulla coda il
+messaggio di risposta. Si tenga conto che se la coda è piena anche questa
+funzione potrà bloccarsi fintanto che non venga liberato dello spazio.
+
+Si noti che il programma può terminare solo grazie ad una interruzione da
+parte di un segnale; in tal caso verrà eseguito (\texttt{\small 45-48}) il
+gestore \code{HandSIGTERM}, che semplicemente si limita a cancellare la coda
+(\texttt{\small 46}) ed ad uscire (\texttt{\small 47}).
+
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-int main(int argc, char *argv[])
-{
- ...
- key = ftok("./MQFortuneServer.c", 1);
- msgid = msgget(key, 0);
- if (msgid < 0) {
- perror("Cannot find message queue");
- exit(1);
- }
- /* Main body: do request and write result */
- msg_read.mtype = 1; /* type for request is always 1 */
- msg_read.pid = getpid(); /* use pid for communications */
- size = sizeof(msg_read.pid);
- msgsnd(msgid, &msg_read, size, 0); /* send request message */
- msgrcv(msgid, &msg_write, MSGMAX, msg_read.pid, MSG_NOERROR);
- printf("%s", msg_write.mtext);
-}
- \end{lstlisting}
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/MQFortuneClient.c}
\end{minipage}
\normalsize
\caption{Sezione principale del codice del client di \textit{fortunes}
\label{fig:ipc_mq_fortune_client}
\end{figure}
-In \figref{fig:ipc_mq_fortune_client} si è riportato un estratto il codice del
-programma client. Al solito il codice completo è con i sorgenti allegati, nel
-file \file{MQFortuneClient.c}. Come sempre si sono rimosse le parti relative
-alla gestione delle opzioni, ed in questo caso, anche la dichiarazione delle
-variabili, che, per la parte relative alle strutture usate per la
-comunicazione tramite le code, sono le stesse viste in
-\figref{fig:ipc_mq_fortune_server}.
+In fig.~\ref{fig:ipc_mq_fortune_client} si è riportato un estratto il codice
+del programma client. Al solito il codice completo è con i sorgenti allegati,
+nel file \file{MQFortuneClient.c}. Come sempre si sono rimosse le parti
+relative alla gestione delle opzioni, ed in questo caso, anche la
+dichiarazione delle variabili, che, per la parte relative alle strutture usate
+per la comunicazione tramite le code, sono le stesse viste in
+fig.~\ref{fig:ipc_mq_fortune_server}.
-Il client in questo caso è molto semplice; la prima parte del programma
-(\texttt{\small 4--9}) si occupa di accedere alla coda di messaggi, ed è
+Il client in questo caso è molto semplice; la prima parte del programma
+(\texttt{\small 4-9}) si occupa di accedere alla coda di messaggi, ed è
identica a quanto visto per il server, solo che in questo caso \func{msgget}
non viene chiamata con il flag di creazione in quanto la coda deve essere
-preesistente. In caso di errore (ad esempio se il server non è stato avviato)
+preesistente. In caso di errore (ad esempio se il server non è stato avviato)
il programma termina immediatamente.
-Una volta acquisito l'identificatore della coda il client compone il
-messaggio di richiesta (\texttt{\small 12--13}) in \var{msg\_read}, usando 1
-per il tipo ed inserendo il proprio \acr{pid} come dato da passare al server.
-Calcolata (\texttt{\small 14}) la dimensione, provvede (\texttt{\small 15}) ad
-immettere la richiesta sulla coda.
-
-A questo punto non resta che (\texttt{\small 16}) rileggere dalla coda la
-risposta del server richiedendo a \func{msgrcv} di selezionare i messaggi di
-tipo corrispondente al valore del \acr{pid} inviato nella richiesta. L'ultimo
-passo (\texttt{\small 17}) prima di uscire è quello di stampare a video il
-messaggio ricevuto.
+Una volta acquisito l'identificatore della coda il client compone
+(\texttt{\small 12-13}) il messaggio di richiesta in \var{msg\_read}, usando
+1 per il tipo ed inserendo il proprio \ids{PID} come dato da passare al
+server. Calcolata (\texttt{\small 14}) la dimensione, provvede
+(\texttt{\small 15}) ad immettere la richiesta sulla coda.
+
+A questo punto non resta che rileggere la risposta (\texttt{\small 16}) dalla
+coda del server richiedendo a \func{msgrcv} di selezionare i messaggi di tipo
+corrispondente al valore del \ids{PID} inviato nella richiesta. L'ultimo passo
+(\texttt{\small 17}) prima di uscire è quello di stampare a video il messaggio
+ricevuto.
-Benché funzionante questa architettura risente dello stesso inconveniente
-visto anche nel caso del precedente server basato sulle fifo; se il client
-viene interrotto dopo l'invio del messaggio di richiesta e prima della lettura
-della risposta, quest'ultima resta nella coda (così come per le fifo si aveva
-il problema delle fifo che restavano nel filesystem). In questo caso però il
-problemi sono maggiori, sia perché è molto più facile esaurire la memoria
-dedicata ad una coda di messaggi che gli inode di un filesystem, sia perché,
-con il riutilizzo dei \acr{pid} da parte dei processi, un client eseguito in
-un momento successivo potrebbe ricevere un messaggio non indirizzato a
-lui.
-
-
-
-\subsection{Semafori}
+Proviamo allora il nostro nuovo sistema, al solito occorre definire
+\code{LD\_LIBRARY\_PATH} per accedere alla libreria \file{libgapil.so}, dopo
+di che, in maniera del tutto analoga a quanto fatto con il programma che usa
+le \textit{fifo}, potremo far partire il server con:
+\begin{Console}
+[piccardi@gont sources]$ \textbf{./mqfortuned -n10}
+\end{Console}
+%$
+come nel caso precedente, avendo eseguito il server in background, il comando
+ritornerà immediatamente; potremo però verificare con \cmd{ps} che il
+programma è effettivamente in esecuzione, e che ha creato una coda di
+messaggi:
+\begin{Console}
+[piccardi@gont sources]$ \textbf{ipcs}
+
+------ Shared Memory Segments --------
+key shmid owner perms bytes nattch status
+
+------ Semaphore Arrays --------
+key semid owner perms nsems
+
+------ Message Queues --------
+key msqid owner perms used-bytes messages
+0x0102dc6a 0 piccardi 666 0 0
+\end{Console}
+%$
+a questo punto potremo usare il client per ottenere le nostre frasi:
+\begin{Console}
+[piccardi@gont sources]$ \textbf{./mqfortune}
+Linux ext2fs has been stable for a long time, now it's time to break it
+ -- Linuxkongreß '95 in Berlin
+[piccardi@gont sources]$ \textbf{./mqfortune}
+Let's call it an accidental feature.
+ --Larry Wall
+\end{Console}
+con un risultato del tutto equivalente al precedente. Infine potremo chiudere
+il server inviando il segnale di terminazione con il comando \code{killall
+ mqfortuned}, verificando che effettivamente la coda di messaggi venga
+rimossa.
+
+Benché funzionante questa architettura risente dello stesso inconveniente
+visto anche nel caso del precedente server basato sulle \textit{fifo}; se il
+client viene interrotto dopo l'invio del messaggio di richiesta e prima della
+lettura della risposta, quest'ultima resta nella coda (così come per le
+\textit{fifo} si aveva il problema delle \textit{fifo} che restavano nel
+filesystem). In questo caso però il problemi sono maggiori, sia perché è molto
+più facile esaurire la memoria dedicata ad una coda di messaggi che gli
+\textit{inode} di un filesystem, sia perché, con il riutilizzo dei \ids{PID}
+da parte dei processi, un client eseguito in un momento successivo potrebbe
+ricevere un messaggio non indirizzato a lui.
+
+
+\subsection{I semafori}
\label{sec:ipc_sysv_sem}
-I semafori non sono meccanismi di intercomunicazione diretta come quelli
-(pipe, fifo e code di messaggi) visti finora, e non consentono di scambiare
-dati fra processi, ma servono piuttosto come meccanismi di sincronizzazione o
-di protezione per le \textsl{sezioni critiche}\index{sezioni critiche} del
-codice (si ricordi quanto detto in \secref{sec:proc_race_cond}).
-
-Un semaforo è uno speciale contatore, mantenuto nel kernel, che permette, a
-seconda del suo valore, di consentire o meno la prosecuzione dell'esecuzione
-di un programma. In questo modo l'accesso ad una risorsa condivisa da più
-processi può essere controllato, associando ad essa un semaforo che consente
-di assicurare che non più di un processo alla volta possa usarla.
-
-Il concetto di semaforo è uno dei concetti base nella programmazione ed è
-assolutamente generico, così come del tutto generali sono modalità con cui lo
-si utilizza. Un processo che deve accedere ad una risorsa eseguirà un
-controllo del semaforo: se questo è positivo il suo valore sarà decrementato,
-indicando che si è consumato una unità della risorsa, ed il processo potrà
-proseguire nell'utilizzo di quest'ultima, provvedendo a rilasciarla, una volta
-completate le operazioni volute, reincrementando il semaforo.
-
-Se al momento del controllo il valore del semaforo è nullo, siamo invece in
-una situazione in cui la risorsa non è disponibile, ed il processo si
-bloccherà in stato di \textit{sleep} fin quando chi la sta utilizzando non la
-rilascerà, incrementando il valore del semaforo. Non appena il semaforo torna
-positivo, indicando che la risorsa è disponibile, il processo sarà svegliato,
-e si potrà operare come nel caso precedente (decremento del semaforo, accesso
-alla risorsa, incremento del semaforo).
+I semafori non sono propriamente meccanismi di intercomunicazione come
+\textit{pipe}, \textit{fifo} e code di messaggi, poiché non consentono di
+scambiare dati fra processi, ma servono piuttosto come meccanismi di
+sincronizzazione o di protezione per le \textsl{sezioni critiche} del codice
+(si ricordi quanto detto in sez.~\ref{sec:proc_race_cond}). Un semaforo
+infatti non è altro che un contatore mantenuto nel kernel che determina se
+consentire o meno la prosecuzione dell'esecuzione di un programma. In questo
+modo si può controllare l'accesso ad una risorsa condivisa da più processi,
+associandovi un semaforo che assicuri che non possa essere usata da più di un
+processo alla volta.
+
+Il concetto di semaforo è uno dei concetti base nella programmazione ed è
+assolutamente generico, così come del tutto generali sono modalità con cui lo
+si utilizza. Un processo che deve accedere ad una risorsa condivisa eseguirà
+un controllo del semaforo: se questo è positivo il suo valore sarà
+decrementato, indicando che si è consumato una unità della risorsa, ed il
+processo potrà proseguire nell'utilizzo di quest'ultima, provvedendo a
+rilasciarla, una volta completate le operazioni volute, reincrementando il
+semaforo.
+
+Se al momento del controllo il valore del semaforo è nullo la risorsa viene
+considerata non disponibile, ed il processo si bloccherà fin quando chi la sta
+utilizzando non la rilascerà, incrementando il valore del semaforo. Non appena
+il semaforo diventa positivo, indicando che la risorsa è tornata disponibile,
+il processo bloccato in attesa riprenderà l'esecuzione, e potrà operare come
+nel caso precedente (decremento del semaforo, accesso alla risorsa, incremento
+del semaforo).
Per poter implementare questo tipo di logica le operazioni di controllo e
decremento del contatore associato al semaforo devono essere atomiche,
-pertanto una realizzazione di un oggetto di questo tipo è necessariamente
-demandata al kernel. La forma più semplice di semaforo è quella del
+pertanto una realizzazione di un oggetto di questo tipo è necessariamente
+demandata al kernel. La forma più semplice di semaforo è quella del
\textsl{semaforo binario}, o \textit{mutex}, in cui un valore diverso da zero
-(normalmente 1) indica la libertà di accesso, e un valore nullo l'occupazione
-della risorsa; in generale però si possono usare semafori con valori interi,
+(normalmente 1) indica la libertà di accesso, e un valore nullo l'occupazione
+della risorsa. In generale però si possono usare semafori con valori interi,
utilizzando il valore del contatore come indicatore del ``numero di risorse''
ancora disponibili.
-Il sistema di comunicazione interprocesso di \textit{SysV IPC} prevede anche i
-semafori, ma gli oggetti utilizzati non sono semafori singoli, ma gruppi di
-semafori detti \textsl{insiemi} (o \textit{semaphore set}); la funzione che
-permette di creare o ottenere l'identificatore di un insieme di semafori è
-\func{semget}, ed il suo prototipo è:
-\begin{functions}
- \headdecl{sys/types.h}
- \headdecl{sys/ipc.h}
- \headdecl{sys/sem.h}
-
- \funcdecl{int semget(key\_t key, int nsems, int flag)}
-
- Restituisce l'identificatore di un insieme di semafori.
-
- \bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
- in caso di errore, nel qual caso \var{errno} assumerà i valori:
- \begin{errlist}
- \item[\macro{ENOSPC}] Si è cercato di creare una insieme di semafori
- quando è stato superato o il limite per il numero totale di semafori
- (\macro{SEMMNS}) o quello per il numero totale degli insiemi
- (\macro{SEMMNI}) nel sistema.
- \item[\macro{EINVAL}] L'argomento \param{nsems} è minore di zero o
- maggiore del limite sul numero di semafori per ciascun insieme
- (\macro{SEMMSL}), o se l'insieme già esiste, maggiore del numero di
- semafori che contiene.
- \item[\macro{ENOMEM}] Il sistema non ha abbastanza memoria per poter
- contenere le strutture per un nuovo insieme di semafori.
- \end{errlist}
- ed inoltre \macro{EACCES}, \macro{ENOENT}, \macro{EEXIST}, \macro{EIDRM},
- con lo stesso significato che hanno per \func{msgget}.}
-\end{functions}
-
-La funzione è del tutto analoga a \func{msgget}, solo che in questo caso
-restituisce l'identificatore di un insieme di semafori, in particolare è
+Il sistema di intercomunicazione di \textit{SysV-IPC} prevede anche una
+implementazione dei semafori, ma gli oggetti utilizzati sono tuttavia non
+semafori singoli, ma gruppi (più propriamente \textsl{insiemi}) di semafori
+detti ``\textit{semaphore set}''. La funzione di sistema che permette di
+creare o ottenere l'identificatore di un insieme di semafori è \funcd{semget},
+ed il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/ipc.h}
+\fhead{sys/sem.h}
+\fdecl{int semget(key\_t key, int nsems, int flag)}
+\fdesc{Restituisce l'identificatore di un insieme di semafori.}
+}
+
+{La funzione ritorna l'identificatore (un intero positivo) in caso di successo
+ e $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{ENOSPC}] si è superato il limite di sistema per il numero
+ totale di semafori (\const{SEMMNS}) o di insiemi (\const{SEMMNI}).
+ \item[\errcode{EINVAL}] \param{nsems} è minore di zero o maggiore del limite
+ sul numero di semafori di un insieme (\const{SEMMSL}), o se l'insieme già
+ esiste, maggiore del numero di semafori che contiene.
+ \item[\errcode{ENOMEM}] il sistema non ha abbastanza memoria per poter
+ contenere le strutture per un nuovo insieme di semafori.
+ \end{errlist}
+ ed inoltre \errval{EACCES}, \errval{EEXIST}, \errval{EIDRM} e
+ \errval{ENOENT} con lo stesso significato che hanno per \func{msgget}.}
+\end{funcproto}
+
+La funzione è del tutto analoga a \func{msgget}, solo che in questo caso
+restituisce l'identificatore di un insieme di semafori, in particolare è
identico l'uso degli argomenti \param{key} e \param{flag}, per cui non
-ripeteremo quanto detto al proposito in \secref{sec:ipc_sysv_mq}. L'argomento
+ripeteremo quanto detto al proposito in sez.~\ref{sec:ipc_sysv_mq}. L'argomento
\param{nsems} permette di specificare quanti semafori deve contenere l'insieme
quando se ne richieda la creazione, e deve essere nullo quando si effettua una
-richiesta dell'identificatore di un insieme già esistente.
+richiesta dell'identificatore di un insieme già esistente.
Purtroppo questa implementazione complica inutilmente lo schema elementare che
-abbiamo descritto, dato che non è possibile definire un singolo semaforo, ma
-se ne deve creare per forza un insieme. Ma questa in definitiva è solo una
-complicazione inutile, il problema è che i semafori del \textit{SysV IPC}
-soffrono di altri due, ben più gravi, difetti.
+abbiamo descritto, dato che non è possibile definire un singolo semaforo, ma
+se ne deve creare per forza un insieme. Ma questa in definitiva è solo una
+complicazione inutile dell'interfaccia, il problema è che i semafori forniti
+dal \textit{SysV-IPC} soffrono di altri due difetti progettuali molto più
+gravi.
-Il primo difetto è che non esiste una funzione che permetta di creare ed
+Il primo difetto è che non esiste una funzione che permetta di creare ed
inizializzare un semaforo in un'unica chiamata; occorre prima creare l'insieme
dei semafori con \func{semget} e poi inizializzarlo con \func{semctl}, si
-perde così ogni possibilità di eseguire atomicamente questa operazione.
+perde così ogni possibilità di eseguire l'operazione atomicamente. Eventuali
+accessi che possono avvenire fra la creazione e l'inizializzazione potranno
+avere effetti imprevisti.
Il secondo difetto deriva dalla caratteristica generale degli oggetti del
-\textit{SysV IPC} di essere risorse globali di sistema, che non vengono
-cancellate quando nessuno le usa più; ci si così a trova a dover affrontare
-esplicitamente il caso in cui un processo termina per un qualche errore,
-lasciando un semaforo occupato, che resterà tale fino al successivo riavvio
-del sistema. Come vedremo esistono delle modalità per evitare tutto ciò, ma
-diventa necessario indicare esplicitamente che si vuole il ripristino del
-semaforo all'uscita del processo.
-
+\textit{SysV-IPC} di essere risorse globali di sistema, che non vengono
+cancellate quando nessuno le usa più. In questo caso il problema è più grave
+perché ci si a trova a dover affrontare esplicitamente il caso in cui un
+processo termina per un qualche errore lasciando un semaforo occupato, che
+resterà tale fino al successivo riavvio del sistema. Come vedremo esistono
+delle modalità per evitare tutto ciò, ma diventa necessario indicare
+esplicitamente che si vuole il ripristino del semaforo all'uscita del
+processo, e la gestione diventa più complicata.
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}[labelstep=0]{}
-struct semid_ds
-{
- struct ipc_perm sem_perm; /* operation permission struct */
- time_t sem_otime; /* last semop() time */
- time_t sem_ctime; /* last time changed by semctl() */
- unsigned long int sem_nsems; /* number of semaphores in set */
-};
- \end{lstlisting}
+ \begin{minipage}[c]{.80\textwidth}
+ \includestruct{listati/semid_ds.h}
\end{minipage}
\normalsize
- \caption{La struttura \var{semid\_ds}, associata a ciascun insieme di
+ \caption{La struttura \structd{semid\_ds}, associata a ciascun insieme di
semafori.}
\label{fig:ipc_semid_ds}
\end{figure}
-A ciascun insieme di semafori è associata una struttura \var{semid\_ds},
-riportata in \figref{fig:ipc_semid_ds}.\footnote{non si sono riportati i campi
- ad uso interno del kernel, che vedremo in \figref{fig:ipc_sem_schema}, che
- dipendono dall'implementazione.} Come nel caso delle code di messaggi quando
-si crea un nuovo insieme di semafori con \func{semget} questa struttura viene
-inizializzata, in particolare il campo \var{sem\_perm} viene inizializzato
-come illustrato in \secref{sec:ipc_sysv_access_control} (si ricordi che in
-questo caso il permesso di scrittura è in realtà permesso di alterare il
-semaforo), per quanto riguarda gli altri campi invece:
+A ciascun insieme di semafori è associata una struttura \struct{semid\_ds},
+riportata in fig.~\ref{fig:ipc_semid_ds}.\footnote{anche in questo caso in
+ realtà il kernel usa una sua specifica struttura interna, ma i dati
+ significativi sono sempre quelli citati.} Come nel caso delle code di
+messaggi quando si crea un nuovo insieme di semafori con \func{semget} questa
+struttura viene inizializzata. In particolare il campo \var{sem\_perm}, che
+esprime i permessi di accesso, viene inizializzato come illustrato in
+sez.~\ref{sec:ipc_sysv_access_control} (si ricordi che in questo caso il
+permesso di scrittura è in realtà permesso di alterare il semaforo), per
+quanto riguarda gli altri campi invece:
\begin{itemize*}
\item il campo \var{sem\_nsems}, che esprime il numero di semafori
nell'insieme, viene inizializzato al valore di \param{nsems}.
-\item il campo \var{sem\_ctime}, che esprime il tempo di creazione
+\item il campo \var{sem\_ctime}, che esprime il tempo di ultimo cambiamento
dell'insieme, viene inizializzato al tempo corrente.
\item il campo \var{sem\_otime}, che esprime il tempo dell'ultima operazione
effettuata, viene inizializzato a zero.
\end{itemize*}
-
-Ciascun semaforo dell'insieme è realizzato come una struttura di tipo
-\var{sem} che ne contiene i dati essenziali, la sua definizione\footnote{si è
- riportata la definizione originaria del kernel 1.0, che contiene la prima
- realizzazione del \textit{SysV IPC} in Linux. In realtà questa struttura
- ormai è ridotta ai soli due primi membri, e gli altri vengono calcolati
- dinamicamente. La si è utilizzata a scopo di esempio, perché indica tutti i
- valori associati ad un semaforo, restituiti dalle funzioni di controllo, e
- citati dalle pagine di manuale.} è riportata in \figref{fig:ipc_sem}. Questa
-struttura, non è accessibile in user space, ma i valori in essa specificati
-possono essere letti in maniera indiretta, attraverso l'uso delle funzioni di
-controllo.
-
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}[labelstep=0]{}
-struct sem {
- short sempid; /* pid of last operation */
- ushort semval; /* current value */
- ushort semncnt; /* num procs awaiting increase in semval */
- ushort semzcnt; /* num procs awaiting semval = 0 */
-};
- \end{lstlisting}
+ \begin{minipage}[c]{.80\textwidth}
+ \includestruct{listati/sem.h}
\end{minipage}
\normalsize
- \caption{La struttura \var{sem}, che contiene i dati di un singolo semaforo.}
+ \caption{La struttura \structd{sem}, che contiene i dati di un singolo
+ semaforo.}
\label{fig:ipc_sem}
\end{figure}
-I dati mantenuti nella struttura, ed elencati in \figref{fig:ipc_sem},
-indicano rispettivamente:
-\begin{description*}
+Ciascun semaforo dell'insieme è realizzato come una struttura di tipo
+\struct{sem} che ne contiene i dati essenziali, la cui definizione è riportata
+in fig.~\ref{fig:ipc_sem}.\footnote{in realtà in fig~\ref{fig:ipc_sem} si è
+ riportata la definizione originaria del kernel 1.0, che contiene la prima
+ realizzazione del \textit{SysV-IPC} in Linux; ormai questa struttura è
+ ridotta ai soli due primi membri, e gli altri vengono calcolati
+ dinamicamente, la si è usata solo a scopo di esempio, perché indica tutti i
+ valori associati ad un semaforo, restituiti dalle funzioni di controllo, e
+ citati dalle pagine di manuale.} Questa struttura non è accessibile
+direttamente dallo \textit{user space}, ma i valori in essa specificati
+possono essere letti in maniera indiretta, attraverso l'uso delle opportune
+funzioni di controllo. I dati mantenuti nella struttura, ed elencati in
+fig.~\ref{fig:ipc_sem}, indicano rispettivamente:
+\begin{basedescript}{\desclabelwidth{2cm}\desclabelstyle{\nextlinelabel}}
\item[\var{semval}] il valore numerico del semaforo.
-\item[\var{sempid}] il \acr{pid} dell'ultimo processo che ha eseguito una
+\item[\var{sempid}] il \ids{PID} dell'ultimo processo che ha eseguito una
operazione sul semaforo.
\item[\var{semncnt}] il numero di processi in attesa che esso venga
incrementato.
\item[\var{semzcnt}] il numero di processi in attesa che esso si annulli.
-\end{description*}
+\end{basedescript}
+
+Come per le code di messaggi anche per gli insiemi di semafori esistono una
+serie di limiti, i cui valori sono associati ad altrettante costanti, che si
+sono riportate in tab.~\ref{tab:ipc_sem_limits}. Alcuni di questi limiti sono
+al solito accessibili e modificabili attraverso \func{sysctl} o scrivendo
+direttamente nel file \sysctlfile{kernel/sem}.
\begin{table}[htb]
\footnotesize
\textbf{Costante} & \textbf{Valore} & \textbf{Significato} \\
\hline
\hline
- \macro{SEMMNI}& 128 & Numero massimo di insiemi di semafori. \\
- \macro{SEMMSL}& 250 & Numero massimo di semafori per insieme.\\
- \macro{SEMMNS}&\macro{SEMMNI}*\macro{SEMMSL}& Numero massimo di semafori
- nel sistema .\\
- \macro{SEMVMX}& 32767 & Massimo valore per un semaforo.\\
- \macro{SEMOPM}& 32 & Massimo numero di operazioni per chiamata a
+ \const{SEMMNI}& 128 & Numero massimo di insiemi di semafori.\\
+ \const{SEMMSL}& 250 & Numero massimo di semafori per insieme.\\
+ \const{SEMMNS}&\const{SEMMNI}*\const{SEMMSL}& Numero massimo di semafori
+ nel sistema.\\
+ \const{SEMVMX}& 32767 & Massimo valore per un semaforo.\\
+ \const{SEMOPM}& 32 & Massimo numero di operazioni per chiamata a
\func{semop}. \\
- \macro{SEMMNU}&\macro{SEMMNS}& Massimo numero di strutture di ripristino.\\
- \macro{SEMUME}&\macro{SEMOPM}& Massimo numero di voci di ripristino.\\
- \macro{SEMAEM}&\macro{SEMVMX}& valore massimo per l'aggiustamento
+ \const{SEMMNU}&\const{SEMMNS}& Massimo numero di strutture di ripristino.\\
+ \const{SEMUME}&\const{SEMOPM}& Massimo numero di voci di ripristino.\\
+ \const{SEMAEM}&\const{SEMVMX}& Valore massimo per l'aggiustamento
all'uscita. \\
\hline
\end{tabular}
\label{tab:ipc_sem_limits}
\end{table}
-Come per le code di messaggi anche per gli insiemi di semafori esistono una
-serie di limiti, i cui valori sono associati ad altrettante costanti, che si
-sono riportate in \tabref{tab:ipc_sem_limits}. Alcuni di questi limiti sono al
-solito accessibili e modificabili attraverso \func{sysctl} o scrivendo
-direttamente nel file \file{/proc/sys/kernel/sem}.
-
-La funzione che permette di effettuare le varie operazioni di controllo sui
-semafori (fra le quali, come accennato, è impropriamente compresa anche la
-loro inizializzazione) è \func{semctl}; il suo prototipo è:
-\begin{functions}
- \headdecl{sys/types.h}
- \headdecl{sys/ipc.h}
- \headdecl{sys/sem.h}
-
- \funcdecl{int semctl(int semid, int semnum, int cmd)}
- \funcdecl{int semctl(int semid, int semnum, int cmd, union semun arg)}
-
- Esegue le operazioni di controllo su un semaforo o un insieme di semafori.
-
- \bodydesc{La funzione restituisce in caso di successo un valore positivo
- quanto usata con tre argomenti ed un valore nullo quando usata con
- quattro. In caso di errore restituisce -1, ed \var{errno} assumerà uno dei
- valori:
- \begin{errlist}
- \item[\macro{EACCES}] Il processo non ha i privilegi per eseguire
- l'operazione richiesta.
- \item[\macro{EIDRM}] L'insieme di semafori è stato cancellato.
- \item[\macro{EPERM}] Si è richiesto \macro{IPC\_SET} o \macro{IPC\_RMID} ma
- il processo non ha privilegi sufficienti ad eseguire l'operazione.
- \item[\macro{ERANGE}] Si è richiesto \macro{SETALL} \macro{SETVAL} ma il
- valore a cui si vuole impostare il semaforo è minore di zero o maggiore
- di \macro{SEMVMX}.
- \end{errlist}
- ed inoltre \macro{EFAULT} ed \macro{EINVAL}.
+
+La funzione di sistema che permette di effettuare le varie operazioni di
+controllo sui semafori fra le quali, come accennato, è impropriamente compresa
+anche la loro inizializzazione, è \funcd{semctl}; il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/ipc.h}
+\fhead{sys/sem.h}
+\fdecl{int semctl(int semid, int semnum, int cmd)}
+\fdecl{int semctl(int semid, int semnum, int cmd, union semun arg)}
+\fdesc{Esegue le operazioni di controllo su un semaforo o un insieme di
+ semafori.}
}
-\end{functions}
-La funzione può avere tre o quattro parametri, a seconda dell'operazione
+{La funzione ritorna in caso di successo un valore positivo quanto usata con
+ tre argomenti ed un valore nullo quando usata con quattro e $-1$ per un
+ errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] i permessi assegnati al semaforo non consentono
+ l'operazione di lettura o scrittura richiesta e non si hanno i privilegi
+ di amministratore.
+ \item[\errcode{EIDRM}] l'insieme di semafori è stato cancellato.
+ \item[\errcode{EPERM}] si è richiesto \const{IPC\_SET} o \const{IPC\_RMID}
+ ma il processo non è né il creatore né il proprietario del semaforo e
+ non ha i privilegi di amministratore.
+ \item[\errcode{ERANGE}] si è richiesto \const{SETALL} \const{SETVAL} ma il
+ valore a cui si vuole impostare il semaforo è minore di zero o maggiore
+ di \const{SEMVMX}.
+ \end{errlist}
+ ed inoltre \errval{EFAULT} ed \errval{EINVAL} nel loro significato
+ generico.}
+\end{funcproto}
+
+La funzione può avere tre o quattro argomenti, a seconda dell'operazione
specificata con \param{cmd}, ed opera o sull'intero insieme specificato da
\param{semid} o sul singolo semaforo di un insieme, specificato da
\param{semnum}.
-Qualora la funzione operi con quattro argomenti \param{arg} è
-un argomento generico, che conterrà un dato diverso a seconda dell'azione
-richiesta; per unificare l'argomento esso deve essere passato come una
-\var{union semun}, la cui definizione, con i possibili valori che può
-assumere, è riportata in \figref{fig:ipc_semun}.
-
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}[labelstep=0]{}
-union semun {
- int val; /* value for SETVAL */
- struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
- unsigned short *array; /* array for GETALL, SETALL */
- /* Linux specific part: */
- struct seminfo *__buf; /* buffer for IPC_INFO */
-};
- \end{lstlisting}
+ \begin{minipage}[c]{0.80\textwidth}
+ \includestruct{listati/semun.h}
\end{minipage}
\normalsize
- \caption{La definizione dei possibili valori di una \var{union semun}, usata
- come quarto argomento della funzione \func{semctl}.}
+ \caption{La definizione dei possibili valori di una \dirct{union}
+ \structd{semun}, usata come quarto argomento della funzione
+ \func{semctl}.}
\label{fig:ipc_semun}
\end{figure}
-Come già accennato sia il comportamento della funzione che il numero di
-parametri con cui deve essere invocata, dipendono dal valore dell'argomento
-\param{cmd}, che specifica l'azione da intraprendere; i valori validi (che
-cioè non causano un errore di \macro{EINVAL}) per questo argomento sono i
-seguenti:
-\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
-\item[\macro{IPC\_STAT}] Legge i dati dell'insieme di semafori, copiando il
- contenuto della relativa struttura \var{semid\_ds} all'indirizzo specificato
- con \var{arg.buf}. Occorre avere il permesso di lettura. L'argomento
+Qualora la funzione operi con quattro argomenti \param{arg} è un argomento
+generico, che conterrà un dato diverso a seconda dell'azione richiesta; per
+unificare detto argomento esso deve essere passato come una unione
+\struct{semun}, la cui definizione, con i possibili valori che può assumere, è
+riportata in fig.~\ref{fig:ipc_semun}.
+
+Nelle versioni più vecchie delle \acr{glibc} questa unione veniva definita in
+\file{sys/sem.h}, ma nelle versioni più recenti questo non avviene più in
+quanto lo standard POSIX.1-2001 richiede che sia sempre definita a cura del
+chiamante. In questa seconda evenienza le \acr{glibc} definiscono però la
+macro \macro{\_SEM\_SEMUN\_UNDEFINED} che può essere usata per controllare la
+situazione.
+
+Come già accennato sia il comportamento della funzione che il numero di
+argomenti con cui deve essere invocata dipendono dal valore dell'argomento
+\param{cmd}, che specifica l'azione da intraprendere. Per questo argomento i
+valori validi, quelli cioè che non causano un errore di \errcode{EINVAL}, sono
+i seguenti:
+\begin{basedescript}{\desclabelwidth{1.6cm}\desclabelstyle{\nextlinelabel}}
+\item[\const{IPC\_STAT}] Legge i dati dell'insieme di semafori, copiandone i
+ valori nella struttura \struct{semid\_ds} posta all'indirizzo specificato
+ con \var{arg.buf}. Occorre avere il permesso di lettura.
+ L'argomento \param{semnum} viene ignorato.
+\item[\const{IPC\_RMID}] Rimuove l'insieme di semafori e le relative strutture
+ dati, con effetto immediato. Tutti i processi che erano bloccati in attesa
+ vengono svegliati, ritornando con un errore di \errcode{EIDRM}. L'\ids{UID}
+ effettivo del processo deve corrispondere o al creatore o al proprietario
+ dell'insieme, o all'amministratore. L'argomento
\param{semnum} viene ignorato.
-\item[\macro{IPC\_RMID}] Rimuove l'insieme di semafori e le relative strutture
- dati, con effetto immediato. Tutti i processi che erano stato di
- \textit{sleep} vengono svegliati, ritornando con un errore di \macro{EIDRM}.
- L'userid effettivo del processo deve corrispondere o al creatore o al
- proprietario dell'insieme, o all'amministratore. L'argomento \param{semnum}
- viene ignorato.
-\item[\macro{IPC\_SET}] Permette di modificare i permessi ed il proprietario
+\item[\const{IPC\_SET}] Permette di modificare i permessi ed il proprietario
dell'insieme. I valori devono essere passati in una struttura
- \var{semid\_ds} puntata da \param{arg.buf} di cui saranno usati soltanto i
- campi \var{sem\_perm.uid}, \var{sem\_perm.gid} e i nove bit meno
- significativi di \var{sem\_perm.mode}. L'userid effettivo del processo deve
- corrispondere o al creatore o al proprietario dell'insieme, o
- all'amministratore. L'argomento \param{semnum} viene ignorato.
-\item[\macro{GETALL}] Restituisce il valore corrente di ciascun semaforo
- dell'insieme (corrispondente al campo \var{semval} di \var{sem}) nel vettore
- indicato da \param{arg.array}. Occorre avere il permesso di lettura.
+ \struct{semid\_ds} puntata da \param{arg.buf} di cui saranno usati soltanto
+ i campi \var{sem\_perm.uid}, \var{sem\_perm.gid} e i nove bit meno
+ significativi di \var{sem\_perm.mode}. La funziona aggiorna anche il campo
+ \var{sem\_ctime}. L'\ids{UID} effettivo del processo deve corrispondere o
+ al creatore o al proprietario dell'insieme, o all'amministratore.
L'argomento \param{semnum} viene ignorato.
-\item[\macro{GETNCNT}] Restituisce come valore di ritorno della funzione il
+\item[\const{GETALL}] Restituisce il valore corrente di ciascun semaforo
+ dell'insieme (corrispondente al campo \var{semval} di \struct{sem}) nel
+ vettore indicato da \param{arg.array}. Occorre avere il permesso di lettura.
+ L'argomento \param{semnum} viene ignorato.
+\item[\const{GETNCNT}] Restituisce come valore di ritorno della funzione il
numero di processi in attesa che il semaforo \param{semnum} dell'insieme
\param{semid} venga incrementato (corrispondente al campo \var{semncnt} di
- \var{sem}); va invocata con tre argomenti. Occorre avere il permesso di
+ \struct{sem}). Va invocata con tre argomenti. Occorre avere il permesso di
lettura.
-\item[\macro{GETPID}] Restituisce come valore di ritorno della funzione il
- \acr{pid} dell'ultimo processo che ha compiuto una operazione sul semaforo
+\item[\const{GETPID}] Restituisce come valore di ritorno della funzione il
+ \ids{PID} dell'ultimo processo che ha compiuto una operazione sul semaforo
\param{semnum} dell'insieme \param{semid} (corrispondente al campo
- \var{sempid} di \var{sem}); va invocata con tre argomenti. Occorre avere il
- permesso di lettura.
-\item[\macro{GETVAL}] Restituisce come valore di ritorno della funzione il il
+ \var{sempid} di \struct{sem}). Va invocata con tre argomenti. Occorre avere
+ il permesso di lettura.
+\item[\const{GETVAL}] Restituisce come valore di ritorno della funzione il il
valore corrente del semaforo \param{semnum} dell'insieme \param{semid}
- (corrispondente al campo \var{semval} di \var{sem}); va invocata con tre
+ (corrispondente al campo \var{semval} di \struct{sem}). Va invocata con tre
argomenti. Occorre avere il permesso di lettura.
-\item[\macro{GETZCNT}] Restituisce come valore di ritorno della funzione il
+\item[\const{GETZCNT}] Restituisce come valore di ritorno della funzione il
numero di processi in attesa che il valore del semaforo \param{semnum}
dell'insieme \param{semid} diventi nullo (corrispondente al campo
- \var{semncnt} di \var{sem}); va invocata con tre argomenti. Occorre avere
- il permesso di lettura.
-\item[\macro{SETALL}] Inizializza il valore di tutti i semafori dell'insieme,
- aggiornando il campo \var{sem\_ctime} di \var{semid\_ds}. I valori devono
+ \var{semncnt} di \struct{sem}). Va invocata con tre argomenti. Occorre
+ avere il permesso di lettura.
+\item[\const{SETALL}] Inizializza il valore di tutti i semafori dell'insieme,
+ aggiornando il campo \var{sem\_ctime} di \struct{semid\_ds}. I valori devono
essere passati nel vettore indicato da \param{arg.array}. Si devono avere i
- privilegi di scrittura sul semaforo. L'argomento \param{semnum} viene
- ignorato.
-\item[\macro{SETVAL}] Inizializza il semaforo \param{semnum} al valore passato
+ privilegi di scrittura. L'argomento \param{semnum} viene ignorato.
+\item[\const{SETVAL}] Inizializza il semaforo \param{semnum} al valore passato
dall'argomento \param{arg.val}, aggiornando il campo \var{sem\_ctime} di
- \var{semid\_ds}. Si devono avere i privilegi di scrittura sul semaforo.
+ \struct{semid\_ds}. Si devono avere i privilegi di scrittura.
\end{basedescript}
+Come per \func{msgctl} esistono tre ulteriori valori, \const{IPC\_INFO},
+\const{SEM\_STAT} e \const{SEM\_INFO}, specifici di Linux e fuori da ogni
+standard, creati specificamente ad uso del comando \cmd{ipcs}. Dato che anche
+questi potranno essere modificati o rimossi, non devono essere utilizzati e
+pertanto non li tratteremo.
+
Quando si imposta il valore di un semaforo (sia che lo si faccia per tutto
-l'insieme con \macro{SETALL}, che per un solo semaforo con \macro{SETVAL}), i
+l'insieme con \const{SETALL}, che per un solo semaforo con \const{SETVAL}), i
processi in attesa su di esso reagiscono di conseguenza al cambiamento di
valore. Inoltre la coda delle operazioni di ripristino viene cancellata per
tutti i semafori il cui valore viene modificato.
\textbf{Operazione} & \textbf{Valore restituito} \\
\hline
\hline
- \macro{GETNCNT}& valore di \var{semncnt}.\\
- \macro{GETPID} & valore di \var{sempid}.\\
- \macro{GETVAL} & valore di \var{semval}.\\
- \macro{GETZCNT}& valore di \var{semzcnt}.\\
+ \const{GETNCNT}& Valore di \var{semncnt}.\\
+ \const{GETPID} & Valore di \var{sempid}.\\
+ \const{GETVAL} & Valore di \var{semval}.\\
+ \const{GETZCNT}& Valore di \var{semzcnt}.\\
\hline
\end{tabular}
\caption{Valori di ritorno della funzione \func{semctl}.}
Il valore di ritorno della funzione in caso di successo dipende
dall'operazione richiesta; per tutte le operazioni che richiedono quattro
-argomenti esso è sempre nullo, per le altre operazioni, elencate in
-\tabref{tab:ipc_semctl_returns} viene invece restituito il valore richiesto,
-corrispondente al campo della struttura \var{sem} indicato nella seconda
+argomenti esso è sempre nullo, per le altre operazioni, elencate in
+tab.~\ref{tab:ipc_semctl_returns} viene invece restituito il valore richiesto,
+corrispondente al campo della struttura \struct{sem} indicato nella seconda
colonna della tabella.
Le operazioni ordinarie sui semafori, come l'acquisizione o il rilascio degli
stessi (in sostanza tutte quelle non comprese nell'uso di \func{semctl})
-vengono effettuate con la funzione \func{semop}, il cui prototipo è:
-\begin{functions}
- \headdecl{sys/types.h}
- \headdecl{sys/ipc.h}
- \headdecl{sys/sem.h}
-
- \funcdecl{int semop(int semid, struct sembuf *sops, unsigned nsops)}
-
- Esegue le operazioni ordinarie su un semaforo o un insieme di semafori.
-
- \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
- errore, nel qual caso \var{errno} assumerà uno dei valori:
- \begin{errlist}
- \item[\macro{EACCES}] Il processo non ha i privilegi per eseguire
- l'operazione richiesta.
- \item[\macro{EIDRM}] L'insieme di semafori è stato cancellato.
- \item[\macro{ENOMEM}] Si è richiesto un \macro{SEM\_UNDO} ma il sistema
- non ha le risorse per allocare la struttura di ripristino.
- \item[\macro{EAGAIN}] Un'operazione comporterebbe il blocco del processo,
- ma si è specificato \macro{IPC\_NOWAIT} in \var{sem\_flg}.
- \item[\macro{EINTR}] La funzione, bloccata in attesa dell'esecuzione
+vengono effettuate con la funzione di sistema \funcd{semop}, il cui prototipo
+è:
+
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/ipc.h}
+\fhead{sys/sem.h}
+\fdecl{int semop(int semid, struct sembuf *sops, unsigned nsops)}
+\fdesc{Esegue operazioni ordinarie su un semaforo o un insieme di semafori.}
+}
+
+{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{E2BIG}] l'argomento \param{nsops} è maggiore del numero
+ massimo di operazioni \const{SEMOPM}.
+ \item[\errcode{EACCES}] il processo non ha i permessi per eseguire
+ l'operazione richiesta e non ha i privilegi di amministratore.
+ \item[\errcode{EAGAIN}] un'operazione comporterebbe il blocco del processo,
+ ma si è specificato \const{IPC\_NOWAIT} in \var{sem\_flg}.
+ \item[\errcode{EFBIG}] il valore del campo \var{sem\_num} è negativo o
+ maggiore o uguale al numero di semafori dell'insieme.
+ \item[\errcode{EIDRM}] l'insieme di semafori è stato cancellato.
+ \item[\errcode{EINTR}] la funzione, bloccata in attesa dell'esecuzione
dell'operazione, viene interrotta da un segnale.
- \item[\macro{E2BIG}] L'argomento \param{nsops} è maggiore del numero
- massimo di operazioni \macro{SEMOPM}.
- \item[\macro{ERANGE}] Per alcune operazioni il valore risultante del
- semaforo viene a superare il limite massimo \macro{SEMVMX}.
+ \item[\errcode{ENOMEM}] si è richiesto un \const{SEM\_UNDO} ma il sistema
+ non ha le risorse per allocare la struttura di ripristino.
+ \item[\errcode{ERANGE}] per alcune operazioni il valore risultante del
+ semaforo viene a superare il limite massimo \const{SEMVMX}.
\end{errlist}
- ed inoltre \macro{EFAULT} ed \macro{EINVAL}.
-}
-\end{functions}
+ ed inoltre \errval{EFAULT} ed \errval{EINVAL} nel loro significato
+ generico.}
+\end{funcproto}
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
+\param{semid} dell'insieme su cui si vuole operare, il numero di operazioni da
effettuare viene specificato con l'argomento \param{nsop}, mentre il loro
contenuto viene passato con un puntatore ad un vettore di strutture
-\var{sembuf} nell'argomento \param{sops}. Le operazioni richieste vengono
-effettivamente eseguite se e soltanto se è possibile effettuarle tutte quante.
+\struct{sembuf} nell'argomento \param{sops}. Le operazioni richieste vengono
+effettivamente eseguite se e soltanto se è possibile effettuarle tutte quante,
+ed in tal caso vengono eseguite nella sequenza passata nel
+vettore \param{sops}.
+
+Con lo standard POSIX.1-2001 è stata introdotta una variante di \func{semop}
+che consente di specificare anche un tempo massimo di attesa. La nuova
+funzione di sistema, disponibile a partire dal kernel 2.4.22 e dalle
+\acr{glibc} 2.3.3, ed utilizzabile solo dopo aver definito la macro
+\macro{\_GNU\_SOURCE}, è \funcd{semtimedop}, ed il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/ipc.h}
+\fhead{sys/sem.h}
+\fdecl{int semtimedop(int semid, struct sembuf *sops, unsigned nsops,
+ struct timespec *timeout)}
+\fdesc{Esegue operazioni ordinarie su un semaforo o un insieme di semafori.}
+}
+
+{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{EAGAIN}] l'operazione comporterebbe il blocco del processo,
+ ma si è specificato \const{IPC\_NOWAIT} in \var{sem\_flg} oppure si è
+ atteso oltre quanto indicato da \param{timeout}.
+ \end{errlist}
+ e gli altri valori già visti per \func{semop}, con lo stesso significato.}
+\end{funcproto}
+
+Rispetto a \func{semop} la funzione consente di specificare un tempo massimo
+di attesa, indicato con una struttura \struct{timespec} (vedi
+fig.~\ref{fig:sys_timespec_struct}), per le operazioni che verrebbero
+bloccate. Alla scadenza di detto tempo la funzione ritorna comunque con un
+errore di \errval{EAGAIN} senza che nessuna delle operazioni richieste venga
+eseguita.
+
+Si tenga presente che la precisione della temporizzazione è comunque limitata
+dalla risoluzione dell'orologio di sistema, per cui il tempo di attesa verrà
+arrotondato per eccesso. In caso si passi un valore \val{NULL}
+per \param{timeout} il comportamento di \func{semtimedop} è identico a quello
+di \func{semop}.
+
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}[labelstep=0]{}
-struct sembuf
-{
- unsigned short int sem_num; /* semaphore number */
- short int sem_op; /* semaphore operation */
- short int sem_flg; /* operation flag */
-};
- \end{lstlisting}
+ \begin{minipage}[c]{.80\textwidth}
+ \includestruct{listati/sembuf.h}
\end{minipage}
\normalsize
- \caption{La struttura \var{sembuf}, usata per le operazioni sui
+ \caption{La struttura \structd{sembuf}, usata per le operazioni sui
semafori.}
\label{fig:ipc_sembuf}
\end{figure}
-Il contenuto di ciascuna operazione deve essere specificato attraverso una
-opportuna struttura \var{sembuf} (la cui definizione è riportata in
-\figref{fig:ipc_sembuf}) che il programma chiamante deve avere cura di
+Come indicato il contenuto di ciascuna operazione deve essere specificato
+attraverso una struttura \struct{sembuf} (la cui definizione è riportata in
+fig.~\ref{fig:ipc_sembuf}) che il programma chiamante deve avere cura di
allocare in un opportuno vettore. La struttura permette di indicare il
-semaforo su cui operare, il tipo di operazione, ed un flag di controllo.
+semaforo su cui operare, il tipo di operazione, ed un flag di controllo.
+
Il campo \var{sem\_num} serve per indicare a quale semaforo dell'insieme fa
-riferimento l'operazione; si ricordi che i semafori sono numerati come in un
-vettore, per cui il primo semaforo corrisponde ad un valore nullo di
-\var{sem\_num}.
-
-Il campo \var{sem\_flg} è un flag, mantenuto come maschera binaria, per il
-quale possono essere impostati i due valori \macro{IPC\_NOWAIT} e
-\macro{SEM\_UNDO}. Impostando \macro{IPC\_NOWAIT} si fa si che, invece di
-bloccarsi (in tutti quei casi in cui l'esecuzione di una operazione richiede
-che il processo vada in stato di \textit{sleep}), \func{semop} ritorni
-immediatamente con un errore di \macro{EAGAIN}. Impostando \macro{SEM\_UNDO}
-si richiede invece che l'operazione venga registrata in modo che il valore del
-semaforo possa essere ripristinato all'uscita del processo.
-
-Infine \var{sem\_op} è il campo che controlla l'operazione che viene eseguita
-e determina il comportamento della chiamata a \func{semop}; tre sono i casi
-possibili:
-\begin{basedescript}{\desclabelwidth{2.0cm}}
-\item[\var{sem\_op}$>0$] In questo caso il valore di \var{sem\_op} viene
- aggiunto al valore corrente di \var{semval}. La funzione ritorna
- immediatamente (con un errore di \macro{ERANGE} qualora si sia superato il
- limite \macro{SEMVMX}) ed il processo non viene bloccato in nessun caso.
- Specificando \macro{SEM\_UNDO} si aggiorna il contatore per il ripristino
- del valore del semaforo. Al processo chiamante è richiesto il privilegio di
- alterazione (scrittura) sull'insieme di semafori.
+riferimento l'operazione. Si ricordi che i semafori sono numerati come gli
+elementi di un vettore, per cui il primo semaforo di un insieme corrisponde ad
+un valore nullo di \var{sem\_num}.
+
+Il campo \var{sem\_flg} è un flag, mantenuto come maschera binaria, per il
+quale possono essere impostati i due valori \const{IPC\_NOWAIT} e
+\const{SEM\_UNDO}. Impostando \const{IPC\_NOWAIT} si fa si che in tutti quei
+casi in cui l'esecuzione di una operazione richiederebbe di porre il processo
+vada nello stato di \textit{sleep}, invece di bloccarsi \func{semop} ritorni
+immediatamente (abortendo così le eventuali operazioni restanti) con un errore
+di \errcode{EAGAIN}. Impostando \const{SEM\_UNDO} si richiede invece che
+l'operazione in questione venga registrata, in modo che il valore del semaforo
+possa essere ripristinato all'uscita del processo.
+
+Infine \var{sem\_op} è il campo che controlla qual'è l'operazione che viene
+eseguita e determina in generale il comportamento della chiamata a
+\func{semop}. I casi possibili per il valore di questo campo sono tre:
+\begin{basedescript}{\desclabelwidth{1.8cm}}
+\item[\var{sem\_op} $>0$] In questo caso il valore viene aggiunto al valore
+ corrente di \var{semval} per il semaforo indicato. Questa operazione non
+ causa mai un blocco del processo, ed eventualmente \func{semop} ritorna
+ immediatamente con un errore di \errcode{ERANGE} qualora si sia superato il
+ limite \const{SEMVMX}. Se l'operazione ha successo si passa immediatamente
+ alla successiva. Specificando \const{SEM\_UNDO} si aggiorna il contatore
+ per il ripristino del valore del semaforo. Al processo chiamante è richiesto
+ il privilegio di alterazione (scrittura) sull'insieme di semafori.
-\item[\var{sem\_op}$=0$] Nel caso \var{semval} sia zero l'esecuzione procede
- immediatamente. Se \var{semval} è diverso da zero il comportamento è
- controllato da \var{sem\_flg}, se è stato impostato \macro{IPC\_NOWAIT} la
- funzione ritorna con un errore di \macro{EAGAIN}, altrimenti viene
- incrementato \var{semzcnt} di uno ed il processo resta in stato di
- \textit{sleep} fintanto che non si ha una delle condizioni seguenti:
+\item[\var{sem\_op} $=0$] Nel caso \var{semval} sia zero l'operazione ha
+ successo immediato, e o si passa alla successiva o \func{semop} ritorna con
+ successo se questa era l'ultima. Se \var{semval} è diverso da zero il
+ comportamento è controllato da \var{sem\_flg}, se è stato impostato
+ \const{IPC\_NOWAIT} \func{semop} ritorna immediatamente abortendo tutte le
+ operazioni con un errore di \errcode{EAGAIN}, altrimenti viene incrementato
+ \var{semzcnt} di uno ed il processo viene bloccato fintanto che non si
+ verifica una delle condizioni seguenti:
\begin{itemize*}
\item \var{semval} diventa zero, nel qual caso \var{semzcnt} viene
- decrementato di uno.
- \item l'insieme di semafori viene rimosso, nel qual caso \func{semop} ritorna
- un errore di \macro{EIDRM}.
+ decrementato di uno, l'operazione ha successo e si passa alla successiva,
+ oppure \func{semop} ritorna con successo se questa era l'ultima.
+ \item l'insieme di semafori viene rimosso, nel qual caso \func{semop}
+ ritorna abortendo tutte le operazioni con un errore di \errcode{EIDRM}.
\item il processo chiamante riceve un segnale, nel qual caso \var{semzcnt}
- viene decrementato di uno e \func{semop} ritorna un errore di
- \macro{EINTR}.
+ viene decrementato di uno e \func{semop} ritorna abortendo tutte le
+ operazioni con un errore di \errcode{EINTR}.
\end{itemize*}
- Al processo chiamante è richiesto il privilegio di lettura dell'insieme dei
- semafori.
+ Al processo chiamante è richiesto soltanto il privilegio di lettura
+ dell'insieme dei semafori.
-\item[\var{sem\_op}$<0$] Nel caso in cui \var{semval} è maggiore o uguale del
- valore assoluto di \var{sem\_op} (se cioè la somma dei due valori resta
- positiva o nulla) i valori vengono sommati e la funzione ritorna
- immediatamente; qualora si sia impostato \macro{SEM\_UNDO} viene anche
+\item[\var{sem\_op} $<0$] Nel caso in cui \var{semval} è maggiore o uguale del
+ valore assoluto di \var{sem\_op} (se cioè la somma dei due valori resta
+ positiva o nulla) i valori vengono sommati e l'operazione ha successo e si
+ passa alla successiva, oppure \func{semop} ritorna con successo se questa
+ era l'ultima. Qualora si sia impostato \const{SEM\_UNDO} viene anche
aggiornato il contatore per il ripristino del valore del semaforo. In caso
- contrario (quando cioè la somma darebbe luogo ad un valore di \var{semval}
- negativo) se si è impostato \macro{IPC\_NOWAIT} la funzione ritorna con un
- errore di \macro{EAGAIN}, altrimenti viene incrementato di uno \var{semncnt}
- ed il processo resta in stato di \textit{sleep} fintanto che non si ha una
- delle condizioni seguenti:
+ contrario (quando cioè la somma darebbe luogo ad un valore di \var{semval}
+ negativo) se si è impostato \const{IPC\_NOWAIT} \func{semop} ritorna
+ immediatamente abortendo tutte le operazioni con un errore di
+ \errcode{EAGAIN}, altrimenti viene incrementato di uno \var{semncnt} ed il
+ processo resta in stato di \textit{sleep} fintanto che non si ha una delle
+ condizioni seguenti:
\begin{itemize*}
\item \var{semval} diventa maggiore o uguale del valore assoluto di
\var{sem\_op}, nel qual caso \var{semncnt} viene decrementato di uno, il
valore di \var{sem\_op} viene sommato a \var{semval}, e se era stato
- impostato \macro{SEM\_UNDO} viene aggiornato il contatore per il
+ impostato \const{SEM\_UNDO} viene aggiornato il contatore per il
ripristino del valore del semaforo.
- \item l'insieme di semafori viene rimosso, nel qual caso \func{semop} ritorna
- un errore di \macro{EIDRM}.
+ \item l'insieme di semafori viene rimosso, nel qual caso \func{semop}
+ ritorna abortendo tutte le operazioni con un errore di \errcode{EIDRM}.
\item il processo chiamante riceve un segnale, nel qual caso \var{semncnt}
- viene decrementato di uno e \func{semop} ritorna un errore di
- \macro{EINTR}.
+ viene decrementato di uno e \func{semop} ritorna abortendo tutte le
+ operazioni con un errore di \errcode{EINTR}.
\end{itemize*}
- Al processo chiamante è richiesto il privilegio di alterazione (scrittura)
+ Al processo chiamante è richiesto il privilegio di alterazione (scrittura)
sull'insieme di semafori.
\end{basedescript}
-In caso di successo della funzione viene aggiornato di \var{sempid} per ogni
-semaforo modificato al valore del \acr{pid} del processo chiamante; inoltre
-vengono pure aggiornati al tempo corrente i campi \var{sem\_otime} e
-\var{sem\_ctime}.
-
-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
-\macro{SEM\_UNDO}. Il meccanismo è implementato tramite una apposita struttura
-\var{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
-avrebbe un doppio ripristino), mentre passano inalterate nell'esecuzione di
-una \func{exec} (altrimenti non si avrebbe ripristino).
-
-Tutto questo però ha un problema di fondo. Per capire di cosa si tratta
-occorre fare riferimento all'implementazione usata in Linux, che è riportata
-in maniera semplificata nello schema di \figref{fig:ipc_sem_schema}. Si è
-presa come riferimento l'architettura usata fino al kernel 2.2.x che è più
-semplice (ed illustrata in dettaglio in \cite{tlk}); nel kernel 2.4.x la
-struttura del \textit{SysV IPC} è stata modificata, ma le definizioni relative
-a queste strutture restano per compatibilità.\footnote{in particolare con le
- vecchie versioni delle librerie del C, come le libc5.}
-
-\begin{figure}[htb]
- \centering \includegraphics[width=15cm]{img/semtruct}
+Qualora si sia usato \func{semtimedop} alle condizioni di errore precedenti si
+aggiunge anche quella di scadenza del tempo di attesa indicato
+con \param{timeout} che farà abortire la funzione, qualora resti bloccata
+troppo a lungo nell'esecuzione delle operazioni richieste, con un errore di
+\errcode{EAGAIN}.
+
+In caso di successo (sia per \func{semop} che per \func{semtimedop}) per ogni
+semaforo modificato verrà aggiornato il campo \var{sempid} al valore del
+\ids{PID} del processo chiamante; inoltre verranno pure aggiornati al tempo
+corrente i campi \var{sem\_otime} e \var{sem\_ctime}.
+
+Dato che, come già accennato in precedenza, in caso di uscita inaspettata i
+semafori possono restare occupati, abbiamo visto come \func{semop} (e
+\func{semtimedop}) permetta di attivare un meccanismo di ripristino attraverso
+l'uso del flag \const{SEM\_UNDO}. Il meccanismo è implementato tramite una
+apposita struttura \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 avrebbe un doppio ripristino), mentre passano
+inalterate nell'esecuzione di una \func{exec} (altrimenti non si avrebbe
+ripristino).
+
+Tutto questo però ha un problema di fondo. Per capire di cosa si tratta
+occorre fare riferimento all'implementazione usata in Linux, che è riportata
+in maniera semplificata nello schema di fig.~\ref{fig:ipc_sem_schema}. Si è
+presa come riferimento l'architettura usata fino al kernel 2.2.x che è più
+semplice (ed illustrata in dettaglio in \cite{tlk}). Nel kernel 2.4.x la
+struttura del \textit{SysV-IPC} è stata modificata, ma le definizioni relative
+a queste strutture restano per compatibilità (in particolare con le vecchie
+versioni delle librerie del C, come le \acr{libc5}).
+
+\begin{figure}[!htb]
+ \centering \includegraphics[width=12cm]{img/semtruct}
\caption{Schema della struttura di un insieme di semafori.}
\label{fig:ipc_sem_schema}
\end{figure}
Alla creazione di un nuovo insieme viene allocata una nuova strutture
-\var{semid\_ds} ed il relativo vettore di strutture \var{sem}. Quando si
+\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 \var{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 \var{semid\_ds}.}. Nella struttura viene memorizzato il riferimento alle
-operazioni richieste (nel campo \var{sops}, che è un puntatore ad una
-struttura \var{sembuf}) e al processo corrente (nel campo \var{sleeper}) poi
-quest'ultimo viene messo stato di attesa e viene invocato lo
-scheduler\index{scheduler} per passare all'esecuzione di un altro processo.
+kernel crea una struttura \kstruct{sem\_queue} che viene aggiunta in fondo
+alla coda di attesa associata a ciascun insieme di semafori, che viene
+referenziata tramite i campi \var{sem\_pending} e \var{sem\_pending\_last} di
+\struct{semid\_ds}. Nella struttura viene memorizzato il riferimento alle
+operazioni richieste (nel campo \var{sops}, che è un puntatore ad una
+struttura \struct{sembuf}) e al processo corrente (nel campo \var{sleeper})
+poi quest'ultimo viene messo stato di attesa e viene invocato lo
+\textit{scheduler} per passare all'esecuzione di un altro processo.
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 \var{sem\_queue} viene rimossa e lo stato del processo associato
+operazioni sospese in precedenza può essere eseguita, nel qual caso la
+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 \macro{SEM\_UNDO} viene mantenuta per ciascun insieme
-di semafori una apposita struttura \var{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.
-
-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
- \var{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 \func{semop}, si pone il
-problema di come eseguire il ripristino dei semafori all'uscita del processo,
-ed in particolare se questo può essere fatto atomicamente. Il punto è cosa
-succede quando una delle operazioni previste per il ripristino non può essere
-eseguita immediatamente perché ad esempio il semaforo è occupato; in tal caso
-infatti, se si pone il processo in stato di \textit{sleep} aspettando la
-disponibilità del semaforo (come faceva l'implementazione originaria) si perde
-l'atomicità dell'operazione. La scelta fatta dal kernel è pertanto quella di
-effettuare subito le operazioni che non prevedono un blocco del processo e di
-ignorare silenziosamente le altre; questo però comporta il fatto che il
-ripristino non è comunque garantito in tutte le occasioni.
+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 \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.
+
+Queste strutture sono mantenute in due liste (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, attraverso il
+campo \var{semundo} di \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
+attraverso diverse chiamate a \func{semop}, si pone il problema di come
+eseguire il ripristino dei semafori all'uscita del processo, ed in particolare
+se questo può essere fatto atomicamente.
+
+Il punto è cosa succede quando una delle operazioni previste per il ripristino
+non può essere eseguita immediatamente perché ad esempio il semaforo è
+occupato; in tal caso infatti, se si pone il processo in stato di
+\textit{sleep} aspettando la disponibilità del semaforo (come faceva
+l'implementazione originaria) si perde l'atomicità dell'operazione. La scelta
+fatta dal kernel è pertanto quella di effettuare subito le operazioni che non
+prevedono un blocco del processo e di ignorare silenziosamente le altre;
+questo però comporta il fatto che il ripristino non è comunque garantito in
+tutte le occasioni.
Come esempio di uso dell'interfaccia dei semafori vediamo come implementare
-con essa dei semplici \textit{mutex} (cioè semafori binari), tutto il codice
-in questione, contenuto nel file \file{wrappers.h} allegato ai sorgenti, è
-riportato in \figref{fig:ipc_mutex_create}. Utilizzeremo l'interfaccia per
+con essa dei semplici \textit{mutex} (cioè semafori binari), tutto il codice
+in questione, contenuto nel file \file{Mutex.c} allegato ai sorgenti, è
+riportato in fig.~\ref{fig:ipc_mutex_create}. Utilizzeremo l'interfaccia per
creare un insieme contenente un singolo semaforo, per il quale poi useremo un
-valore unitario per segnalare la disponibilità della risorsa, ed un valore
-nullo per segnalarne l'indisponibilità.
+valore unitario per segnalare la disponibilità della risorsa, ed un valore
+nullo per segnalarne l'indisponibilità.
-\begin{figure}[!bht]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-/*
- * Function MutexCreate: create a mutex/semaphore
- */
-inline int MutexCreate(key_t ipc_key)
-{
- const union semun semunion={1}; /* semaphore union structure */
- int sem_id, ret;
- sem_id = semget(ipc_key, 1, IPC_CREAT|0666); /* get semaphore ID */
- if (sem_id == -1) { /* if error return code */
- return sem_id;
- }
- ret = semctl(sem_id, 0, SETVAL, semunion); /* init semaphore */
- if (ret == -1) {
- return ret;
- }
- return sem_id;
-}
-/*
- * Function MutexFind: get the semaphore/mutex Id given the IPC key value
- */
-inline int MutexFind(key_t ipc_key)
-{
- return semget(ipc_key,1,0);
-}
-/*
- * Function MutexRead: read the current value of the mutex/semaphore
- */
-inline int MutexRead(int sem_id)
-{
- return semctl(sem_id, 0, GETVAL);
-}
-/*
- * Define sembuf structures to lock and unlock the semaphore
- */
-struct sembuf sem_lock={ /* to lock semaphore */
- 0, /* semaphore number (only one so 0) */
- -1, /* operation (-1 to use resource) */
- SEM_UNDO}; /* flag (set for undo at exit) */
-struct sembuf sem_ulock={ /* to unlock semaphore */
- 0, /* semaphore number (only one so 0) */
- 1, /* operation (1 to release resource) */
- SEM_UNO}; /* flag (in this case 0) */
-/*
- * Function MutexLock: to lock a mutex/semaphore
- */
-inline int MutexLock(int sem_id)
-{
- return semop(sem_id, &sem_lock, 1);
-}
-/*
- * Function MutexUnlock: to unlock a mutex/semaphore
- */
-inline int MutexUnlock(int sem_id)
-{
- return semop(sem_id, &sem_ulock, 1);
-}
- \end{lstlisting}
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/Mutex.c}
\end{minipage}
\normalsize
\caption{Il codice delle funzioni che permettono di creare o recuperare
\label{fig:ipc_mutex_create}
\end{figure}
-La prima funzione (\texttt{\small 1--17}) è \func{MutexCreate} che data una
+La prima funzione (\texttt{\small 2-15}) è \func{MutexCreate} che data una
chiave crea il semaforo usato per il mutex e lo inizializza, restituendone
-l'identificatore. Il primo passo (\texttt{\small 8}) è chiamare \func{semget}
-con \macro{IPC\_CREATE} per creare il semaforo qualora non esista,
+l'identificatore. Il primo passo (\texttt{\small 6}) è chiamare \func{semget}
+con \const{IPC\_CREATE} per creare il semaforo qualora non esista,
assegnandogli i privilegi di lettura e scrittura per tutti. In caso di errore
-(\texttt{\small 9--11}) si ritorna subito il risultato di \func{semget},
-altrimenti (\texttt{\small 12}) si inizializza il semaforo chiamando
-\func{semctl} con il comando \macro{SETVAL}, utilizzando l'unione
-\var{semunion} dichiarata ed avvalorata in precedenza (\texttt{\small 6}) ad 1
-per significare che risorsa è libera. In caso di errore (\texttt{\small
- 13--16}) si restituisce il valore di ritorno di \func{semctl}, altrimenti si
-ritorna l'identificatore del semaforo.
-
-La seconda funzione (\texttt{\small 18--24}) è \func{MutexFind}, che data una
+(\texttt{\small 7-9}) si ritorna subito il risultato di \func{semget},
+altrimenti (\texttt{\small 10}) si inizializza il semaforo chiamando
+\func{semctl} con il comando \const{SETVAL}, utilizzando l'unione
+\struct{semunion} dichiarata ed avvalorata in precedenza (\texttt{\small 4})
+ad 1 per significare che risorsa è libera. In caso di errore (\texttt{\small
+ 11-13}) si restituisce il valore di ritorno di \func{semctl}, altrimenti
+(\texttt{\small 14}) si ritorna l'identificatore del semaforo.
+
+La seconda funzione (\texttt{\small 17-20}) è \func{MutexFind}, che, data una
chiave, restituisce l'identificatore del semaforo ad essa associato. La
-comprensione del suo funzionamento è immediata in quanto è solo un
-\textit{wrapper}\footnote{si chiama così una funzione usata per fare da
+comprensione del suo funzionamento è immediata in quanto essa è soltanto un
+\textit{wrapper}\footnote{si chiama così una funzione usata per fare da
\textsl{involucro} alla chiamata di un altra, usata in genere per
semplificare un'interfaccia (come in questo caso) o per utilizzare con la
stessa funzione diversi substrati (librerie, ecc.) che possono fornire le
- stesse funzionalità.} di \func{semget} per cercare l'identificatore
-associato alla chiave, restituendo direttamente il valore di ritorno della
-funzione.
-
-La terza funzione (\texttt{\small 25--31}) è \func{MutexRead} che, dato
-l'identificatore, restituisce il valore del mutex. Anche in questo caso la
-funzione è un \textit{wrapper} per la chiamata di \func{semctl}, questa volta
-con il comando \macro{GETVAL}, che permette di restituire il valore del
-semaforo.
+ stesse funzionalità.} di una chiamata a \func{semget} per cercare
+l'identificatore associato alla chiave, il valore di ritorno di quest'ultima
+viene passato all'indietro al chiamante.
+
+La terza funzione (\texttt{\small 22-25}) è \func{MutexRead} che, dato un
+identificatore, restituisce il valore del semaforo associato al mutex. Anche
+in questo caso la funzione è un \textit{wrapper} per una chiamata a
+\func{semctl} con il comando \const{GETVAL}, che permette di restituire il
+valore del semaforo.
-La quarta e la quinta funzione (\texttt{\small 43--56}) sono \func{MutexLock},
+La quarta e la quinta funzione (\texttt{\small 36-44}) sono \func{MutexLock},
e \func{MutexUnlock}, che permettono rispettivamente di bloccare e sbloccare
il mutex. Entrambe fanno da wrapper per \func{semop}, utilizzando le due
strutture \var{sem\_lock} e \var{sem\_unlock} definite in precedenza
-(\texttt{\small 32--42}). Si noti come per queste ultime si sia fatto uso
-dell'opzione \macro{SEM\_UNDO} per evitare che il semaforo resti bloccato in
-caso di terminazione imprevista del processo. Si noti infine come, essendo
-tutte le funzioni riportate in \figref{fig:ipc_mutex_create} estremamente
-semplici, se si sono definite tutte come \ctyp{inline}.\footnote{la direttiva
- \func{inline} viene usata per dire al compilatore di non trattare la
- funzione cui essa fa riferimento come una funzione, ma di inserire il codice
- direttamente nel testo del programma. Anche se i compilatori più moderni
- sono in grado di effettuare da soli queste manipolazioni (impostando le
- opportune ottimizzazioni) questa è una tecnica usata per migliorare le
- prestazioni per le funzioni piccole ed usate di frequente, in tal caso
- infatti le istruzioni per creare un nuovo frame nello stack per chiamare la
- funzione costituirebbero una parte rilevante del codice, appesantendo
- inutilmente il programma. Originariamente questa era fatto utilizzando delle
- macro, ma queste hanno tutta una serie di problemi di sintassi nel passaggio
- degli argomenti (si veda ad esempio \cite{PratC} che in questo modo possono
- essere evitati.}
-
-
-Chiamare \func{MutexLock} decrementa il valore del semaforo: se questo è
-libero (ha già valore 1) sarà bloccato (valore nullo), se è bloccato la
-chiamata a \func{semop} si bloccherà fintanto che la risorsa non venga
-rilasciata. Chiamando \func{MutexUnlock} il valore del semaforo sarà
-incrementato di uno, sbloccandolo qualora fosse bloccato. Si noti che occorre
-eseguire sempre prima \func{MutexLock} e poi \func{MutexUnlock}, perché se per
-un qualche errore si esegue più volte quest'ultima il valore del semaforo
-crescerebbe oltre 1, e \func{MutexLock} non avrebbe più l'effetto aspettato
-(bloccare la risorsa quando questa è considerata libera). Si tenga presente
-che usare \func{MutexRead} per controllare il valore dei mutex prima di
-proseguire non servirebbe comunque, dato che l'operazione non sarebbe atomica.
-Vedremo in \secref{sec:ipc_posix_sem} come è possibile ottenere un'interfaccia
-analoga senza questo problemi usando il file locking.
-
-
-
+(\texttt{\small 27-34}). Si noti come per queste ultime si sia fatto uso
+dell'opzione \const{SEM\_UNDO} per evitare che il semaforo resti bloccato in
+caso di terminazione imprevista del processo.
+
+L'ultima funzione (\texttt{\small 46-49}) della serie, è \func{MutexRemove},
+che rimuove il mutex. Anche in questo caso si ha un wrapper per una chiamata a
+\func{semctl} con il comando \const{IPC\_RMID}, che permette di cancellare il
+semaforo; il valore di ritorno di quest'ultima viene passato all'indietro.
+
+Chiamare \func{MutexLock} decrementa il valore del semaforo: se questo è
+libero (ha già valore 1) sarà bloccato (valore nullo), se è bloccato la
+chiamata a \func{semop} si bloccherà fintanto che la risorsa non venga
+rilasciata. Chiamando \func{MutexUnlock} il valore del semaforo sarà
+incrementato di uno, sbloccandolo qualora fosse bloccato.
+
+Si noti che occorre eseguire sempre prima \func{MutexLock} e poi
+\func{MutexUnlock}, perché se per un qualche errore si esegue più volte
+quest'ultima il valore del semaforo crescerebbe oltre 1, e \func{MutexLock}
+non avrebbe più l'effetto aspettato (bloccare la risorsa quando questa è
+considerata libera). Infine si tenga presente che usare \func{MutexRead} per
+controllare il valore dei mutex prima di proseguire in una operazione di
+sblocco non servirebbe comunque, dato che l'operazione non sarebbe atomica.
+Vedremo in sez.~\ref{sec:ipc_lock_file} come sia possibile ottenere
+un'interfaccia analoga a quella appena illustrata, senza incorrere in questi
+problemi, usando il \itindex{file~locking} \textit{file locking}.
\subsection{Memoria condivisa}
\label{sec:ipc_sysv_shm}
-Il terzo oggetto introdotto dal \textit{SysV IPC} è quello dei segmenti di
-memoria condivisa. La funzione che permette di ottenerne uno è \func{shmget},
-ed il suo prototipo è:
-\begin{functions}
- \headdecl{sys/types.h}
- \headdecl{sys/ipc.h}
- \headdecl{sys/shm.h}
-
- \funcdecl{int shmget(key\_t key, int size, int flag)}
-
- Restituisce l'identificatore di una memoria condivisa.
-
- \bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
- in caso di errore, nel qual caso \var{errno} assumerà i valori:
- \begin{errlist}
- \item[\macro{ENOSPC}] Si è superato il limite (\macro{SHMMNI}) sul numero
+Il terzo oggetto introdotto dal \textit{SysV-IPC} è quello dei segmenti di
+memoria condivisa. La funzione di sistema che permette di ottenerne uno è
+\funcd{shmget}, ed il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/ipc.h}
+\fhead{sys/shm.h}
+\fdecl{int shmget(key\_t key, int size, int flag)}
+\fdesc{Ottiene o crea una memoria condivisa.}
+}
+
+{La funzione ritorna l'identificatore (un intero positivo) in caso di successo
+ e $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{ENOSPC}] si è superato il limite (\const{SHMMNI}) sul numero
di segmenti di memoria nel sistema, o cercato di allocare un segmento le
- cui dimensioni fanno superare il limite di sistema (\macro{SHMALL}) per
+ cui dimensioni fanno superare il limite di sistema (\const{SHMALL}) per
la memoria ad essi riservata.
- \item[\macro{EINVAL}] Si è richiesta una dimensione per un nuovo segmento
- maggiore di \macro{SHMMAX} o minore di \macro{SHMMIN}, o se il segmento
- già esiste \param{size} è maggiore delle sue dimensioni.
- \item[\macro{ENOMEM}] Il sistema non ha abbastanza memoria per poter
+ \item[\errcode{EINVAL}] si è richiesta una dimensione per un nuovo segmento
+ maggiore di \const{SHMMAX} o minore di \const{SHMMIN}, o se il segmento
+ già esiste \param{size} è maggiore delle sue dimensioni.
+ \item[\errcode{ENOMEM}] il sistema non ha abbastanza memoria per poter
contenere le strutture per un nuovo segmento di memoria condivisa.
- \end{errlist}
- ed inoltre \macro{EACCES}, \macro{ENOENT}, \macro{EEXIST}, \macro{EIDRM},
- con lo stesso significato che hanno per \func{msgget}.}
-\end{functions}
-
-La funzione, come \func{semget}, è del tutto analoga a \func{msgget}, ed
-identico è l'uso degli argomenti \param{key} e \param{flag} per cui non
-ripeteremo quanto detto al proposito in \secref{sec:ipc_sysv_mq}. L'argomento
-\param{size} specifica invece la dimensione, in byte, del segmento, che viene
-comunque arrotondata al multiplo superiore di \macro{PAGE\_SIZE}.
-
-La memoria condivisa è la forma più veloce di comunicazione fra due processi,
+ \item[\errcode{ENOMEM}] si è specificato \const{IPC\_HUGETLB} ma non si
+ hanno i privilegi di amministratore.
+ \end{errlist}
+ ed inoltre \errval{EACCES}, \errval{ENOENT}, \errval{EEXIST},
+ \errval{EIDRM}, con lo stesso significato che hanno per \func{msgget}.}
+\end{funcproto}
+
+
+La funzione, come \func{semget}, è analoga a \func{msgget}, ed identico è
+l'uso degli argomenti \param{key} e \param{flag} per cui non ripeteremo quanto
+detto al proposito in sez.~\ref{sec:ipc_sysv_mq}. A partire dal kernel 2.6
+però sono stati introdotti degli ulteriori bit di controllo per
+l'argomento \param{flag}, specifici di \func{shmget}, attinenti alle modalità
+di gestione del segmento di memoria condivisa in relazione al sistema della
+memoria virtuale.
+
+Il primo dei due flag è \const{SHM\_HUGETLB} che consente di richiedere la
+creazione del segmento usando una \textit{huge page}, le pagine di memoria di
+grandi dimensioni introdotte con il kernel 2.6 per ottimizzare le prestazioni
+nei sistemi più recenti che hanno grandi quantità di memoria. L'operazione è
+privilegiata e richiede che il processo abbia la \textit{capability}
+\const{CAP\_IPC\_LOCK}. Questa funzionalità è specifica di Linux e non è
+portabile.
+
+Il secondo flag aggiuntivo, introdotto a partire dal kernel 2.6.15, è
+\const{SHM\_NORESERVE}, ed ha lo stesso scopo del flag \const{MAP\_NORESERVE}
+di \func{mmap} (vedi sez.~\ref{sec:file_memory_map}): non vengono riservate
+delle pagine di swap ad uso del meccanismo del \textit{copy on write} per
+mantenere le modifiche fatte sul segmento. Questo significa che caso di
+scrittura sul segmento quando non c'è più memoria disponibile, si avrà
+l'emissione di un \signal{SIGSEGV}.
+
+Infine l'argomento \param{size} specifica la dimensione del segmento di
+memoria condivisa; il valore deve essere specificato in byte, ma verrà
+comunque arrotondato al multiplo superiore di \const{PAGE\_SIZE}. Il valore
+deve essere specificato quando si crea un nuovo segmento di memoria con
+\const{IPC\_CREAT} o \const{IPC\_PRIVATE}, se invece si accede ad un segmento
+di memoria condivisa esistente non può essere maggiore del valore con cui esso
+è stato creato.
+
+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
-copia per trasmettere i dati da un processo all'altro, in quanto ciascuno può
+stessa sezione di memoria. Pertanto non è necessaria nessuna operazione di
+copia per trasmettere i dati da un processo all'altro, in quanto ciascuno può
accedervi direttamente con le normali operazioni di lettura e scrittura dei
dati in memoria.
Ovviamente tutto questo ha un prezzo, ed il problema fondamentale della
-memoria condivisa è la sincronizzazione degli accessi. È evidente infatti che
+memoria condivisa è la sincronizzazione degli accessi. È evidente infatti che
se un processo deve scambiare dei dati con un altro, si deve essere sicuri che
quest'ultimo non acceda al segmento di memoria condivisa prima che il primo
non abbia completato le operazioni di scrittura, inoltre nel corso di una
lettura si deve essere sicuri che i dati restano coerenti e non vengono
sovrascritti da un accesso in scrittura sullo stesso segmento da parte di un
-altro processo; per questo in genere la memoria condivisa viene sempre
+altro processo. Per questo in genere la memoria condivisa viene sempre
utilizzata in abbinamento ad un meccanismo di sincronizzazione, il che, di
norma, significa insieme a dei semafori.
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}[labelstep=0]{}
-struct shmid_ds {
- struct ipc_perm shm_perm; /* operation perms */
- int shm_segsz; /* size of segment (bytes) */
- time_t shm_atime; /* last attach time */
- time_t shm_dtime; /* last detach time */
- time_t shm_ctime; /* last change time */
- unsigned short shm_cpid; /* pid of creator */
- unsigned short shm_lpid; /* pid of last operator */
- short shm_nattch; /* no. of current attaches */
-};
- \end{lstlisting}
+ \begin{minipage}[c]{0.80\textwidth}
+ \includestruct{listati/shmid_ds.h}
\end{minipage}
\normalsize
- \caption{La struttura \var{shmid\_ds}, associata a ciascun segmento di
+ \caption{La struttura \structd{shmid\_ds}, associata a ciascun segmento di
memoria condivisa.}
\label{fig:ipc_shmid_ds}
\end{figure}
-A ciascun segmento di memoria condivisa è associata una struttura
-\var{shmid\_ds}, riportata in \figref{fig:ipc_shmid_ds}. Come nel caso delle
-code di messaggi quando si crea un nuovo segmento di memoria condivisa con
-\func{shmget} questa struttura viene inizializzata, in particolare il campo
-\var{shm\_perm} viene inizializzato come illustrato in
-\secref{sec:ipc_sysv_access_control}, e valgono le considerazioni ivi fatte
+A ciascun segmento di memoria condivisa è associata una struttura
+\struct{shmid\_ds}, riportata in fig.~\ref{fig:ipc_shmid_ds}. Come nel caso
+delle code di messaggi quando si crea un nuovo segmento di memoria condivisa
+con \func{shmget} questa struttura viene inizializzata, in particolare il
+campo \var{shm\_perm} viene inizializzato come illustrato in
+sez.~\ref{sec:ipc_sysv_access_control}, e valgono le considerazioni ivi fatte
relativamente ai permessi di accesso; per quanto riguarda gli altri campi
invece:
\begin{itemize*}
inizializzato al valore di \param{size}.
\item il campo \var{shm\_ctime}, che esprime il tempo di creazione del
segmento, viene inizializzato al tempo corrente.
-\item i campi \var{shm\_atime} e \var{shm\_atime}, che esprimono
- rispettivamente il tempo dell'ultima volta che il segmento è stato
+\item i campi \var{shm\_atime} e \var{shm\_dtime}, che esprimono
+ rispettivamente il tempo dell'ultima volta che il segmento è stato
agganciato o sganciato da un processo, vengono inizializzati a zero.
-\item il campo \var{shm\_lpid}, che esprime il \acr{pid} del processo che ha
+\item il campo \var{shm\_lpid}, che esprime il \ids{PID} del processo che ha
eseguito l'ultima operazione, viene inizializzato a zero.
-\item il campo \var{shm\_cpid}, che esprime il \acr{pid} del processo che ha
- creato il segmento, viene inizializzato al \acr{pid} del processo chiamante.
+\item il campo \var{shm\_cpid}, che esprime il \ids{PID} del processo che ha
+ creato il segmento, viene inizializzato al \ids{PID} del processo chiamante.
\item il campo \var{shm\_nattac}, che esprime il numero di processi agganciati
al segmento viene inizializzato a zero.
\end{itemize*}
Come per le code di messaggi e gli insiemi di semafori, anche per i segmenti
-di memoria condivisa esistono una serie di limiti, i cui valori, riportati in
-\tabref{tab:ipc_shm_limits} sono associati ad altrettante costanti. Alcuni di
-questi limiti sono al solito accessibili e modificabili attraverso
+di memoria condivisa esistono una serie di limiti imposti dal sistema. Alcuni
+di questi limiti sono al solito accessibili e modificabili attraverso
\func{sysctl} o scrivendo direttamente nei rispettivi file di
-\file{/proc/sys/kernel/}.
+\file{/proc/sys/kernel/}.
+
+In tab.~\ref{tab:ipc_shm_limits} si sono riportate le
+costanti simboliche associate a ciascuno di essi, il loro significato, i
+valori preimpostati, e, quando presente, il file in \file{/proc/sys/kernel/}
+che permettono di cambiarne il valore.
+
\begin{table}[htb]
\footnotesize
& \textbf{Significato} \\
\hline
\hline
- \macro{SHMALL}&0x200000&\file{shmall}& Numero massimo di pagine che
- possono essere usate per i segmenti di
- memoria condivisa. \\
- \macro{SHMMAX}&0x2000000&\file{shmmax}& Dimensione massima di un segmento
- di memoria condivisa.\\
- \macro{SHMMNI}&4096&\file{msgmni}& Numero massimo di segmenti di memoria
- condivisa presenti nel kernel.\\
- \macro{SHMMIN}& 1& --- & Dimensione minima di un segmento di
- memoria condivisa. \\
+ \const{SHMALL}& 0x200000&\sysctlrelfile{kernel}{shmall}
+ & Numero massimo di pagine che
+ possono essere usate per i segmenti di
+ memoria condivisa.\\
+ \const{SHMMAX}&0x2000000&\sysctlrelfile{kernel}{shmmax}
+ & Dimensione massima di un segmento di memoria
+ condivisa.\\
+ \const{SHMMNI}& 4096&\sysctlrelfile{kernel}{msgmni}
+ & Numero massimo di segmenti di memoria condivisa
+ presenti nel kernel.\\
+ \const{SHMMIN}& 1& --- & Dimensione minima di un segmento di
+ memoria condivisa.\\
+ \const{SHMLBA}&\const{PAGE\_SIZE}&--- & Limite inferiore per le dimensioni
+ minime di un segmento (deve essere
+ allineato alle dimensioni di una
+ pagina di memoria).\\
+ \const{SHMSEG}& --- & --- & Numero massimo di segmenti di
+ memoria condivisa per ciascun
+ processo (l'implementazione non
+ prevede l'esistenza di questo
+ limite).\\
+
+
\hline
\end{tabular}
\caption{Valori delle costanti associate ai limiti dei segmenti di memoria
\label{tab:ipc_shm_limits}
\end{table}
-Al solito la funzione che permette di effettuare le operazioni di controllo su
-un segmento di memoria condivisa è \func{shmctl}; il suo prototipo è:
-\begin{functions}
- \headdecl{sys/ipc.h}
- \headdecl{sys/shm.h}
-
- \funcdecl{int shmctl(int shmid, int cmd, struct shmid\_ds *buf)}
-
- Esegue le operazioni di controllo su un segmento di memoria condivisa.
-
- \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
- errore, nel qual caso \var{errno} assumerà i valori:
- \begin{errlist}
- \item[\macro{EACCES}] Si è richiesto \macro{IPC\_STAT} ma i permessi non
+Al solito la funzione di sistema che permette di effettuare le operazioni di
+controllo su un segmento di memoria condivisa è \funcd{shmctl}; il suo
+prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/ipc.h}
+\fhead{sys/shm.h}
+\fdecl{int shmctl(int shmid, int cmd, struct shmid\_ds *buf)}
+
+\fdesc{Esegue le operazioni di controllo su un segmento di memoria condivisa.}
+}
+
+{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{EACCES}] si è richiesto \const{IPC\_STAT} ma i permessi non
consentono l'accesso in lettura al segmento.
- \item[\macro{EINVAL}] O \param{shmid} o \param{cmd} hanno valori non
- validi.
- \item[\macro{EIDRM}] L'argomento \param{shmid} fa riferimento ad un
- segmento che è stato cancellato.
- \item[\macro{EPERM}] Si è specificato un comando con \macro{IPC\_SET} o
- \macro{IPC\_RMID} senza i permessi necessari.
- \item[\macro{EOVERFLOW}] L'argomento \param{shmid} fa riferimento ad un
- segmento che è stato cancellato.
- \end{errlist}
- ed inoltre \macro{EFAULT}.}
-\end{functions}
-
-Il comportamento della funzione dipende dal valore del comando passato
-attraverso l'argomento \param{cmd}, i valori possibili sono i seguenti:
+ \item[\errcode{EFAULT}] l'indirizzo specificato con \param{buf} non è
+ valido.
+ \item[\errcode{EIDRM}] l'argomento \param{shmid} fa riferimento ad un
+ segmento che è stato cancellato.
+ \item[\errcode{EINVAL}] o \param{shmid} non è un identificatore valido o
+ \param{cmd} non è un comando valido.
+ \item[\errcode{ENOMEM}] si è richiesto un \textit{memory lock} di
+ dimensioni superiori al massimo consentito.
+ \item[\errcode{EOVERFLOW}] si è tentato il comando \const{IPC\_STAT} ma il
+ valore del \ids{GID} o dell'\ids{UID} è troppo grande per essere
+ memorizzato nella struttura puntata da \param{buf}.
+ \item[\errcode{EPERM}] si è specificato un comando con \const{IPC\_SET} o
+ \const{IPC\_RMID} senza i permessi necessari.
+ \end{errlist}
+}
+\end{funcproto}
+
+Il comando specificato attraverso l'argomento \param{cmd} determina i diversi
+effetti della funzione. Nello standard POSIX.1-2001 i valori che esso può
+assumere, ed il corrispondente comportamento della funzione, sono i seguenti:
+
\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
-\item[\macro{IPC\_STAT}] Legge le informazioni riguardo il segmento di memoria
- condivisa nella struttura \var{shmid\_ds} puntata da \param{buf}. Occorre
- avere il permesso di lettura sulla coda.
-\item[\macro{IPC\_RMID}] Marca il segmento di memoria condivisa per la
- rimozione, questo verrà cancellato effettivamente solo quando l'ultimo
- processo ad esso agganciato si sarà staccato. Questo comando può essere
- eseguito solo da un processo con userid effettivo, corrispondente al
- creatore o al proprietario della coda, o all'amministratore.
-\item[\macro{IPC\_SET}] Permette di modificare i permessi ed il proprietario
+\item[\const{IPC\_STAT}] Legge le informazioni riguardo il segmento di memoria
+ condivisa nella struttura \struct{shmid\_ds} puntata da \param{buf}. Occorre
+ che il processo chiamante abbia il permesso di lettura sulla segmento.
+\item[\const{IPC\_RMID}] Marca il segmento di memoria condivisa per la
+ rimozione, questo verrà cancellato effettivamente solo quando l'ultimo
+ processo ad esso agganciato si sarà staccato. Questo comando può essere
+ eseguito solo da un processo con \ids{UID} effettivo corrispondente o al
+ creatore del segmento, o al proprietario del segmento, o all'amministratore.
+\item[\const{IPC\_SET}] Permette di modificare i permessi ed il proprietario
del segmento. Per modificare i valori di \var{shm\_perm.mode},
\var{shm\_perm.uid} e \var{shm\_perm.gid} occorre essere il proprietario o
- il creatore della coda, oppure l'amministratore. Compiuta l'operazione
+ il creatore del segmento, oppure l'amministratore. Compiuta l'operazione
aggiorna anche il valore del campo \var{shm\_ctime}.
-\item[\macro{SHM\_LOCK}] Abilita il \textit{memory locking}\index{memory
- locking} (vedi \secref{sec:proc_mem_lock}) sul segmento di memoria
- condivisa. Solo l'amministratore può utilizzare questo comando.
-\item[\macro{SHM\_UNLOCK}] Disabilita il \textit{memory locking}. Solo
- l'amministratore può utilizzare questo comando.
\end{basedescript}
-i primi tre comandi sono gli stessi già visti anche per le code ed i semafori,
-gli ultimi due sono delle estensioni previste da Linux.
-
-Per utilizzare i segmenti di memoria condivisa l'interfaccia prevede due
-funzioni, la prima è \func{shmat}, che serve ad agganciare un segmento al
-processo chiamante, in modo che quest'ultimo possa vederlo nel suo spazio di
-indirizzi; il suo prototipo è:
-\begin{functions}
- \headdecl{sys/types.h}
- \headdecl{sys/shm.h}
-
- \funcdecl{void *shmat(int shmid, const void *shmaddr, int shmflg)}
- Aggancia al processo un segmento di memoria condivisa.
-
- \bodydesc{La funzione restituisce l'indirizzo del segmento in caso di
- successo, e -1 in caso di errore, nel qual caso \var{errno} assumerà i
- valori:
- \begin{errlist}
- \item[\macro{EACCES}] Il processo non ha i privilegi per accedere al
- segmento nella modalità richiesta.
- \item[\macro{EINVAL}] Si è specificato un identificatore invalido per
+
+Oltre ai precedenti su Linux sono definiti anche degli ulteriori comandi, che
+consentono di estendere le funzionalità, ovviamente non devono essere usati se
+si ha a cuore la portabilità. Questi comandi aggiuntivi sono:
+
+\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
+\item[\const{SHM\_LOCK}] Abilita il \textit{memory locking} sul segmento di
+ memoria condivisa, impedendo che la memoria usata per il segmento venga
+ salvata su disco dal meccanismo della memoria virtuale. Come illustrato in
+ sez.~\ref{sec:proc_mem_lock} fino al kernel 2.6.9 solo l'amministratore
+ poteva utilizzare questa capacità,\footnote{che richiedeva la
+ \textit{capability} \const{CAP\_IPC\_LOCK}.} a partire dal dal kernel
+ 2.6.10 anche gli utenti normali possono farlo fino al limite massimo
+ determinato da \const{RLIMIT\_MEMLOCK} (vedi
+ sez.~\ref{sec:sys_resource_limit}).
+\item[\const{SHM\_UNLOCK}] Disabilita il \textit{memory locking} sul segmento
+ di memoria condivisa. Fino al kernel 2.6.9 solo l'amministratore poteva
+ utilizzare questo comando in corrispondenza di un segmento da lui bloccato.
+\end{basedescript}
+
+A questi due, come per \func{msgctl} e \func{semctl}, si aggiungono tre
+ulteriori valori, \const{IPC\_INFO}, \const{MSG\_STAT} e \const{MSG\_INFO},
+introdotti ad uso del programma \cmd{ipcs} per ottenere le informazioni
+generali relative alle risorse usate dai segmenti di memoria condivisa. Dato
+che potranno essere modificati o rimossi in favore dell'uso di \texttt{/proc},
+non devono essere usati e non li tratteremo.
+
+L'argomento \param{buf} viene utilizzato solo con i comandi \const{IPC\_STAT}
+e \const{IPC\_SET} nel qual caso esso dovrà puntare ad una struttura
+\struct{shmid\_ds} precedentemente allocata, in cui nel primo caso saranno
+scritti i dati del segmento di memoria restituiti dalla funzione e da cui, nel
+secondo caso, verranno letti i dati da impostare sul segmento.
+
+Una volta che lo si è creato, per utilizzare un segmento di memoria condivisa
+l'interfaccia prevede due funzioni, \funcd{shmat} e \func{shmdt}. La prima di
+queste serve ad agganciare un segmento al processo chiamante, in modo che
+quest'ultimo possa inserirlo nel suo spazio di indirizzi per potervi accedere;
+il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/shm.h}
+\fdecl{void *shmat(int shmid, const void *shmaddr, int shmflg)}
+
+\fdesc{Aggancia un segmento di memoria condivisa al processo chiamante.}
+}
+
+{La funzione ritorna l'indirizzo del segmento in caso di successo e $-1$ (in
+ un cast a \ctyp{void *}) per un errore, nel qual caso \var{errno} assumerà
+ uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] il processo non ha i privilegi per accedere al
+ segmento nella modalità richiesta.
+ \item[\errcode{EINVAL}] si è specificato un identificatore invalido per
\param{shmid}, o un indirizzo non allineato sul confine di una pagina
- per \param{shmaddr}.
- \end{errlist}
- ed inoltre \macro{ENOMEM}.}
-\end{functions}
+ per \param{shmaddr} o il valore \val{NULL} indicando \const{SHM\_REMAP}.
+ \end{errlist}
+ ed inoltre \errval{ENOMEM} nel suo significato generico.
+}
+\end{funcproto}
La funzione inserisce un segmento di memoria condivisa all'interno dello
spazio di indirizzi del processo, in modo che questo possa accedervi
-direttamente, la situazione dopo l'esecuzione di \func{shmat} è illustrata in
-\figref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si
-ricordi quanto illustrato al proposito in \secref{sec:proc_mem_layout}). Si
-tenga presente che la funzione ha successo anche se il segmento è stato
-marcato per la cancellazione.
+direttamente, la situazione dopo l'esecuzione di \func{shmat} è illustrata in
+fig.~\ref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si
+ricordi quanto illustrato al proposito in sez.~\ref{sec:proc_mem_layout}). In
+particolare l'indirizzo finale del segmento dati (quello impostato da
+\func{brk}, vedi sez.~\ref{sec:proc_mem_alloc}) non viene influenzato.
+Si tenga presente infine che la funzione ha successo anche se il segmento è
+stato marcato per la cancellazione.
-\begin{figure}[htb]
- \centering
- \includegraphics[height=10cm]{img/sh_memory_layout}
- \caption{Disposizione dei segmenti di memoria di un processo quando si è
+\begin{figure}[!htb]
+ \centering \includegraphics[height=10cm]{img/sh_memory_layout}
+ \caption{Disposizione dei segmenti di memoria di un processo quando si è
agganciato un segmento di memoria condivisa.}
\label{fig:ipc_shmem_layout}
\end{figure}
-L'argomento \param{shmaddr} specifica a quale indirizzo\footnote{Lo standard
- SVID prevede che l'argomento \param{shmaddr} sia di tipo \ctyp{char *}, così
- come il valore di ritorno della funzione. In Linux è stato così con le
- \acr{libc4} e le \acr{libc5}, con il passaggio alle \acr{glibc} il tipo di
- \param{shmaddr} è divenuto un \ctyp{const void *} e quello del valore di
- ritorno un \ctyp{void *}.} deve essere associato il segmento, se il valore
-specificato è \macro{NULL} è il sistema a scegliere opportunamente un'area di
-memoria libera (questo è il modo più portabile e sicuro di usare la funzione).
-Altrimenti il kernel aggancia il segmento all'indirizzo specificato da
-\param{shmaddr}; questo però può avvenire solo se l'indirizzo coincide con il
-limite di una pagina, cioè se è un multiplo esatto del parametro di sistema
-\macro{SHMLBA}, che in Linux è sempre uguale \macro{PAGE\_SIZE}.
+L'argomento \param{shmaddr} specifica a quale indirizzo\footnote{lo standard
+ SVID prevede che l'argomento \param{shmaddr} sia di tipo \ctyp{char *}, così
+ come il valore di ritorno della funzione; in Linux è stato così con le
+ \acr{libc4} e le \acr{libc5}, con il passaggio alla \acr{glibc} il tipo di
+ \param{shmaddr} è divenuto un \ctyp{const void *} e quello del valore di
+ ritorno un \ctyp{void *} seguendo POSIX.1-2001.} deve essere associato il
+segmento, se il valore specificato è \val{NULL} è il sistema a scegliere
+opportunamente un'area di memoria libera (questo è il modo più portabile e
+sicuro di usare la funzione). Altrimenti il kernel aggancia il segmento
+all'indirizzo specificato da \param{shmaddr}; questo però può avvenire solo se
+l'indirizzo coincide con il limite di una pagina, cioè se è un multiplo esatto
+del parametro di sistema \const{SHMLBA}, che in Linux è sempre uguale
+\const{PAGE\_SIZE}.
+
+Si tenga presente però che quando si usa \val{NULL} come valore di
+\param{shmaddr}, l'indirizzo restituito da \func{shmat} può cambiare da
+processo a processo; pertanto se nell'area di memoria condivisa si salvano
+anche degli indirizzi, si deve avere cura di usare valori relativi (in genere
+riferiti all'indirizzo di partenza del segmento).
L'argomento \param{shmflg} permette di cambiare il comportamento della
-funzione; esso va specificato come maschera binaria, i bit utilizzati sono
-solo due e sono identificati dalle costanti \macro{SHM\_RND} e
-\macro{SHM\_RDONLY}, che vanno combinate con un OR aritmetico. Specificando
-\macro{SHM\_RND} si evita che \func{shmat} ritorni un errore quando
-\param{shmaddr} non è allineato ai confini di una pagina. Si può quindi usare
-un valore qualunque per \param{shmaddr}, e il segmento verrà comunque
-agganciato, ma al più vicino multiplo di \macro{SHMLBA} (il nome della
+funzione; esso va specificato come maschera binaria, i bit utilizzati al
+momento sono sono tre e sono identificati dalle costanti \const{SHM\_RND},
+\const{SHM\_RDONLY} e \const{SHM\_REMAP} che vanno combinate con un OR
+aritmetico.
+
+Specificando \const{SHM\_RND} si evita che \func{shmat} ritorni un errore
+quando \param{shmaddr} non è allineato ai confini di una pagina. Si può quindi
+usare un valore qualunque per \param{shmaddr}, e il segmento verrà comunque
+agganciato, ma al più vicino multiplo di \const{SHMLBA}; il nome della
costante sta infatti per \textit{rounded}, e serve per specificare un
-indirizzo come arrotondamento).
-
-Il secondo bit permette di agganciare il segmento in sola lettura (si ricordi
-che anche le pagine di memoria hanno dei permessi), in tal caso un tentativo
-di scrivere sul segmento comporterà una violazione di accesso con l'emissione
-di un segnale di \macro{SIGSEGV}. Il comportamento usuale di \func{shmat} è
-quello di agganciare il segmento con l'accesso in lettura e scrittura (ed il
-processo deve aver questi permessi in \var{shm\_perm}), non è prevista la
-possibilità di agganciare un segmento in sola scrittura.
-
-In caso di successo la funzione aggiorna anche i seguenti campi di
-\var{shmid\_ds}:
+indirizzo come arrotondamento.
+
+L'uso di \const{SHM\_RDONLY} permette di agganciare il segmento in sola
+lettura (si ricordi che anche le pagine di memoria hanno dei permessi), in tal
+caso un tentativo di scrivere sul segmento comporterà una violazione di
+accesso con l'emissione di un segnale di \signal{SIGSEGV}. Il comportamento
+usuale di \func{shmat} è quello di agganciare il segmento con l'accesso in
+lettura e scrittura (ed il processo deve aver questi permessi in
+\var{shm\_perm}), non è prevista la possibilità di agganciare un segmento in
+sola scrittura.
+
+Infine \const{SHM\_REMAP} è una estensione specifica di Linux (quindi non
+portabile) che indica che la mappatura del segmento deve rimpiazzare ogni
+precedente mappatura esistente nell'intervallo iniziante
+all'indirizzo \param{shmaddr} e di dimensione pari alla lunghezza del
+segmento. In condizioni normali questo tipo di richiesta fallirebbe con un
+errore di \errval{EINVAL}. Ovviamente usando \const{SHM\_REMAP}
+l'argomento \param{shmaddr} non può essere nullo.
+
+In caso di successo la funzione \func{shmat} aggiorna anche i seguenti campi
+della struttura \struct{shmid\_ds}:
\begin{itemize*}
\item il tempo \var{shm\_atime} dell'ultima operazione di aggancio viene
impostato al tempo corrente.
-\item il \acr{pid} \var{shm\_lpid} dell'ultimo processo che ha operato sul
+\item il \ids{PID} \var{shm\_lpid} dell'ultimo processo che ha operato sul
segmento viene impostato a quello del processo corrente.
\item il numero \var{shm\_nattch} di processi agganciati al segmento viene
aumentato di uno.
-\end{itemize*}
+\end{itemize*}
-Come accennato in \secref{sec:proc_fork} un segmento di memoria condivisa
+Come accennato in sez.~\ref{sec:proc_fork} un segmento di memoria condivisa
agganciato ad un processo viene ereditato da un figlio attraverso una
\func{fork}, dato che quest'ultimo riceve una copia dello spazio degli
indirizzi del padre. Invece, dato che attraverso una \func{exec} viene
automaticamente sganciati. Lo stesso avviene all'uscita del processo
attraverso una \func{exit}.
-
-Una volta che un segmento di memoria condivisa non serve più, si può
+Una volta che un segmento di memoria condivisa non serve più, si può
sganciarlo esplicitamente dal processo usando l'altra funzione
-dell'interfaccia, \func{shmdt}, il cui prototipo è:
-\begin{functions}
- \headdecl{sys/types.h}
- \headdecl{sys/shm.h}
+dell'interfaccia, \funcd{shmdt}, il cui prototipo è:
- \funcdecl{int shmdt(const void *shmaddr)}
- Sgancia dal processo un segmento di memoria condivisa.
-
- \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
- errore, la funzione fallisce solo quando non c'è un segmento agganciato
- all'indirizzo \func{shmaddr}, con \var{errno} che assume il valore
- \macro{EINVAL}.}
-\end{functions}
+\begin{funcproto}{
+\fhead{sys/types.h}
+\fhead{sys/shm.h}
+\fdecl{int shmdt(const void *shmaddr)}
+
+\fdesc{Sgancia dal processo un segmento di memoria condivisa.}
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, la funzione
+ fallisce solo quando non c'è un segmento agganciato
+ all'indirizzo \param{shmaddr}, con \var{errno} che assume il valore
+ \errval{EINVAL}.
+}
+\end{funcproto}
La funzione sgancia dallo spazio degli indirizzi del processo un segmento di
memoria condivisa; questo viene identificato con l'indirizzo \param{shmaddr}
restituito dalla precedente chiamata a \func{shmat} con il quale era stato
agganciato al processo.
-Per capire meglio il funzionamento delle funzioni facciamo ancora una volta
-riferimento alle strutture con cui il kernel implementa i segmenti di memoria
-condivisa; uno schema semplificato della struttura è illustrato in
-\figref{fig:ipc_shm_struct}.
+In caso di successo la funzione aggiorna anche i seguenti campi di
+\struct{shmid\_ds}:
+\begin{itemize*}
+\item il tempo \var{shm\_dtime} dell'ultima operazione di sganciamento viene
+ impostato al tempo corrente.
+\item il \ids{PID} \var{shm\_lpid} dell'ultimo processo che ha operato sul
+ segmento viene impostato a quello del processo corrente.
+\item il numero \var{shm\_nattch} di processi agganciati al segmento viene
+ decrementato di uno.
+\end{itemize*}
+inoltre la regione di indirizzi usata per il segmento di memoria condivisa
+viene tolta dallo spazio di indirizzi del processo.
-\begin{figure}[htb]
- \centering
- \includegraphics[width=10cm]{img/shmstruct}
- \caption{Schema dell'implementazione dei segmenti di memoria condivisa in
- Linux.}
- \label{fig:ipc_shm_struct}
+\begin{figure}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/SharedMem.c}
+ \end{minipage}
+ \normalsize
+ \caption{Il codice delle funzioni che permettono di creare, trovare e
+ rimuovere un segmento di memoria condivisa.}
+ \label{fig:ipc_sysv_shm_func}
\end{figure}
+Come esempio di uso di queste funzioni vediamo come implementare una serie di
+funzioni di libreria che ne semplifichino l'uso, automatizzando le operazioni
+più comuni; il codice, contenuto nel file \file{SharedMem.c}, è riportato in
+fig.~\ref{fig:ipc_sysv_shm_func}.
+
+La prima funzione (\texttt{\small 1-16}) è \func{ShmCreate} che, data una
+chiave, crea il segmento di memoria condivisa restituendo il puntatore allo
+stesso. La funzione comincia (\texttt{\small 6}) con il chiamare
+\func{shmget}, usando il flag \const{IPC\_CREATE} per creare il segmento
+qualora non esista, ed assegnandogli i privilegi specificati dall'argomento
+\var{perm} e la dimensione specificata dall'argomento \var{shm\_size}. In
+caso di errore (\texttt{\small 7-9}) si ritorna immediatamente un puntatore
+nullo, altrimenti (\texttt{\small 10}) si prosegue agganciando il segmento di
+memoria condivisa al processo con \func{shmat}. In caso di errore
+(\texttt{\small 11-13}) si restituisce di nuovo un puntatore nullo, infine
+(\texttt{\small 14}) si inizializza con \func{memset} il contenuto del
+segmento al valore costante specificato dall'argomento \var{fill}, e poi si
+ritorna il puntatore al segmento stesso.
+
+La seconda funzione (\texttt{\small 17-31}) è \func{ShmFind}, che, data una
+chiave, restituisce l'indirizzo del segmento ad essa associato. Anzitutto
+(\texttt{\small 22}) si richiede l'identificatore del segmento con
+\func{shmget}, ritornando (\texttt{\small 23-25}) un puntatore nullo in caso
+di errore. Poi si prosegue (\texttt{\small 26}) agganciando il segmento al
+processo con \func{shmat}, restituendo (\texttt{\small 27-29}) di nuovo un
+puntatore nullo in caso di errore, se invece non ci sono errori si restituisce
+il puntatore ottenuto da \func{shmat}.
+
+La terza funzione (\texttt{\small 32-51}) è \func{ShmRemove} che, data la
+chiave ed il puntatore associati al segmento di memoria condivisa, prima lo
+sgancia dal processo e poi lo rimuove. Il primo passo (\texttt{\small 37}) è
+la chiamata a \func{shmdt} per sganciare il segmento, restituendo
+(\texttt{\small 38-39}) un valore -1 in caso di errore. Il passo successivo
+(\texttt{\small 41}) è utilizzare \func{shmget} per ottenere l'identificatore
+associato al segmento data la chiave \var{key}. Al solito si restituisce un
+valore di -1 (\texttt{\small 42-45}) in caso di errore, mentre se tutto va
+bene si conclude restituendo un valore nullo.
+
+Benché la memoria condivisa costituisca il meccanismo di intercomunicazione
+fra processi più veloce, essa non è sempre il più appropriato, dato che, come
+abbiamo visto, si avrà comunque la necessità di una sincronizzazione degli
+accessi. Per questo motivo, quando la comunicazione fra processi è
+sequenziale, altri meccanismi come le \textit{pipe}, le \textit{fifo} o i
+socket, che non necessitano di sincronizzazione esplicita, sono da
+preferire. Essa diventa l'unico meccanismo possibile quando la comunicazione
+non è sequenziale\footnote{come accennato in sez.~\ref{sec:ipc_sysv_mq} per la
+ comunicazione non sequenziale si possono usare le code di messaggi,
+ attraverso l'uso del campo \var{mtype}, ma solo se quest'ultima può essere
+ effettuata in forma di messaggio.} o quando non può avvenire secondo una
+modalità predefinita.
+
+Un esempio classico di uso della memoria condivisa è quello del
+``\textit{monitor}'', in cui viene per scambiare informazioni fra un processo
+server, che vi scrive dei dati di interesse generale che ha ottenuto, e i
+processi client interessati agli stessi dati che così possono leggerli in
+maniera completamente asincrona. Con questo schema di funzionamento da una
+parte si evita che ciascun processo client debba compiere l'operazione,
+potenzialmente onerosa, di ricavare e trattare i dati, e dall'altra si evita
+al processo server di dover gestire l'invio a tutti i client di tutti i dati
+(non potendo il server sapere quali di essi servono effettivamente al singolo
+client).
+
+Nel nostro caso implementeremo un ``\textsl{monitor}'' di una directory: un
+processo si incaricherà di tenere sotto controllo alcuni parametri relativi ad
+una directory (il numero dei file contenuti, la dimensione totale, quante
+directory, link simbolici, file normali, ecc.) che saranno salvati in un
+segmento di memoria condivisa cui altri processi potranno accedere per
+ricavare la parte di informazione che interessa.
+
+In fig.~\ref{fig:ipc_dirmonitor_main} si è riportata la sezione principale del
+corpo del programma server, insieme alle definizioni delle altre funzioni
+usate nel programma e delle variabili globali, omettendo tutto quello che
+riguarda la gestione delle opzioni e la stampa delle istruzioni di uso a
+video; al solito il codice completo si trova con i sorgenti allegati nel file
+\file{DirMonitor.c}.
+
+\begin{figure}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/DirMonitor.c}
+ \end{minipage}
+ \normalsize
+ \caption{Codice della funzione principale del programma \file{DirMonitor.c}.}
+ \label{fig:ipc_dirmonitor_main}
+\end{figure}
+
+Il programma usa delle variabili globali (\texttt{\small 2-14}) per mantenere
+i valori relativi agli oggetti usati per la comunicazione inter-processo; si è
+definita inoltre una apposita struttura \struct{DirProp} che contiene i dati
+relativi alle proprietà che si vogliono mantenere nella memoria condivisa, per
+l'accesso da parte dei client.
+
+Il programma, dopo la sezione, omessa, relativa alla gestione delle opzioni da
+riga di comando (che si limitano alla eventuale stampa di un messaggio di
+aiuto a video ed all'impostazione della durata dell'intervallo con cui viene
+ripetuto il calcolo delle proprietà della directory) controlla (\texttt{\small
+ 20-23}) che sia stato specificato l'argomento necessario contenente il nome
+della directory da tenere sotto controllo, senza il quale esce immediatamente
+con un messaggio di errore.
+
+Poi, per verificare che l'argomento specifichi effettivamente una directory,
+si esegue (\texttt{\small 24-26}) su di esso una \func{chdir}, uscendo
+immediatamente in caso di errore. Questa funzione serve anche per impostare
+la directory di lavoro del programma nella directory da tenere sotto
+controllo, in vista del successivo uso della funzione \func{daemon}. Si noti
+come si è potuta fare questa scelta, nonostante le indicazioni illustrate in
+sez.~\ref{sec:sess_daemon}, per il particolare scopo del programma, che
+necessita comunque di restare all'interno di una directory.
+
+Infine (\texttt{\small 27-29}) si installano i gestori per i vari segnali di
+terminazione che, avendo a che fare con un programma che deve essere eseguito
+come server, sono il solo strumento disponibile per concluderne l'esecuzione.
+
+Il passo successivo (\texttt{\small 30-39}) è quello di creare gli oggetti di
+intercomunicazione necessari. Si inizia costruendo (\texttt{\small 30}) la
+chiave da usare come riferimento con il nome del programma,\footnote{si è
+ usato un riferimento relativo alla home dell'utente, supposto che i sorgenti
+ di GaPiL siano stati installati direttamente in essa; qualora si effettui
+ una installazione diversa si dovrà correggere il programma.} dopo di che si
+richiede (\texttt{\small 31}) la creazione di un segmento di memoria condivisa
+con usando la funzione \func{ShmCreate} illustrata in precedenza (una pagina
+di memoria è sufficiente per i dati che useremo), uscendo (\texttt{\small
+ 32-35}) qualora la creazione ed il successivo agganciamento al processo non
+abbia successo. Con l'indirizzo \var{shmptr} così ottenuto potremo poi
+accedere alla memoria condivisa, che, per come abbiamo lo abbiamo definito,
+sarà vista nella forma data da \struct{DirProp}. Infine (\texttt{\small
+ 36-39}) utilizzando sempre la stessa chiave, si crea, tramite le funzioni
+di interfaccia già descritte in sez.~\ref{sec:ipc_sysv_sem}, anche un mutex,
+che utilizzeremo per regolare l'accesso alla memoria condivisa.
+
+Completata l'inizializzazione e la creazione degli oggetti di
+intercomunicazione il programma entra nel ciclo principale (\texttt{\small
+ 40-49}) dove vengono eseguite indefinitamente le attività di monitoraggio.
+Il primo passo (\texttt{\small 41}) è eseguire \func{daemon} per proseguire
+con l'esecuzione in background come si conviene ad un programma demone; si
+noti che si è mantenuta, usando un valore non nullo del primo argomento, la
+directory di lavoro corrente. Una volta che il programma è andato in
+background l'esecuzione prosegue all'interno di un ciclo infinito
+(\texttt{\small 42-48}).
+
+Si inizia (\texttt{\small 43}) bloccando il mutex con \func{MutexLock} per
+poter accedere alla memoria 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 \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}
+usando una \func{sleep}.
+
+Si noti come per il calcolo dei valori da mantenere nella memoria condivisa si
+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.
+
+\begin{figure}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/ComputeValues.c}
+ \end{minipage}
+ \normalsize
+ \caption{Codice delle funzioni ausiliarie usate da \file{DirMonitor.c}.}
+ \label{fig:ipc_dirmonitor_sub}
+\end{figure}
+
+
+Il codice di quest'ultima è riportato in fig.~\ref{fig:ipc_dirmonitor_sub}.
+Come si vede la funzione (\texttt{\small 2-16}) è molto semplice e si limita a
+chiamare (\texttt{\small 5}) la funzione \func{stat} sul file indicato da
+ciascuna voce, per ottenerne i dati, che poi utilizza per incrementare i vari
+contatori nella memoria condivisa, cui accede grazie alla variabile globale
+\var{shmptr}.
+
+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
+ne sono per ciascun tipo.
+
+In fig.~\ref{fig:ipc_dirmonitor_sub} è riportato anche il codice
+(\texttt{\small 17-23}) del gestore dei segnali di terminazione, usato per
+chiudere il programma. Esso, oltre a provocare l'uscita del programma, si
+incarica anche di cancellare tutti gli oggetti di intercomunicazione non più
+necessari. Per questo anzitutto (\texttt{\small 19}) acquisisce il mutex con
+\func{MutexLock}, per evitare di operare mentre un client sta ancora leggendo
+i dati, dopo di che (\texttt{\small 20}) distacca e rimuove il segmento di
+memoria condivisa usando \func{ShmRemove}. Infine (\texttt{\small 21})
+rimuove il mutex con \func{MutexRemove} ed esce (\texttt{\small 22}).
+
+\begin{figure}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/ReadMonitor.c}
+ \end{minipage}
+ \normalsize
+ \caption{Codice del programma client del monitor delle proprietà di una
+ directory, \file{ReadMonitor.c}.}
+ \label{fig:ipc_dirmonitor_client}
+\end{figure}
+
+Il codice del client usato per leggere le informazioni mantenute nella memoria
+condivisa è riportato in fig.~\ref{fig:ipc_dirmonitor_client}. Al solito si è
+omessa la sezione di gestione delle opzioni e la funzione che stampa a video
+le istruzioni; il codice completo è nei sorgenti allegati, nel file
+\file{ReadMonitor.c}.
+
+Una volta conclusa la gestione delle opzioni a riga di comando il programma
+rigenera (\texttt{\small 7}) con \func{ftok} la stessa chiave usata dal server
+per identificare il segmento di memoria condivisa ed il mutex, poi
+(\texttt{\small 8}) richiede con \func{ShmFind} l'indirizzo della memoria
+condivisa agganciando al contempo il segmento al processo, Infine
+(\texttt{\small 17-20}) con \func{MutexFind} si richiede l'identificatore del
+mutex. Completata l'inizializzazione ed ottenuti i riferimenti agli oggetti
+di intercomunicazione necessari viene eseguito il corpo principale del
+programma (\texttt{\small 21-33}); si comincia (\texttt{\small 22})
+acquisendo il mutex con \func{MutexLock}; qui avviene il blocco del processo
+se la memoria condivisa non è disponibile. Poi (\texttt{\small 23-31}) si
+stampano i vari valori mantenuti nella memoria condivisa attraverso l'uso di
+\var{shmptr}. Infine (\texttt{\small 41}) con \func{MutexUnlock} si rilascia
+il mutex, prima di uscire.
+
+Verifichiamo allora il funzionamento dei nostri programmi; al solito, usando
+le funzioni di libreria occorre definire opportunamente
+\code{LD\_LIBRARY\_PATH}; poi si potrà lanciare il server con:
+\begin{Console}
+[piccardi@gont sources]$ \textbf{./dirmonitor ./}
+\end{Console}
+%$
+ed avendo usato \func{daemon} il comando ritornerà immediatamente. Una volta
+che il server è in esecuzione, possiamo passare ad invocare il client per
+verificarne i risultati, in tal caso otterremo:
+\begin{Console}
+[piccardi@gont sources]$ \textbf{./readmon}
+Ci sono 68 file dati
+Ci sono 3 directory
+Ci sono 0 link
+Ci sono 0 fifo
+Ci sono 0 socket
+Ci sono 0 device a caratteri
+Ci sono 0 device a blocchi
+Totale 71 file, per 489831 byte
+\end{Console}
+%$
+ed un rapido calcolo (ad esempio con \code{ls -a | wc} per contare i file) ci
+permette di verificare che il totale dei file è giusto. Un controllo con
+\cmd{ipcs} ci permette inoltre di verificare la presenza di un segmento di
+memoria condivisa e di un semaforo:
+\begin{Console}
+[piccardi@gont sources]$ \textbf{ipcs}
+------ Shared Memory Segments --------
+key shmid owner perms bytes nattch status
+0xffffffff 54067205 piccardi 666 4096 1
+
+------ Semaphore Arrays --------
+key semid owner perms nsems
+0xffffffff 229376 piccardi 666 1
+
+------ Message Queues --------
+key msqid owner perms used-bytes messages
+\end{Console}
+%$
+
+Se a questo punto aggiungiamo un file, ad esempio con \code{touch prova},
+potremo verificare che, passati nel peggiore dei casi almeno 10 secondi (o
+l'eventuale altro intervallo impostato per la rilettura dei dati) avremo:
+\begin{Console}
+[piccardi@gont sources]$ \textbf{./readmon}
+Ci sono 69 file dati
+Ci sono 3 directory
+Ci sono 0 link
+Ci sono 0 fifo
+Ci sono 0 socket
+Ci sono 0 device a caratteri
+Ci sono 0 device a blocchi
+Totale 72 file, per 489887 byte
+\end{Console}
+%$
+
+A questo punto possiamo far uscire il server inviandogli un segnale di
+\signal{SIGTERM} con il comando \code{killall dirmonitor}, a questo punto
+ripetendo la lettura, otterremo un errore:
+\begin{Console}
+[piccardi@gont sources]$ \textbf{./readmon}
+Cannot find shared memory: No such file or directory
+\end{Console}
+%$
+e inoltre potremo anche verificare che anche gli oggetti di intercomunicazione
+visti in precedenza sono stati regolarmente cancellati:
+\begin{Console}
+[piccardi@gont sources]$ \textbf{ipcs}
+------ Shared Memory Segments --------
+key shmid owner perms bytes nattch status
+
+------ Semaphore Arrays --------
+key semid owner perms nsems
+
+------ Message Queues --------
+key msqid owner perms used-bytes messages
+\end{Console}
+%$
+
+
+%% Per capire meglio il funzionamento delle funzioni facciamo ancora una volta
+%% riferimento alle strutture con cui il kernel implementa i segmenti di memoria
+%% condivisa; uno schema semplificato della struttura è illustrato in
+%% fig.~\ref{fig:ipc_shm_struct}.
+
+%% \begin{figure}[!htb]
+%% \centering
+%% \includegraphics[width=10cm]{img/shmstruct}
+%% \caption{Schema dell'implementazione dei segmenti di memoria condivisa in
+%% Linux.}
+%% \label{fig:ipc_shm_struct}
+%% \end{figure}
+
\section{Tecniche alternative}
\label{sec:ipc_alternatives}
-Come abbiamo visto in \secref{sec:ipc_sysv_generic} il \textit{SysV IPC}
+Come abbiamo detto in sez.~\ref{sec:ipc_sysv_generic}, e ripreso nella
+descrizione dei singoli oggetti che ne fan parte, il \textit{SysV-IPC}
presenta numerosi problemi; in \cite{APUE}\footnote{in particolare nel
- capitolo 14.} Stevens effettua una accurata analisi (alcuni dei concetti
-sono già stati accennati in precedenza) ed elenca alcune possibili
+ capitolo 14.} Stevens ne effettua una accurata analisi (alcuni dei concetti
+sono già stati accennati in precedenza) ed elenca alcune possibili tecniche
alternative, che vogliamo riprendere in questa sezione.
\label{sec:ipc_mq_alternative}
Le code di messaggi sono probabilmente il meno usato degli oggetti del
-\textit{SysV IPC}; esse infatti nacquero principalmente come meccanismo di
-comunicazione bidirezionale quando ancora le pipe erano unidirezionali; con la
-disponibilità di \func{socketpair} (vedi \secref{sec:ipc_socketpair}) si può
-ottenere lo stesso risultato senza incorrere nelle complicazioni introdotte
-dal \textit{SysV IPC}.
-
-In realtà, grazie alla presenza del campo \var{mtype}, le code di messaggi
+\textit{SysV-IPC}; esse infatti nacquero principalmente come meccanismo di
+comunicazione bidirezionale quando ancora le \textit{pipe} erano
+unidirezionali; con la disponibilità di \func{socketpair} (vedi
+sez.~\ref{sec:ipc_socketpair}) o utilizzando una coppia di \textit{pipe}, si
+può ottenere questo risultato senza incorrere nelle complicazioni introdotte
+dal \textit{SysV-IPC}.
+
+In realtà, grazie alla presenza del campo \var{mtype}, le code di messaggi
hanno delle caratteristiche ulteriori, consentendo una classificazione dei
messaggi ed un accesso non rigidamente sequenziale; due caratteristiche che
-sono impossibili da ottenere con le pipe e i socket di \func{socketpair}. A
-queste esigenze però si può comunque ovviare in maniera diversa con un uso
-combinato della memoria condivisa e dei meccanismi di sincronizzazione, per
-cui alla fine l'uso delle code di messaggi classiche è poco diffuso.
+sono impossibili da ottenere con le \textit{pipe} e i socket di
+\func{socketpair}. A queste esigenze però si può comunque ovviare in maniera
+diversa con un uso combinato della memoria condivisa e dei meccanismi di
+sincronizzazione, per cui alla fine l'uso delle code di messaggi classiche è
+relativamente poco diffuso.
+% TODO: trattare qui, se non si trova posto migliore, copy_from_process e
+% copy_to_process, introdotte con il kernel 3.2. Vedi
+% http://lwn.net/Articles/405346/ e
+% http://ozlabs.org/~cyeoh/cma/process_vm_readv.txt
-\subsection{La sincronizzazione con il \textit{file locking}}
+\subsection{I \textsl{file di lock}}
\label{sec:ipc_file_lock}
-Come illustrato in \secref{sec:ipc_sysv_sem} i semafori del \textit{SysV IPC}
+\index{file!di~lock|(}
+
+Come illustrato in sez.~\ref{sec:ipc_sysv_sem} i semafori del \textit{SysV-IPC}
presentano una interfaccia inutilmente complessa e con alcuni difetti
strutturali, per questo quando si ha una semplice esigenza di sincronizzazione
per la quale basterebbe un semaforo binario (quello che abbiamo definito come
-\textit{mutex}), per indicare la disponibilità o meno di una risorsa, senza la
-necessità di un contatore come i semafori, si possono utilizzare metodi
+\textit{mutex}), per indicare la disponibilità o meno di una risorsa, senza la
+necessità di un contatore come i semafori, si possono utilizzare metodi
alternativi.
-La prima possibilità, utilizzata fin dalle origini di Unix, è quella di usare
-dei \textsl{file di lock}\index{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
-\secref{sec:file_open}) 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 race condition.} che essa
-ritorni un errore quando usata con i flag di \macro{O\_CREAT} e
-\macro{O\_EXCL}. In tal modo la creazione di un file di lock può essere
-eseguita atomicamente, il processo che crea il file con successo si può
-considerare come titolare del lock (e della risorsa ad esso associata) mentre
-il rilascio si può eseguire con una chiamata ad
-\func{unlink}.\footnote{abbiamo già accennato in \secref{sec:file_open} che
- questa tecnica può non funzionare se il filesystem su cui si va ad operare è
- su NFS; in tal caso si può adottare una tecnica alternativa che prevede
- l'uso di \func{link} per creare come file di lock un hard link ad un file
- esistente; se il link esiste già e la funzione fallisce, significa che la
- risorsa è bloccata e potrà essere sbloccata solo con un \func{unlink},
- altrimenti il link è creato ed il lock acquisito; il controllo e l'eventuale
- acquisizione sono atomici; il difetto di questa soluzione è che funziona
- solo se si opera all'interno di uno stesso filesystem.}
-
-L'uso di un file di lock presenta però parecchi problemi, che non lo rendono
-una alternativa praticabile per la sincronizzazione: anzitutto anche in questo
-caso in caso di terminazione imprevista del processo lascia allocata la
-risorsa (il file di lock) e questa deve essere sempre cancellata
-esplicitamente. Inoltre il controllo della disponibilità può essere fatto
-solo con una tecnica di \textit{polling}\index{polling}, che è molto
-inefficiente.
-
-La tecnica può comunque essere usata con successo quando l'esigenza è solo
-quella di segnalare l'occupazione di una risorsa, senza necessità di attendere
-che questa si liberi; ad esempio la si usa spesso per evitare interferenze
-sull'uso delle porte seriali da parte di più programmi: qualora si trovi un
-file di lock il programma che cerca di accedere alla seriale si limita a
-segnalare che la risorsa non è disponibile; sempre in \file{wrapper.h} si sono
-predisposte due funzioni, \func{LockFile} e \func{UnlockFile}, da utilizzare
-allo scopo.
+La prima possibilità, utilizzata fin dalle origini di Unix, è quella di usare
+dei \textsl{file di lock} (per i quali è stata anche riservata una opportuna
+directory, \file{/var/lock}, nella standardizzazione del \textit{Filesystem
+ Hierarchy Standard}). Per questo si usa la caratteristica della funzione
+\func{open} (illustrata in 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 \textit{race condition}.} che essa ritorni un errore
+quando usata con i flag di \const{O\_CREAT} e \const{O\_EXCL}. In tal modo la
+creazione di un \textsl{file di lock} può essere eseguita atomicamente, il
+processo che crea il file con successo si può considerare come titolare del
+lock (e della risorsa ad esso associata) mentre il rilascio si può eseguire
+con una chiamata ad \func{unlink}.
+
+Un esempio dell'uso di questa funzione è mostrato dalle funzioni
+\func{LockFile} ed \func{UnlockFile} riportate in fig.~\ref{fig:ipc_file_lock}
+(sono contenute in \file{LockFile.c}, un altro dei sorgenti allegati alla
+guida) che permettono rispettivamente di creare e rimuovere un \textsl{file di
+ lock}. Come si può notare entrambe le funzioni sono elementari; la prima
+(\texttt{\small 4-10}) si limita ad aprire il file di lock (\texttt{\small
+ 9}) nella modalità descritta, mentre la seconda (\texttt{\small 11-17}) lo
+cancella con \func{unlink}.
+
+\begin{figure}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/LockFile.c}
+ \end{minipage}
+ \normalsize
+ \caption{Il codice delle funzioni \func{LockFile} e \func{UnlockFile} che
+ permettono di creare e rimuovere un \textsl{file di lock}.}
+ \label{fig:ipc_file_lock}
+\end{figure}
+
+Uno dei limiti di questa tecnica è che, come abbiamo già accennato in
+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
+\func{link} per creare come \textsl{file di lock} un hard link ad un file
+esistente; se il link esiste già e la funzione fallisce, significa che la
+risorsa è bloccata e potrà essere sbloccata solo con un \func{unlink},
+altrimenti il link è creato ed il lock acquisito; il controllo e l'eventuale
+acquisizione sono atomici; la soluzione funziona anche su NFS, ma ha un altro
+difetto è che è quello di poterla usare solo se si opera all'interno di uno
+stesso filesystem.
+
+In generale comunque l'uso di un \textsl{file di lock} presenta parecchi
+problemi che non lo rendono una alternativa praticabile per la
+sincronizzazione: anzitutto in caso di terminazione imprevista del processo,
+si lascia allocata la risorsa (il \textsl{file di lock}) e questa deve essere
+sempre cancellata esplicitamente. Inoltre il controllo della disponibilità
+può essere eseguito solo con una tecnica di \itindex{polling}
+\textit{polling}, ed è quindi molto inefficiente.
+
+La tecnica dei file di lock ha comunque una sua utilità, e può essere usata
+con successo quando l'esigenza è solo quella di segnalare l'occupazione di una
+risorsa, senza necessità di attendere che questa si liberi; ad esempio la si
+usa spesso per evitare interferenze sull'uso delle porte seriali da parte di
+più programmi: qualora si trovi un file di lock il programma che cerca di
+accedere alla seriale si limita a segnalare che la risorsa non è disponibile.
+
+\index{file!di~lock|)}
+
+
+\subsection{La sincronizzazione con il \textit{file locking}}
+\label{sec:ipc_lock_file}
Dato che i file di lock presentano gli inconvenienti illustrati in precedenza,
-la tecnica alternativa più comune è quella di fare ricorso al \textit{file
- locking} (trattato in \secref{sec:file_locking}) usando \func{fcntl} su un
-file creato per l'occasione per ottenere un write lock. In questo modo potremo
-usare il lock come un \textit{mutex}: per bloccare la risorsa basterà
-acquisire il lock, per sbloccarla basterà rilasciare il lock; una richiesta
-fatta con un write lock metterà automaticamente il processo in stato di
-attesa, senza necessità di ricorrere al \textit{polling}\index{polling} per
-determinare la disponibilità della risorsa, e al rilascio della stessa da
-parte del processo che la occupava si otterrà il nuovo lock atomicamente.
+la tecnica alternativa di sincronizzazione più comune è quella di fare ricorso
+al \itindex{file~locking} \textit{file locking} (trattato in
+sez.~\ref{sec:file_locking}) usando \func{fcntl} su un file creato per
+l'occasione per ottenere un write lock. In questo modo potremo usare il lock
+come un \textit{mutex}: per bloccare la risorsa basterà acquisire il lock, per
+sbloccarla basterà rilasciare il lock. Una richiesta fatta con un write lock
+metterà automaticamente il processo in stato di attesa, senza necessità di
+ricorrere al \itindex{polling} \textit{polling} per determinare la
+disponibilità della risorsa, e al rilascio della stessa da parte del processo
+che la occupava si otterrà il nuovo lock atomicamente.
Questo approccio presenta il notevole vantaggio che alla terminazione di un
processo tutti i lock acquisiti vengono rilasciati automaticamente (alla
-chiusura dei relativi file) e non ci si deve preoccupare di niente, inoltre
-non consuma risorse permanentemente allocate nel sistema, lo svantaggio è che
-dovendo fare ricorso a delle operazioni sul filesystem esso è in genere
-leggermente più lento.
+chiusura dei relativi file) e non ci si deve preoccupare di niente; inoltre
+non consuma risorse permanentemente allocate nel sistema. Lo svantaggio è che,
+dovendo fare ricorso a delle operazioni sul filesystem, esso è in genere
+leggermente più lento.
-\begin{figure}[!bht]
+\begin{figure}[!htbp]
\footnotesize \centering
- \begin{minipage}[c]{15cm}
- \begin{lstlisting}{}
-
- \end{lstlisting}
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/MutexLocking.c}
\end{minipage}
\normalsize
- \caption{Il codice delle funzioni che permettono di creare un
- \textit{mutex} utilizzando il file locking.}
+ \caption{Il codice delle funzioni che permettono per la gestione dei
+ \textit{mutex} con il \itindex{file~locking} \textit{file locking}.}
\label{fig:ipc_flock_mutex}
\end{figure}
-Il codice per implementare un mutex utilizzando il file locking è riportato in
-\figref{fig:ipc_flock_mutex}; come nel precedente caso dei mutex implementato
-con i semafori le funzioni sono tre
-
-
+Il codice delle varie funzioni usate per implementare un mutex utilizzando il
+\textit{file locking} \itindex{file~locking} è riportato in
+fig.~\ref{fig:ipc_flock_mutex}; si è mantenuta volutamente una struttura
+analoga alle precedenti funzioni che usano i semafori, anche se le due
+interfacce non possono essere completamente equivalenti, specie per quanto
+riguarda la rimozione del mutex.
+
+La prima funzione (\texttt{\small 1-5}) è \func{CreateMutex}, e serve a
+creare il mutex; la funzione è estremamente semplice, e si limita
+(\texttt{\small 4}) a creare, con una opportuna chiamata ad \func{open}, il
+file che sarà usato per il successivo \textit{file locking}, assicurandosi che
+non esista già (nel qual caso segnala un errore); poi restituisce il file
+descriptor che sarà usato dalle altre funzioni per acquisire e rilasciare il
+mutex.
+
+La seconda funzione (\texttt{\small 6-10}) è \func{FindMutex}, che, come la
+precedente, è stata definita per mantenere una analogia con la corrispondente
+funzione basata sui semafori. Anch'essa si limita (\texttt{\small 9}) ad
+aprire il file da usare per il \itindex{file~locking} \textit{file locking},
+solo che in questo caso le opzioni di \func{open} sono tali che il file in
+questione deve esistere di già.
+
+La terza funzione (\texttt{\small 11-22}) è \func{LockMutex} e serve per
+acquisire il mutex. La funzione definisce (\texttt{\small 14}) e inizializza
+(\texttt{\small 16-19}) la struttura \var{lock} da usare per acquisire un
+write lock sul file, che poi (\texttt{\small 21}) viene richiesto con
+\func{fcntl}, restituendo il valore di ritorno di quest'ultima. Se il file è
+libero il lock viene acquisito e la funzione ritorna immediatamente;
+altrimenti \func{fcntl} si bloccherà (si noti che la si è chiamata con
+\const{F\_SETLKW}) fino al rilascio del lock.
+
+La quarta funzione (\texttt{\small 24-34}) è \func{UnlockMutex} e serve a
+rilasciare il mutex. La funzione è analoga alla precedente, solo che in questo
+caso si inizializza (\texttt{\small 28-31}) la struttura \var{lock} per il
+rilascio del lock, che viene effettuato (\texttt{\small 33}) con la opportuna
+chiamata a \func{fcntl}. Avendo usato il \itindex{file~locking} \textit{file
+ locking} in semantica POSIX (si riveda quanto detto
+sez.~\ref{sec:file_posix_lock}) solo il processo che ha precedentemente
+eseguito il lock può sbloccare il mutex.
+
+La quinta funzione (\texttt{\small 36-39}) è \func{RemoveMutex} e serve a
+cancellare il mutex. Anche questa funzione è stata definita per mantenere una
+analogia con le funzioni basate sui semafori, e si limita a cancellare
+(\texttt{\small 38}) il file con una chiamata ad \func{unlink}. Si noti che in
+questo caso la funzione non ha effetto sui mutex già ottenuti con precedenti
+chiamate a \func{FindMutex} o \func{CreateMutex}, che continueranno ad essere
+disponibili fintanto che i relativi file descriptor restano aperti. Pertanto
+per rilasciare un mutex occorrerà prima chiamare \func{UnlockMutex} oppure
+chiudere il file usato per il lock.
+
+La sesta funzione (\texttt{\small 41-55}) è \func{ReadMutex} e serve a
+leggere lo stato del mutex. In questo caso si prepara (\texttt{\small 46-49})
+la solita struttura \var{lock} come l'acquisizione del lock, ma si effettua
+(\texttt{\small 51}) la chiamata a \func{fcntl} usando il comando
+\const{F\_GETLK} per ottenere lo stato del lock, e si restituisce
+(\texttt{\small 52}) il valore di ritorno in caso di errore, ed il valore del
+campo \var{l\_type} (che descrive lo stato del lock) altrimenti
+(\texttt{\small 54}). Per questo motivo la funzione restituirà -1 in caso di
+errore e uno dei due valori \const{F\_UNLCK} o \const{F\_WRLCK}\footnote{non
+ si dovrebbe mai avere il terzo valore possibile, \const{F\_RDLCK}, dato che
+ la nostra interfaccia usa solo i write lock. Però è sempre possibile che
+ siano richiesti altri lock sul file al di fuori dell'interfaccia, nel qual
+ caso si potranno avere, ovviamente, interferenze indesiderate.} in caso di
+successo, ad indicare che il mutex è, rispettivamente, libero o occupato.
+
+Basandosi sulla semantica dei file lock POSIX valgono tutte le considerazioni
+relative al comportamento di questi ultimi fatte in
+sez.~\ref{sec:file_posix_lock}; questo significa ad esempio che, al contrario
+di quanto avveniva con l'interfaccia basata sui semafori, chiamate multiple a
+\func{UnlockMutex} o \func{LockMutex} non si cumulano e non danno perciò
+nessun inconveniente.
\subsection{Il \textit{memory mapping} anonimo}
\label{sec:ipc_mmap_anonymous}
-Abbiamo visto in \secref{sec:file_memory_map} come sia possibile mappare il
-contenuto di un file nella memoria di un processo. Una della opzioni possibili
-utilizzabili con Linux è quella del \textit{memory mapping}
-anonimo\footnote{in altri sistemi una funzionalità simile a questa viene
- implementata mappando il file speciale \file{/dev/zero}.}, in tal caso
-infatti
-
-
-\section{La comunicazione fra processi di POSIX}
+\itindbeg{memory~mapping} Abbiamo già visto che quando i processi sono
+\textsl{correlati}, se cioè hanno almeno un progenitore comune, l'uso delle
+\textit{pipe} può costituire una valida alternativa alle code di messaggi;
+nella stessa situazione si può evitare l'uso di una memoria condivisa facendo
+ricorso al cosiddetto \textit{memory mapping} anonimo.
+
+In sez.~\ref{sec:file_memory_map} abbiamo visto come sia possibile mappare il
+contenuto di un file nella memoria di un processo, e che, quando viene usato
+il flag \const{MAP\_SHARED}, le modifiche effettuate al contenuto del file
+vengono viste da tutti i processi che lo hanno mappato. Utilizzare questa
+tecnica per creare una memoria condivisa fra processi diversi è estremamente
+inefficiente, in quanto occorre passare attraverso il disco.
+
+Però abbiamo visto anche che se si esegue la mappatura con il flag
+\const{MAP\_ANONYMOUS} la regione mappata non viene associata a nessun file,
+anche se quanto scritto rimane in memoria e può essere riletto; allora, dato
+che un processo figlio mantiene nel suo spazio degli indirizzi anche le
+regioni mappate, esso sarà anche in grado di accedere a quanto in esse è
+contenuto.
+
+In questo modo diventa possibile creare una memoria condivisa fra processi
+diversi, purché questi abbiano almeno un progenitore comune che ha effettuato
+il \textit{memory mapping} anonimo.\footnote{nei sistemi derivati da SysV una
+ funzionalità simile a questa viene implementata mappando il file speciale
+ \file{/dev/zero}. In tal caso i valori scritti nella regione mappata non
+ vengono ignorati (come accade qualora si scriva direttamente sul file), ma
+ restano in memoria e possono essere riletti secondo le stesse modalità usate
+ nel \textit{memory mapping} anonimo.} Vedremo come utilizzare questa tecnica
+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: 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
+
+% TODO: con il kernel 3.17 è stata introdotta una fuunzionalità di
+% sigillatura dei file mappati in memoria e la system call memfd
+% (capire se va messo qui o altrove) vedi: http://lwn.net/Articles/593918/
+
+
+\section{L'intercomunicazione fra processi di POSIX}
\label{sec:ipc_posix}
-Per superare i numerosi problemi del \textit{SysV IPC}, evidenziati per i suoi
-aspetti generali in coda a \secref{sec:ipc_sysv_generic} e per i singoli
+Per superare i numerosi problemi del \textit{SysV-IPC}, evidenziati per i suoi
+aspetti generali in coda a sez.~\ref{sec:ipc_sysv_generic} e per i singoli
oggetti nei paragrafi successivi, lo standard POSIX.1b ha introdotto dei nuovi
meccanismi di comunicazione, che vanno sotto il nome di POSIX IPC, definendo
una interfaccia completamente nuova, che tratteremo in questa sezione.
-
\subsection{Considerazioni generali}
\label{sec:ipc_posix_generic}
-Il Linux non tutti gli oggetti del POSIX IPC sono supportati nel kernel
-ufficiale; solo la memoria condivisa è presente, ma solo a partire dal kernel
-2.4.x, per gli altri oggetti esistono patch e librerie non
-ufficiali. Nonostante questo è importante esaminare questa interfaccia per la
-sua netta superiorità nei confronti di quella del \textit{SysV IPC}.
-
+Oggi Linux supporta tutti gli oggetti definito nello standard POSIX per l'IPC,
+ma a lungo non è stato così; la memoria condivisa è presente a partire dal
+kernel 2.4.x, i semafori sono forniti dalla \acr{glibc} nella sezione che
+implementa i \itindex{thread} \textit{thread} POSIX di nuova generazione che
+richiedono il kernel 2.6, le code di messaggi sono supportate a partire dal
+kernel 2.6.6.
+
+La caratteristica fondamentale dell'interfaccia POSIX è l'abbandono dell'uso
+degli identificatori e delle chiavi visti nel \textit{SysV-IPC}, per passare ai
+\itindex{POSIX~IPC~names} \textit{POSIX IPC names}, che sono sostanzialmente
+equivalenti ai nomi dei file. Tutte le funzioni che creano un oggetto di IPC
+POSIX prendono come primo argomento una stringa che indica uno di questi nomi;
+lo standard è molto generico riguardo l'implementazione, ed i nomi stessi
+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
+ \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.
+\item l'interpretazione di ulteriori \texttt{/} presenti nel nome dipende
+ dall'implementazione.
+\end{itemize*}
-\subsection{Code di messaggi}
+Data la assoluta genericità delle specifiche, il comportamento delle funzioni
+è subordinato in maniera quasi completa alla relativa implementazione, tanto
+che Stevens in \cite{UNP2} cita questo caso come un esempio della maniera
+standard usata dallo standard POSIX per consentire implementazioni non
+standardizzabili.
+
+Nel caso di Linux, sia per quanto riguarda la memoria condivisa ed i semafori,
+che per le code di messaggi, tutto viene creato usando come radici delle
+opportune directory (rispettivamente \file{/dev/shm} e \file{/dev/mqueue}, per
+i dettagli si faccia riferimento a sez.~\ref{sec:ipc_posix_shm},
+sez.~\ref{sec:ipc_posix_sem} e sez.~\ref{sec:ipc_posix_mq}). I nomi
+specificati nelle relative funzioni devono essere nella forma di un
+\textit{pathname} assoluto (devono cioè iniziare con ``\texttt{/}'') e
+corrisponderanno ad altrettanti file creati all'interno di queste directory;
+per questo motivo detti nomi non possono contenere altre ``\texttt{/}'' oltre
+quella iniziale.
+
+Il vantaggio degli oggetti di IPC POSIX è comunque che essi vengono inseriti
+nell'albero dei file, e possono essere maneggiati con le usuali funzioni e
+comandi di accesso ai file, che funzionano come su dei file normali. Questo
+però è vero nel caso di Linux, che usa una implementazione che lo consente,
+non è detto che altrettanto valga per altri kernel. In particolare, come si
+può facilmente verificare con il comando \cmd{strace}, sia per la memoria
+condivisa che per le code di messaggi varie \textit{system call} utilizzate da
+Linux corrispondono in realtà a quelle ordinarie dei file, essendo detti
+oggetti realizzati come tali usando degli specifici filesystem.
+
+In particolare i permessi associati agli oggetti di IPC POSIX sono identici ai
+permessi dei file, ed il controllo di accesso segue esattamente la stessa
+semantica (quella illustrata in sez.~\ref{sec:file_access_control}), e non
+quella particolare (si ricordi quanto visto in
+sez.~\ref{sec:ipc_sysv_access_control}) che viene usata per gli oggetti del
+SysV-IPC. Per quanto riguarda l'attribuzione dell'utente e del gruppo
+proprietari dell'oggetto alla creazione di quest'ultimo essa viene effettuata
+secondo la semantica SysV: corrispondono cioè a \ids{UID} e \ids{GID} effettivi
+del processo che esegue la creazione.
+
+
+\subsection{Code di messaggi Posix}
\label{sec:ipc_posix_mq}
-Le code di messaggi non sono supportate a livello del kernel, esse però
-possono essere implementate, usando la memoria condivisa ed i mutex, con
-funzioni di libreria. In generale esse sono comunque poco usate, i socket, nei
-casi in cui sono sufficienti, sono più comodi, e negli altri casi la
-comunicazione può essere gestita direttamente con la stessa metodologia usata
-per implementare le code di messaggi. Per questo ci limiteremo ad una
-descrizione essenziale.
+Le code di messaggi POSIX sono supportate da Linux a partire dalla versione
+2.6.6 del kernel. In generale, come le corrispettive del \textit{SysV-IPC}, le
+code di messaggi sono poco usate, dato che i socket, nei casi in cui sono
+sufficienti, sono più comodi, e che in casi più complessi la comunicazione può
+essere gestita direttamente con mutex (o semafori) e memoria condivisa con
+tutta la flessibilità che occorre.
+
+Per poter utilizzare le code di messaggi, oltre ad utilizzare un kernel
+superiore al 2.6.6 occorre utilizzare la libreria \file{librt} che contiene le
+funzioni dell'interfaccia POSIX ed i programmi che usano le code di messaggi
+devono essere compilati aggiungendo l'opzione \code{-lrt} al comando
+\cmd{gcc}. In corrispondenza all'inclusione del supporto nel kernel ufficiale
+le funzioni di libreria sono state inserite nella \acr{glibc}, e sono
+disponibili a partire dalla versione 2.3.4 delle medesime.
+
+La libreria inoltre richiede la presenza dell'apposito filesystem di tipo
+\texttt{mqueue} montato sulla directory \file{/dev/mqueue}; questo può essere
+fatto aggiungendo ad \conffile{/etc/fstab} una riga come:
+\begin{FileExample}[label=/etc/fstab]
+mqueue /dev/mqueue mqueue defaults 0 0
+\end{FileExample}
+ed esso sarà utilizzato come radice sulla quale vengono risolti i nomi delle
+code di messaggi che iniziano con una ``\texttt{/}''. Le opzioni di mount
+accettate sono \texttt{uid}, \texttt{gid} e \texttt{mode} che permettono
+rispettivamente di impostare l'utente, il gruppo ed i permessi associati al
+filesystem.
+
+
+La funzione di sistema che permette di aprire (e crearla se non esiste ancora)
+una coda di messaggi POSIX è \funcd{mq\_open}, ed il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{fcntl.h}
+\fhead{sys/stat.h}
+\fhead{mqueue.h}
+\fdecl{mqd\_t mq\_open(const char *name, int oflag)}
+\fdecl{mqd\_t mq\_open(const char *name, int oflag, unsigned long mode,
+ struct mq\_attr *attr)}
+
+\fdesc{Apre una coda di messaggi POSIX impostandone le caratteristiche.}
+}
+{La funzione ritorna il descrittore associato alla coda in caso di successo e
+ $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] il processo non ha i privilegi per accedere alla
+ coda secondo quanto specificato da \param{oflag} oppure \const{name}
+ contiene più di una ``\texttt{/}''.
+ \item[\errcode{EEXIST}] si è specificato \const{O\_CREAT} e \const{O\_EXCL}
+ ma la coda già esiste.
+ \item[\errcode{EINVAL}] il file non supporta la funzione, o si è specificato
+ \const{O\_CREAT} con una valore non nullo di \param{attr} e valori non
+ validi dei campi \var{mq\_maxmsg} e \var{mq\_msgsize}; questi valori
+ devono essere positivi ed inferiori ai limiti di sistema se il processo
+ non ha privilegi amministrativi, inoltre \var{mq\_maxmsg} non può comunque
+ superare \const{HARD\_MAX}.
+ \item[\errcode{ENOENT}] non si è specificato \const{O\_CREAT} ma la coda non
+ esiste o si è usato il nome ``\texttt{/}''.
+ \item[\errcode{ENOSPC}] lo spazio è insufficiente, probabilmente per aver
+ superato il limite di \texttt{queues\_max}.
+ \end{errlist}
+ ed inoltre \errval{EMFILE}, \errval{ENAMETOOLONG}, \errval{ENFILE},
+ \errval{ENOMEM} ed nel loro significato generico. }
+\end{funcproto}
+
+La funzione apre la coda di messaggi identificata dall'argomento \param{name}
+restituendo il descrittore ad essa associato, del tutto analogo ad un file
+descriptor, con l'unica differenza che lo standard prevede un apposito tipo
+\type{mqd\_t}. Nel caso di Linux si tratta in effetti proprio di un normale
+file descriptor; pertanto, anche se questo comportamento non è portabile, lo
+si può tenere sotto osservazione con le funzioni dell'I/O multiplexing (vedi
+sez.~\ref{sec:file_multiplexing}) come possibile alternativa all'uso
+dell'interfaccia di notifica di \func{mq\_notify} (che vedremo a breve).
+
+Se il nome indicato fa riferimento ad una coda di messaggi già esistente, il
+descrittore ottenuto farà riferimento allo stesso oggetto, pertanto tutti i
+processi che hanno usato \func{mq\_open} su quel nome otterranno un
+riferimento alla stessa coda. Diventa così immediato costruire un canale di
+comunicazione fra detti processi.
+
+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
+sez.~\ref{sec:file_open_close} (per questo occorre includere \texttt{fcntl.h})
+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
+ processo potrà usare il descrittore con \func{mq\_receive} ma non con
+ \func{mq\_send}.
+\item[\const{O\_WRONLY}] Apre la coda solo per la trasmissione di messaggi. Il
+ processo potrà usare il descrittore con \func{mq\_send} ma non con
+ \func{mq\_receive}.
+\item[\const{O\_RDWR}] Apre la coda solo sia per la trasmissione che per la
+ ricezione.
+\item[\const{O\_CREAT}] Necessario qualora si debba creare la coda; la
+ presenza di questo bit richiede la presenza degli ulteriori argomenti
+ \param{mode} e \param{attr}.
+\item[\const{O\_EXCL}] Se usato insieme a \const{O\_CREAT} fa fallire la
+ chiamata se la coda esiste già, altrimenti esegue la creazione atomicamente.
+\item[\const{O\_NONBLOCK}] Imposta la coda in modalità non bloccante, le
+ funzioni di ricezione e trasmissione non si bloccano quando non ci sono le
+ risorse richieste, ma ritornano immediatamente con un errore di
+ \errcode{EAGAIN}.
+\end{basedescript}
+I primi tre bit specificano la modalità di apertura della coda, e sono fra
+loro esclusivi. Ma qualunque sia la modalità in cui si è aperta una coda,
+questa potrà essere riaperta più volte in una modalità diversa, e vi si potrà
+sempre accedere attraverso descrittori diversi, esattamente come si può fare
+per i file normali.
+
+Se la coda non esiste e la si vuole creare si deve specificare
+\const{O\_CREAT}, in tal caso occorre anche specificare i permessi di
+creazione con l'argomento \param{mode};\footnote{fino al 2.6.14 per un bug i
+ valori della \textit{umask} del processo non venivano applicati a questi
+ permessi.} i valori di quest'ultimo sono identici a quelli usati per
+\func{open} (per questo occorre includere \texttt{sys/stat.h}), anche se per
+le code di messaggi han senso solo i permessi di lettura e scrittura.
+
+Oltre ai permessi di creazione possono essere specificati anche gli attributi
+specifici della coda tramite l'argomento \param{attr}; quest'ultimo è un
+puntatore ad una apposita struttura \struct{mq\_attr}, la cui definizione è
+riportata in fig.~\ref{fig:ipc_mq_attr}.
-\subsection{Semafori}
-\label{sec:ipc_posix_sem}
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{0.90\textwidth}
+ \includestruct{listati/mq_attr.h}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \structd{mq\_attr}, contenente gli attributi di una
+ coda di messaggi POSIX.}
+ \label{fig:ipc_mq_attr}
+\end{figure}
+
+Per la creazione della coda i campi della struttura che devono essere
+specificati sono \var{mq\_maxmsg} e \var{mq\_msgsize}, che indicano
+rispettivamente il numero massimo di messaggi che può contenere e la
+dimensione massima di un messaggio. Il valore dovrà essere positivo e minore
+dei rispettivi limiti di sistema altrimenti la funzione fallirà con un errore
+di \errcode{EINVAL}. Se \param{attr} è un puntatore nullo gli attributi della
+coda saranno impostati ai valori predefiniti.
+
+I suddetti limiti di sistema sono impostati attraverso altrettanti file in
+\texttt{/proc/sys/fs/mqueue}, in particolare i file che controllano i valori
+dei limiti sono:
+\begin{basedescript}{\desclabelwidth{1.5cm}\desclabelstyle{\nextlinelabel}}
+\item[\sysctlfile{fs/mqueue/msg\_max}] Indica il valore massimo del numero di
+ messaggi in una coda e agisce come limite superiore per il valore di
+ \var{attr->mq\_maxmsg} in \func{mq\_open}. Il suo valore di default è 10. Il
+ valore massimo è \const{HARD\_MAX} che vale \code{(131072/sizeof(void *))},
+ ed il valore minimo 1 (ma era 10 per i kernel precedenti il 2.6.28). Questo
+ limite viene ignorato per i processi con privilegi amministrativi (più
+ precisamente con la \textit{capability} \const{CAP\_SYS\_RESOURCE}) ma
+ \const{HARD\_MAX} resta comunque non superabile.
+
+\item[\sysctlfile{fs/mqueue/msgsize\_max}] Indica il valore massimo della
+ dimensione in byte di un messaggio sulla coda ed agisce come limite
+ superiore per il valore di \var{attr->mq\_msgsize} in \func{mq\_open}. Il
+ suo valore di default è 8192. Il valore massimo è 1048576 ed il valore
+ minimo 128 (ma per i kernel precedenti il 2.6.28 detti limiti erano
+ rispettivamente \const{INT\_MAX} e 8192). Questo limite viene ignorato dai
+ processi con privilegi amministrativi (con la \textit{capability}
+ \const{CAP\_SYS\_RESOURCE}).
+
+\item[\sysctlfile{fs/mqueue/queues\_max}] Indica il numero massimo di code di
+ messaggi creabili in totale sul sistema, il valore di default è 256 ma si
+ può usare un valore qualunque fra $0$ e \const{INT\_MAX}. Il limite non
+ viene applicato ai processi con privilegi amministrativi (cioè con la
+ \textit{capability} \const{CAP\_SYS\_RESOURCE}).
+
+\end{basedescript}
+
+Infine sulle code di messaggi si applica il limite imposto sulla risorsa
+\const{RLIMIT\_MSGQUEUE} (vedi sez.~\ref{sec:sys_resource_limit}) che indica
+lo spazio massimo (in byte) occupabile dall'insieme di tutte le code di
+messaggi appartenenti ai processi di uno stesso utente, che viene identificato
+in base al \textit{real user ID} degli stessi.
+
+Quando l'accesso alla coda non è più necessario si può chiudere il relativo
+descrittore con la funzione \funcd{mq\_close}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{mqueue.h}
+\fdecl{int mq\_close(mqd\_t mqdes)}
+
+\fdesc{Chiude una coda di messaggi.}
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà uno dei valori \errval{EBADF} o \errval{EINTR} nel
+ loro significato generico.
+}
+\end{funcproto}
+
+La funzione è analoga a \func{close},\footnote{su Linux, dove le code sono
+ implementate come file su un filesystem dedicato, è esattamente la stessa
+ funzione, per cui non esiste una \textit{system call} autonoma e la funzione
+ viene rimappata su \func{close} dalle \acr{glibc}.} dopo la sua esecuzione
+il processo non sarà più in grado di usare il descrittore della coda, ma
+quest'ultima continuerà ad esistere nel sistema e potrà essere acceduta con
+un'altra chiamata a \func{mq\_open}. All'uscita di un processo tutte le code
+aperte, così come i file, vengono chiuse automaticamente. Inoltre se il
+processo aveva agganciato una richiesta di notifica sul descrittore che viene
+chiuso, questa sarà rilasciata e potrà essere richiesta da qualche altro
+processo.
+
+Quando si vuole effettivamente rimuovere una coda dal sistema occorre usare la
+funzione di sistema \funcd{mq\_unlink}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{mqueue.h}
+\fdecl{int mq\_unlink(const char *name)}
+
+\fdesc{Rimuove una coda di messaggi.}
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà gli uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] non si hanno i permessi per cancellare la coda.
+ \item[\errcode{ENAMETOOLONG}] il nome indicato è troppo lungo.
+ \item[\errcode{ENOENT}] non esiste una coda con il nome indicato.
+ \end{errlist}
+}
+\end{funcproto}
+
+Anche in questo caso il comportamento della funzione è analogo a quello di
+\func{unlink} per i file, la funzione rimuove la coda \param{name} (ed il
+relativo file sotto \texttt{/dev/mqueue}), così che una successiva chiamata a
+\func{mq\_open} fallisce o crea una coda diversa.
+
+% TODO, verificare se mq_unlink è davvero una system call indipendente.
+
+Come per i file ogni coda di messaggi ha un contatore di riferimenti, per cui
+la coda non viene effettivamente rimossa dal sistema fin quando questo non si
+annulla. Pertanto anche dopo aver eseguito con successo \func{mq\_unlink} la
+coda resterà accessibile a tutti i processi che hanno un descrittore aperto su
+di essa. Allo stesso modo una coda ed i suoi contenuti resteranno disponibili
+all'interno del sistema anche quando quest'ultima non è aperta da nessun
+processo (questa è una delle differenze più rilevanti nei confronti di
+\textit{pipe} e \textit{fifo}). La sola differenza fra code di messaggi POSIX
+e file normali è che, essendo il filesystem delle code di messaggi virtuale, e
+basato su oggetti interni al kernel, il suo contenuto viene perduto con il
+riavvio del sistema.
+
+Come accennato ad ogni coda di messaggi è associata una struttura
+\struct{mq\_attr}, che può essere letta e modificata attraverso le due
+funzioni \funcd{mq\_getattr} e \funcd{mq\_setattr}, i cui prototipi sono:
+
+\begin{funcproto}{
+\fhead{mqueue.h}
+\fdecl{int mq\_getattr(mqd\_t mqdes, struct mq\_attr *mqstat)}
+\fdesc{Legge gli attributi di una coda di messaggi POSIX.}
+\fdecl{int mq\_setattr(mqd\_t mqdes, const struct mq\_attr *mqstat,
+ struct mq\_attr *omqstat)}
+\fdesc{Modifica gli attributi di una coda di messaggi POSIX.}
+}
+{
+Entrambe le funzioni ritornano $0$ in caso di successo e $-1$ per un errore,
+ nel qual caso \var{errno} assumerà i valori \errval{EBADF}
+ o \errval{EINVAL} nel loro significato generico.
+}
+\end{funcproto}
+
+La funzione \func{mq\_getattr} legge i valori correnti degli attributi della
+coda \param{mqdes} nella struttura \struct{mq\_attr} puntata
+da \param{mqstat}; di questi l'unico relativo allo stato corrente della coda è
+\var{mq\_curmsgs} che indica il numero di messaggi da essa contenuti, gli
+altri indicano le caratteristiche generali della stessa impostate in fase di
+apertura.
+
+La funzione \func{mq\_setattr} permette di modificare gli attributi di una
+coda (indicata da \param{mqdes}) tramite i valori contenuti nella struttura
+\struct{mq\_attr} puntata da \param{mqstat}, ma può essere modificato solo il
+campo \var{mq\_flags}, gli altri campi vengono comunque ignorati.
+
+In particolare i valori di \var{mq\_maxmsg} e \var{mq\_msgsize} possono essere
+specificati solo in fase ci creazione della coda. Inoltre i soli valori
+possibili per \var{mq\_flags} sono 0 e \const{O\_NONBLOCK}, per cui alla fine
+la funzione può essere utilizzata solo per abilitare o disabilitare la
+modalità non bloccante. L'argomento \param{omqstat} viene usato, quando
+diverso da \val{NULL}, per specificare l'indirizzo di una struttura su cui
+salvare i valori degli attributi precedenti alla chiamata della funzione.
+
+Per inserire messaggi su di una coda sono previste due funzioni di sistema,
+\funcd{mq\_send} e \funcd{mq\_timedsend}. In realtà su Linux la \textit{system
+ call} è soltanto \func{mq\_timedsend}, mentre \func{mq\_send} viene
+implementata come funzione di libreria che si appoggia alla
+precedente. Inoltre \func{mq\_timedsend} richiede che sia definita la macro
+\macro{\_XOPEN\_SOURCE} ad un valore pari ad almeno \texttt{600} o la macro
+\macro{\_POSIX\_C\_SOURCE} ad un valore uguale o maggiore di \texttt{200112L}.
+I rispettivi prototipi sono:
+
+\begin{funcproto}{
+\fhead{mqueue.h}
+\fdecl{int mq\_send(mqd\_t mqdes, const char *msg\_ptr, size\_t msg\_len,
+ unsigned int msg\_prio)}
+\fdesc{Esegue l'inserimento di un messaggio su una coda.}
+\fhead{mqueue.h}
+\fhead{time.h}
+\fdecl{int mq\_timedsend(mqd\_t mqdes, const char *msg\_ptr, size\_t
+ msg\_len, \\
+\phantom{int mq\_timedsend(}unsigned int msg\_prio, const struct timespec *abs\_timeout)}
+\fdesc{Esegue l'inserimento di un messaggio su una coda entro un tempo
+ specificato}
+}
+
+{Entrambe le funzioni ritornano $0$ in caso di successo e $-1$ per un errore,
+ nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EAGAIN}] si è aperta la coda con \const{O\_NONBLOCK}, e la
+ coda è piena.
+ \item[\errcode{EBADF}] si specificato un file descriptor non valido.
+ \item[\errcode{EINVAL}] si è specificato un valore nullo per
+ \param{msg\_len}, o un valore di \param{msg\_prio} fuori dai limiti, o
+ un valore non valido per \param{abs\_timeout}.
+ \item[\errcode{EMSGSIZE}] la lunghezza del messaggio \param{msg\_len}
+ eccede il limite impostato per la coda.
+ \item[\errcode{ETIMEDOUT}] l'inserimento del messaggio non è stato
+ effettuato entro il tempo stabilito (solo \func{mq\_timedsend}).
+ \end{errlist}
+ ed inoltre \errval{EBADF} e \errval{EINTR} nel loro significato generico.
+}
+\end{funcproto}
+
+Entrambe le funzioni richiedono un puntatore ad un buffer in memoria
+contenente il testo del messaggio da inserire nella coda \param{mqdes}
+nell'argomento \param{msg\_ptr}, e la relativa lunghezza in \param{msg\_len}.
+Se quest'ultima eccede la dimensione massima specificata da \var{mq\_msgsize}
+le funzioni ritornano immediatamente con un errore di \errcode{EMSGSIZE}.
+
+L'argomento \param{msg\_prio} indica la priorità dell'argomento, che, essendo
+definito come \ctyp{unsigned int}, è sempre un intero positivo. I messaggi di
+priorità maggiore vengono inseriti davanti a quelli di priorità inferiore, e
+quindi saranno riletti per primi. A parità del valore della priorità il
+messaggio sarà inserito in coda a tutti quelli che hanno la stessa priorità
+che quindi saranno letti con la politica di una \textit{fifo}. Il valore della
+priorità non può eccedere il limite di sistema \const{MQ\_PRIO\_MAX}, che al
+momento è pari a 32768.
+
+Qualora la coda sia piena, entrambe le funzioni si bloccano, a meno che non
+sia stata selezionata in fase di apertura della stessa la modalità non
+bloccante o non si sia impostato il flag \const{O\_NONBLOCK} sul file
+descriptor della coda, nel qual caso entrambe ritornano con un codice di
+errore di \errcode{EAGAIN}.
+
+La sola differenza fra le due funzioni è che \func{mq\_timedsend}, passato il
+tempo massimo impostato con l'argomento \param{abs\_timeout}, ritorna con un
+errore di \errcode{ETIMEDOUT}, se invece il tempo è già scaduto al momento
+della chiamata e la coda è piena la funzione ritorna immediatamente. Il valore
+di \param{abs\_timeout} deve essere specificato come tempo assoluto tramite
+una struttura \struct{timespec} (vedi fig.~\ref{fig:sys_timespec_struct})
+indicato in numero di secondi e nanosecondi a partire dal 1 gennaio 1970.
+
+Come per l'inserimento, anche per l'estrazione dei messaggi da una coda sono
+previste due funzioni di sistema, \funcd{mq\_receive} e
+\funcd{mq\_timedreceive}. Anche in questo caso su Linux soltanto
+\func{mq\_timedreceive} è effettivamente, una \textit{system call} e per
+usarla devono essere definite le opportune macro come per
+\func{mq\_timedsend}. I rispettivi prototipi sono:
+
+\begin{funcproto}{
+\fhead{mqueue.h}
+\fdecl{ssize\_t mq\_receive(mqd\_t mqdes, char *msg\_ptr, size\_t
+ msg\_len, unsigned int *msg\_prio)}
+\fdesc{Effettua la ricezione di un messaggio da una coda.}
+\fhead{mqueue.h}
+\fhead{time.h}
+\fdecl{ssize\_t mq\_timedreceive(mqd\_t mqdes, char *msg\_ptr, size\_t
+ msg\_len,\\
+\phantom{ssize\_t mq\_timedreceive(}unsigned int *msg\_prio, const struct timespec
+*abs\_timeout)}
+\fdesc{Riceve un messaggio da una coda entro un limite di tempo.}
+}
+{Entrambe le funzioni ritornano il numero di byte del messaggio in caso di
+ successo e $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei
+ valori:
+ \begin{errlist}
+ \item[\errcode{EAGAIN}] si è aperta la coda con \const{O\_NONBLOCK}, e la
+ coda è vuota.
+ \item[\errcode{EINVAL}] si è specificato un valore nullo per
+ \param{msg\_ptr}, o un valore non valido per \param{abs\_timeout}.
+ \item[\errcode{EMSGSIZE}] la lunghezza del messaggio sulla coda eccede il
+ valore \param{msg\_len} specificato per la ricezione.
+ \item[\errcode{ETIMEDOUT}] la ricezione del messaggio non è stata
+ effettuata entro il tempo stabilito.
+ \end{errlist}
+ ed inoltre \errval{EBADF} o \errval{EINTR} nel loro significato generico. }
+\end{funcproto}
+
+La funzione estrae dalla coda \param{mqdes} il messaggio a priorità più alta,
+o il più vecchio fra quelli della stessa priorità. Una volta ricevuto il
+messaggio viene tolto dalla coda e la sua dimensione viene restituita come
+valore di ritorno; si tenga presente che 0 è una dimensione valida e che la
+condizione di errore è indicata soltanto da un valore di
+$-1$.\footnote{Stevens in \cite{UNP2} fa notare che questo è uno dei casi in
+ cui vale ciò che lo standard \textsl{non} dice, una dimensione nulla
+ infatti, pur non essendo citata, non viene proibita.}
+
+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\_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.
+
+Se si specifica un puntatore per l'argomento \param{msg\_prio} il valore della
+priorità del messaggio viene memorizzato all'indirizzo da esso indicato.
+Qualora non interessi usare la priorità dei messaggi si può specificare
+\var{NULL}, ed usare un valore nullo della priorità nelle chiamate a
+\func{mq\_send}.
+
+Si noti che con le code di messaggi POSIX non si ha la possibilità di
+selezionare quale messaggio estrarre con delle condizioni sulla priorità, a
+differenza di quanto avveniva con le code di messaggi di SysV che permettono
+invece la selezione in base al valore del campo \var{mtype}.
+
+Qualora la coda sia vuota entrambe le funzioni si bloccano, a meno che non si
+sia selezionata la modalità non bloccante; in tal caso entrambe ritornano
+immediatamente con l'errore \errcode{EAGAIN}. Anche in questo caso la sola
+differenza fra le due funzioni è che la seconda non attende indefinitamente e
+passato il tempo massimo \param{abs\_timeout} ritorna comunque con un errore
+di \errcode{ETIMEDOUT}.
+
+Uno dei problemi sottolineati da Stevens in \cite{UNP2}, comuni ad entrambe le
+tipologie di code messaggi, è che non è possibile per chi riceve identificare
+chi è che ha inviato il messaggio, in particolare non è possibile sapere da
+quale utente esso provenga. Infatti, in mancanza di un meccanismo interno al
+kernel, anche se si possono inserire delle informazioni nel messaggio, queste
+non possono essere credute, essendo completamente dipendenti da chi lo invia.
+Vedremo però come, attraverso l'uso del meccanismo di notifica, sia possibile
+superare in parte questo problema.
+
+Una caratteristica specifica delle code di messaggi POSIX è la possibilità di
+usufruire di un meccanismo di notifica asincrono; questo può essere attivato
+usando la funzione \funcd{mq\_notify}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{mqueue.h}
+\fdecl{int mq\_notify(mqd\_t mqdes, const struct sigevent *notification)}
+
+\fdesc{Attiva il meccanismo di notifica per una coda.}
+}
-Dei semafori POSIX esistono sostanzialmente due implementazioni; una è fatta a
-livello di libreria ed è fornita dalla libreria dei thread; questa però li
-implementa solo a livello di thread e non di processi. Esiste una
+{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{EBADF}] il descrittore non fa riferimento ad una coda di
+ messaggi.
+ \item[\errcode{EBUSY}] c'è già un processo registrato per la notifica.
+ \item[\errcode{EINVAL}] si è richiesto un meccanismo di notifica invalido
+ o specificato nella notifica con i segnali il valore di un segnale non
+ esistente.
+ \end{errlist}
+ ed inoltre \errval{ENOMEM} nel suo significato generico.
+}
+\end{funcproto}
+
+Il meccanismo di notifica permette di segnalare in maniera asincrona ad un
+processo la presenza di dati sulla coda indicata da \param{mqdes}, in modo da
+evitare la necessità di bloccarsi nell'attesa. Per far questo un processo deve
+registrarsi con la funzione \func{mq\_notify}, ed il meccanismo è disponibile
+per un solo processo alla volta per ciascuna coda.
+
+Il comportamento di \func{mq\_notify} dipende dai valori passati con
+l'argomento \param{notification}, che è un puntatore ad una apposita struttura
+\struct{sigevent}, (definita in fig.~\ref{fig:struct_sigevent}) introdotta
+dallo standard POSIX.1b per gestire la notifica di eventi; per altri dettagli
+su di essa si può rivedere quanto detto in sez.~\ref{sec:sig_timer_adv} a
+proposito dell'uso della stessa struttura per la notifica delle scadenze dei
+\textit{timer}.
+
+Attraverso questa struttura si possono impostare le modalità con cui viene
+effettuata la notifica nel campo \var{sigev\_notify}, che può assumere i
+valori di tab.~\ref{tab:sigevent_sigev_notify}; fra questi la pagina di
+manuale riporta soltanto i primi tre, ed inizialmente era possibile solo
+\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} (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
+ \textit{real-time}.} posto che questo sia installato nella forma estesa
+vista in sez.~\ref{sec:sig_sigaction}.
+
+La funzione registra il processo chiamante per la notifica se
+\param{notification} punta ad una struttura \struct{sigevent} opportunamente
+inizializzata, o cancella una precedente registrazione se è \val{NULL}. Dato
+che un solo processo alla volta può essere registrato, la funzione fallisce
+con \errcode{EBUSY} se c'è un altro processo già registrato. Questo significa
+anche che se si registra una notifica con \const{SIGEV\_NONE} il processo non
+la riceverà, ma impedirà anche che altri possano registrarsi per poterlo fare.
+Si tenga presente inoltre che alla chiusura del descrittore associato alla
+coda (e quindi anche all'uscita del processo) ogni eventuale registrazione di
+notifica presente viene cancellata.
+
+La notifica del segnale avviene all'arrivo di un messaggio in una coda vuota
+(cioè solo se sulla coda non ci sono messaggi) e se non c'è nessun processo
+bloccato in una chiamata a \func{mq\_receive}, in questo caso infatti il
+processo bloccato ha la precedenza ed il messaggio gli viene immediatamente
+inviato, mentre per il meccanismo di notifica tutto funziona come se la coda
+fosse rimasta vuota.
+
+Quando un messaggio arriva su una coda vuota al processo che si era registrato
+viene inviato il segnale specificato da \code{notification->sigev\_signo}, e
+la coda diventa disponibile per una ulteriore registrazione. Questo comporta
+che se si vuole mantenere il meccanismo di notifica occorre ripetere la
+registrazione chiamando nuovamente \func{mq\_notify} all'interno del gestore
+del segnale di notifica. A differenza della situazione simile che si aveva con
+i segnali non affidabili (l'argomento è stato affrontato in
+\ref{sec:sig_semantics}) questa caratteristica non configura una \textit{race
+ condition} perché l'invio di un segnale avviene solo se la coda è vuota;
+pertanto se si vuole evitare di correre il rischio di perdere eventuali
+ulteriori segnali inviati nel lasso di tempo che occorre per ripetere la
+richiesta di notifica basta avere cura di eseguire questa operazione prima di
+estrarre i messaggi presenti dalla coda.
+
+L'invio del segnale di notifica avvalora alcuni campi di informazione
+restituiti al gestore attraverso la struttura \struct{siginfo\_t} (definita in
+fig.~\ref{fig:sig_siginfo_t}). In particolare \var{si\_pid} viene impostato al
+valore del \ids{PID} del processo che ha emesso il segnale, \var{si\_uid}
+all'\textsl{user-ID} effettivo, \var{si\_code} a \const{SI\_MESGQ}, e
+\var{si\_errno} a 0. Questo ci dice che, se si effettua la ricezione dei
+messaggi usando esclusivamente il meccanismo di notifica, è possibile ottenere
+le informazioni sul processo che ha inserito un messaggio usando un gestore
+per il segnale in forma estesa, di nuovo si faccia riferimento a quanto detto
+al proposito in sez.~\ref{sec:sig_sigaction} e sez.~\ref{sec:sig_real_time}.
\subsection{Memoria condivisa}
\label{sec:ipc_posix_shm}
-La memoria condivisa è l'unico degli oggetti di IPC POSIX già presente nel
-kernel ufficiale.
+La memoria condivisa è stato il primo degli oggetti di IPC POSIX inserito nel
+kernel ufficiale; il supporto a questo tipo di oggetti è realizzato attraverso
+il filesystem \texttt{tmpfs}, uno speciale filesystem che mantiene tutti i
+suoi contenuti in memoria, che viene attivato abilitando l'opzione
+\texttt{CONFIG\_TMPFS} in fase di compilazione del kernel.
+
+Per potere utilizzare l'interfaccia POSIX per la memoria condivisa la
+\acr{glibc} (le funzioni sono state introdotte con la versione 2.2) richiede
+di compilare i programmi con l'opzione \code{-lrt}; inoltre è necessario che
+in \file{/dev/shm} sia montato un filesystem \texttt{tmpfs}; questo di norma
+viene fatto aggiungendo una riga del tipo di:
+\begin{FileExample}[label=/etc/fstab]
+tmpfs /dev/shm tmpfs defaults 0 0
+\end{FileExample}
+ad \conffile{/etc/fstab}. In realtà si può montare un filesystem
+\texttt{tmpfs} dove si vuole, per usarlo come RAM disk, con un comando del
+tipo:
+\begin{Example}
+mount -t tmpfs -o size=128M,nr_inodes=10k,mode=700 tmpfs /mytmpfs
+\end{Example}
+
+Il filesystem riconosce, oltre quelle mostrate, le opzioni \texttt{uid} e
+\texttt{gid} che identificano rispettivamente utente e gruppo cui assegnarne
+la titolarità, e \texttt{nr\_blocks} che permette di specificarne la
+dimensione in blocchi, cioè in multipli di \const{PAGECACHE\_SIZE} che in
+questo caso è l'unità di allocazione elementare.
+
+La funzione che permette di aprire un segmento di memoria condivisa POSIX, ed
+eventualmente di crearlo se non esiste ancora, è \funcd{shm\_open}; il suo
+prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/mman.h}
+\fhead{sys/stat.h}
+\fhead{fcntl.h}
+\fdecl{int shm\_open(const char *name, int oflag, mode\_t mode)}
+
+\fdesc{Apre un segmento di memoria condivisa.}
+}
+
+{La funzione ritorna un file descriptor in caso di successo e $-1$ per un
+ errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] non si hanno i permessi di aprire il segmento nella
+ modalità scelta o si richiesto \const{O\_TRUNC} per un segmento su cui non
+ si ha il permesso di scrittura.
+ \item[\errcode{EINVAL}] si è utilizzato un nome non valido.
+ \end{errlist}
+ ed inoltre \errval{EEXIST}, \errval{EMFILE}, \errval{ENAMETOOLONG},
+ \errval{ENFILE} e \errval{ENOENT} nello stesso significato che hanno per
+ \func{open}.
+}
+\end{funcproto}
+
+
+La funzione apre un segmento di memoria condivisa identificato dal nome
+\param{name}. Come già spiegato in sez.~\ref{sec:ipc_posix_generic} questo
+nome può essere specificato in forma standard solo facendolo iniziare per
+``\texttt{/}'' e senza ulteriori ``\texttt{/}''. Linux supporta comunque nomi
+generici, che verranno interpretati prendendo come radice
+\file{/dev/shm}.\footnote{occorre pertanto evitare di specificare qualcosa del
+ tipo \file{/dev/shm/nome} all'interno di \param{name}, perché questo
+ comporta, da parte delle funzioni di libreria, il tentativo di accedere a
+ \file{/dev/shm/dev/shm/nome}.}
+
+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
+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
+ memoria condivisa per l'accesso in sola lettura.
+\item[\const{O\_RDWR}] Apre il file descriptor associato al segmento di
+ memoria condivisa per l'accesso in lettura e scrittura.
+\item[\const{O\_CREAT}] Necessario qualora si debba creare il segmento di
+ memoria condivisa se esso non esiste; in questo caso viene usato il valore
+ di \param{mode} per impostare i permessi, che devono essere compatibili con
+ le modalità con cui si è aperto il file.
+\item[\const{O\_EXCL}] Se usato insieme a \const{O\_CREAT} fa fallire la
+ chiamata a \func{shm\_open} se il segmento esiste già, altrimenti esegue la
+ creazione atomicamente.
+\item[\const{O\_TRUNC}] Se il segmento di memoria condivisa esiste già, ne
+ tronca le dimensioni a 0 byte.
+\end{basedescript}
+
+In caso di successo la funzione restituisce un file descriptor associato al
+segmento di memoria condiviso con le stesse modalità di \func{open} viste in
+sez.~\ref{sec:file_open_close}. Inoltre sul file descriptor viene sempre
+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 ordinari, essi sono associati
+allo stesso inode. In questo modo è possibile effettuare una chiamata ad
+\func{mmap} sul file descriptor restituito da \func{shm\_open} ed i processi
+vedranno lo stesso segmento di memoria condivisa.
+
+Quando il nome non esiste si può creare un nuovo segmento specificando
+\const{O\_CREAT}; in tal caso il segmento avrà (così come i nuovi file)
+lunghezza nulla. Il nuovo segmento verrà creato con i permessi indicati
+da \param{mode} (di cui vengono usati solo i 9 bit meno significativi, non si
+applicano pertanto i permessi speciali di sez.~\ref{sec:file_special_perm})
+filtrati dal valore dell'\textit{umask} del processo. Come gruppo ed utente
+proprietario del segmento saranno presi quelli facenti parte del gruppo
+\textit{effective} del processo chiamante.
+
+Dato che un segmento di lunghezza nulla è di scarsa utilità, una vola che lo
+si è creato per impostarne la dimensione si dovrà poi usare \func{ftruncate}
+(vedi sez.~\ref{sec:file_file_size}) prima di mapparlo in memoria con
+\func{mmap}. Si tenga presente che una volta chiamata \func{mmap} si può
+chiudere il file descriptor ad esso associato (semplicemente con
+\func{close}), senza che la mappatura ne risenta, e che questa può essere
+rimossa usando \func{munmap}.
+
+Come per i file, quando si vuole rimuovere completamente un segmento di
+memoria condivisa occorre usare la funzione \funcd{shm\_unlink}, il cui
+prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/mman.h}
+\fdecl{int shm\_unlink(const char *name)}
+
+\fdesc{Rimuove un segmento di memoria condivisa.}
+}
+
+{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{EACCES}] non si è proprietari del segmento.
+ \end{errlist}
+ ed inoltre \errval{ENAMETOOLONG} e \errval{ENOENT}, nel loro significato
+ generico.
+}
+\end{funcproto}
+
+La funzione è del tutto analoga ad \func{unlink}, e si limita a cancellare il
+nome del segmento da \file{/dev/shm}, senza nessun effetto né sui file
+descriptor precedentemente aperti con \func{shm\_open}, né sui segmenti già
+mappati in memoria; questi verranno cancellati automaticamente dal sistema
+solo con le rispettive chiamate a \func{close} e \func{munmap}. Una volta
+eseguita questa funzione però, qualora si richieda l'apertura di un segmento
+con lo stesso nome, la chiamata a \func{shm\_open} fallirà, a meno di non aver
+usato \const{O\_CREAT}, in quest'ultimo caso comunque si otterrà un file
+descriptor che fa riferimento ad un segmento distinto da eventuali precedenti.
+
+Dato che i segmenti di memoria condivisa sono trattati come file del
+filesystem \texttt{tmpfs}, si possono usare su di essi, con lo stesso
+significato che assumono sui file ordinari, anche funzioni come quelle delle
+famiglie \func{fstat}, \func{fchown} e \func{fchmod}. Inoltre a partire dal
+kernel 2.6.19 per i permessi sono supportate anche le ACL illustrate in
+sez.~\ref{sec:file_ACL}.
+
+Come esempio dell'uso delle funzioni attinenti ai segmenti di memoria
+condivisa POSIX, vediamo come è possibile riscrivere una interfaccia
+semplificata analoga a quella vista in fig.~\ref{fig:ipc_sysv_shm_func} per la
+memoria condivisa in stile SysV. Il codice completo, di cui si sono riportate
+le parti essenziali in fig.~\ref{fig:ipc_posix_shmmem}, è contenuto nel file
+\file{SharedMem.c} dei sorgenti allegati.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/MemShared.c}
+ \end{minipage}
+ \normalsize
+ \caption{Il codice delle funzioni di gestione dei segmenti di memoria
+ condivisa POSIX.}
+ \label{fig:ipc_posix_shmmem}
+\end{figure}
+
+La prima funzione (\texttt{\small 1-24}) è \func{CreateShm} che, dato un nome
+nell'argomento \var{name} crea un nuovo segmento di memoria condivisa,
+accessibile in lettura e scrittura, e ne restituisce l'indirizzo. Anzitutto si
+definiscono (\texttt{\small 8}) i flag per la successiva (\texttt{\small 9})
+chiamata a \func{shm\_open}, che apre il segmento in lettura e scrittura
+(creandolo se non esiste, ed uscendo in caso contrario) assegnandogli sul
+filesystem i permessi specificati dall'argomento \var{perm}.
+
+In caso di errore (\texttt{\small 10-12}) si restituisce un puntatore nullo,
+altrimenti si prosegue impostando (\texttt{\small 14}) la dimensione del
+segmento con \func{ftruncate}. Di nuovo (\texttt{\small 15-16}) si esce
+immediatamente restituendo un puntatore nullo in caso di errore. Poi si passa
+(\texttt{\small 18}) a mappare in memoria il segmento con \func{mmap}
+specificando dei diritti di accesso corrispondenti alla modalità di apertura.
+Di nuovo si restituisce (\texttt{\small 19-21}) un puntatore nullo in caso di
+errore, altrimenti si inizializza (\texttt{\small 22}) il contenuto del
+segmento al valore specificato dall'argomento \var{fill} con \func{memset}, e
+se ne restituisce (\texttt{\small 23}) l'indirizzo.
+
+La seconda funzione (\texttt{\small 25-40}) è \func{FindShm} che trova un
+segmento di memoria condiviso esistente, restituendone l'indirizzo. In questo
+caso si apre (\texttt{\small 31}) il segmento con \func{shm\_open} richiedendo
+che il segmento sia già esistente, in caso di errore (\texttt{\small 31-33})
+si ritorna immediatamente un puntatore nullo. Ottenuto il file descriptor del
+segmento lo si mappa (\texttt{\small 35}) in memoria con \func{mmap},
+restituendo (\texttt{\small 36-38}) un puntatore nullo in caso di errore, o
+l'indirizzo (\texttt{\small 39}) dello stesso in caso di successo.
+
+La terza funzione (\texttt{\small 40-45}) è \func{RemoveShm}, e serve a
+cancellare un segmento di memoria condivisa. Dato che al contrario di quanto
+avveniva con i segmenti del \textit{SysV-IPC} gli oggetti allocati nel kernel
+vengono rilasciati automaticamente quando nessuna li usa più, tutto quello che
+c'è da fare (\texttt{\small 44}) in questo caso è chiamare \func{shm\_unlink},
+restituendo al chiamante il valore di ritorno.
+
+
+
+
+\subsection{Semafori}
+\label{sec:ipc_posix_sem}
+
+Fino alla serie 2.4.x del kernel esisteva solo una implementazione parziale
+dei semafori POSIX che li realizzava solo a livello di \itindex{thread}
+\textit{thread} e non di processi,\footnote{questo significava che i semafori
+ erano visibili solo all'interno dei \itindex{thread} \textit{thread} creati
+ da un singolo processo, e non potevano essere usati come meccanismo di
+ sincronizzazione fra processi diversi.} fornita attraverso la sezione delle
+estensioni \textit{real-time} della \acr{glibc} (quelle che si accedono
+collegandosi alla libreria \texttt{librt}). Esisteva inoltre una libreria che
+realizzava (parzialmente) l'interfaccia POSIX usando le funzioni dei semafori
+di \textit{SysV-IPC} (mantenendo così tutti i problemi sottolineati in
+sez.~\ref{sec:ipc_sysv_sem}).
+
+A partire dal kernel 2.5.7 è stato introdotto un meccanismo di
+sincronizzazione completamente nuovo, basato sui cosiddetti \textit{futex} (la
+sigla sta per \textit{fast user mode mutex}) con il quale è stato possibile
+implementare una versione nativa dei semafori POSIX. Grazie a questo con i
+kernel della serie 2.6 e le nuove versioni della \acr{glibc} che usano questa
+nuova infrastruttura per quella che viene che viene chiamata \textit{New Posix
+ Thread Library}, sono state implementate anche tutte le funzioni
+dell'interfaccia dei semafori POSIX.
+
+Anche in questo caso è necessario appoggiarsi alla libreria per le estensioni
+\textit{real-time} \texttt{librt}, questo significa che se si vuole utilizzare
+questa interfaccia, oltre ad utilizzare gli opportuni file di definizione,
+occorrerà compilare i programmi con l'opzione \texttt{-lrt} o con
+\texttt{-lpthread} se si usano questi ultimi.
+
+La funzione che permette di creare un nuovo semaforo POSIX, creando il
+relativo file, o di accedere ad uno esistente, è \funcd{sem\_open}, questa
+prevede due forme diverse a seconda che sia utilizzata per aprire un semaforo
+esistente o per crearne uno nuovi, i relativi prototipi sono:
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fhead{sys/stat.h}
+\fhead{fcntl.h}
+\fdecl{sem\_t *sem\_open(const char *name, int oflag)}
+\fdecl{sem\_t *sem\_open(const char *name, int oflag, mode\_t mode,
+ unsigned int value)}
+
+\fdesc{Crea un semaforo o ne apre uno esistente.}
+}
+{La funzione ritorna l'indirizzo del semaforo in caso di successo e
+ \const{SEM\_FAILED} per un errore, nel qual caso \var{errno} assumerà uno
+ dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] il semaforo esiste ma non si hanno permessi
+ sufficienti per accedervi.
+ \item[\errcode{EEXIST}] si sono specificati \const{O\_CREAT} e
+ \const{O\_EXCL} ma il semaforo esiste.
+ \item[\errcode{EINVAL}] il valore di \param{value} eccede
+ \const{SEM\_VALUE\_MAX} o il nome è solo ``\texttt{/}''.
+ \item[\errcode{ENAMETOOLONG}] si è utilizzato un nome troppo lungo.
+ \item[\errcode{ENOENT}] non si è usato \const{O\_CREAT} ed il nome
+ specificato non esiste.
+ \end{errlist}
+ ed inoltre \errval{EMFILE}, \errval{ENFILE} ed \errval{ENOMEM} nel loro
+ significato generico.
+
+}
+\end{funcproto}
+
+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 nella stessa forma utilizzata
+per i segmenti di memoria condivisa, con un nome che inizia con ``\texttt{/}''
+e senza ulteriori ``\texttt{/}'', vale a dire nella forma
+\texttt{/nome-semaforo}.
+
+Con Linux i file associati ai semafori sono mantenuti nel filesystem virtuale
+\texttt{/dev/shm}, e gli viene assegnato automaticamente un nome nella forma
+\texttt{sem.nome-semaforo}, si ha cioè una corrispondenza per cui
+\texttt{/nome-semaforo} viene rimappato, nella creazione tramite
+\func{sem\_open}, su \texttt{/dev/shm/sem.nome-semaforo}. Per questo motivo la
+dimensione massima per il nome di un semaforo, a differenza di quanto avviene
+per i segmenti di memoria condivisa, è pari a \const{NAME\_MAX}$ - 4$.
+
+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_close} sono utilizzati soltanto
+\const{O\_CREAT} e \const{O\_EXCL}.
+
+Se si usa \const{O\_CREAT} si richiede la creazione del semaforo qualora
+questo non esista, ed in tal caso occorre utilizzare la seconda forma della
+funzione, in cui si devono specificare sia un valore iniziale con l'argomento
+\param{value},\footnote{e si noti come così diventa possibile, differenza di
+ quanto avviene per i semafori del \textit{SysV-IPC}, effettuare in maniera
+ atomica creazione ed inizializzazione di un semaforo usando una unica
+ funzione.} che una maschera dei permessi con l'argomento
+\param{mode}; se il semaforo esiste già questi saranno semplicemente
+ignorati. Usando il flag \const{O\_EXCL} si richiede invece la verifica che il
+semaforo non esista, ed usandolo insieme ad \const{O\_CREAT} la funzione
+fallisce qualora un semaforo con lo stesso nome sia già presente.
+
+Si tenga presente che, come accennato in sez.~\ref{sec:ipc_posix_generic}, i
+semafori usano la semantica standard dei file per quanto riguarda i controlli
+di accesso, questo significa che un nuovo semaforo viene sempre creato con
+l'\ids{UID} ed il \ids{GID} effettivo del processo chiamante, e che i permessi
+indicati con \param{mode} vengono filtrati dal valore della \itindex{umask}
+\textit{umask} del processo. Inoltre per poter aprire un semaforo è
+necessario avere su di esso sia il permesso di lettura che quello di
+scrittura.
+
+La funzione restituisce in caso di successo un puntatore all'indirizzo del
+semaforo con un valore di tipo \ctyp{sem\_t *}, è questo valore che dovrà
+essere passato alle altre funzioni per operare sul semaforo stesso, e non sarà
+più necessario fare riferimento al nome, che potrebbe anche essere rimosso con
+\func{sem\_unlink}.
+
+Una volta che si sia ottenuto l'indirizzo di un semaforo, sarà possibile
+utilizzarlo; se si ricorda quanto detto all'inizio di
+sez.~\ref{sec:ipc_sysv_sem}, dove si sono introdotti i concetti generali
+relativi ai semafori, le operazioni principali sono due, quella che richiede
+l'uso di una risorsa bloccando il semaforo e quella che rilascia la risorsa
+liberando il semaforo. La prima operazione è effettuata dalla funzione
+\funcd{sem\_wait}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_wait(sem\_t *sem)}
+
+\fdesc{Blocca un semaforo.}
+}
+
+{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{EINTR}] la funzione è stata interrotta da un segnale.
+ \item[\errcode{EINVAL}] il semaforo \param{sem} non esiste.
+ \end{errlist}
+}
+\end{funcproto}
+
+La funzione cerca di decrementare il valore del semaforo indicato dal
+puntatore \param{sem}, se questo ha un valore positivo, cosa che significa che
+la risorsa è disponibile, la funzione ha successo, il valore del semaforo
+viene diminuito di 1 ed essa ritorna immediatamente consentendo la
+prosecuzione del processo.
+
+Se invece il valore è nullo la funzione si blocca (fermando l'esecuzione del
+processo) fintanto che il valore del semaforo non ritorna positivo (cosa che a
+questo punto può avvenire solo per opera di altro processo che rilascia il
+semaforo con una chiamata a \func{sem\_post}) così che poi essa possa
+decrementarlo con successo e proseguire.
+
+Si tenga presente che la funzione può sempre essere interrotta da un segnale,
+nel qual caso si avrà un errore di \const{EINTR}; inoltre questo avverrà
+comunque, anche qualora si fosse richiesta la gestione con la semantica BSD,
+installando il gestore del suddetto segnale con l'opzione \const{SA\_RESTART}
+(vedi sez.~\ref{sec:sig_sigaction}) per riavviare le \textit{system call}
+interrotte.
+
+Della funzione \func{sem\_wait} esistono due varianti che consentono di
+gestire diversamente le modalità di attesa in caso di risorsa occupata, la
+prima di queste è \funcd{sem\_trywait}, che serve ad effettuare un tentativo
+di acquisizione senza bloccarsi; il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_trywait(sem\_t *sem)}
+
+\fdesc{Tenta di bloccare un semaforo.}
+}
+{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{EAGAIN}] il semaforo non può essere acquisito senza
+ bloccarsi.
+ \item[\errcode{EINVAL}] l'argomento \param{sem} non indica un semaforo
+ valido.
+ \end{errlist}
+}
+\end{funcproto}
+
+La funzione è identica a \func{sem\_wait} ed se la risorsa è libera ha lo
+stesso effetto, vale a dire che in caso di semaforo diverso da zero la
+funzione lo decrementa e ritorna immediatamente; la differenza è che nel caso
+in cui il semaforo è occupato essa non si blocca e di nuovo ritorna
+immediatamente, restituendo però un errore di \errval{EAGAIN}, così che il
+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 almeno 600 o la macro \macro{\_POSIX\_C\_SOURCE} ad un valore
+uguale o maggiore di \texttt{200112L} prima di includere
+\headfiled{semaphore.h}, la funzione è \funcd{sem\_timedwait}, ed il suo
+prototipo è:
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_timedwait(sem\_t *sem, const struct timespec
+ *abs\_timeout)}
+
+\fdesc{Blocca un semaforo.}
+}
+
+{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{EINTR}] la funzione è stata interrotta da un segnale.
+ \item[\errcode{EINVAL}] l'argomento \param{sem} non indica un semaforo
+ valido.
+ \item[\errcode{ETIMEDOUT}] è scaduto il tempo massimo di attesa.
+ \end{errlist}
+}
+\end{funcproto}
+
+Anche in questo caso il comportamento della funzione è identico a quello di
+\func{sem\_wait}, ma è possibile impostare un tempo limite per l'attesa
+tramite la struttura \struct{timespec} (vedi
+fig.~\ref{fig:sys_timespec_struct}) puntata
+dall'argomento \param{abs\_timeout}, indicato in secondi e nanosecondi a
+partire dalla cosiddetta \textit{Epoch} (00:00:00, 1 January 1970
+UTC). Scaduto il limite la funzione ritorna anche se non è possibile acquisire
+il semaforo fallendo con un errore di \errval{ETIMEDOUT}.
+
+La seconda funzione principale utilizzata per l'uso dei semafori è quella che
+viene usata per rilasciare un semaforo occupato o, in generale, per aumentare
+di una unità il valore dello stesso anche qualora non fosse occupato (si
+ricordi che in generale un semaforo viene usato come indicatore di un numero
+di risorse disponibili). Detta funzione è \funcd{sem\_post} ed il suo
+prototipo è:
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_post(sem\_t *sem)}
+
+\fdesc{Rilascia un semaforo.}
+}
+
+{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}] l'argomento \param{sem} non indica un semaforo
+ valido.
+ \item[\errcode{EOVERFLOW}] si superato il massimo valore di un semaforo.
+ \end{errlist}
+}
+\end{funcproto}
+
+La funzione incrementa di uno il valore corrente del semaforo indicato
+dall'argomento \param{sem}, se questo era nullo la relativa risorsa risulterà
+sbloccata, cosicché un altro processo (o \itindex{thread} \textit{thread})
+eventualmente bloccato in una \func{sem\_wait} sul semaforo possa essere
+svegliato e rimesso in esecuzione. Si tenga presente che la funzione è sicura
+per l'uso all'interno di un gestore di segnali (si ricordi quanto detto in
+sez.~\ref{sec:sig_signal_handler}).
+
+Se invece di operare su un semaforo se ne volesse semplicemente leggere il
+valore, si potrà usare la funzione \funcd{sem\_getvalue}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_getvalue(sem\_t *sem, int *sval)}
+
+\fdesc{Richiede il valore di un semaforo.}
+}
+{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}] l'argomento \param{sem} non indica un semaforo
+ valido.
+ \end{errlist}
+}
+\end{funcproto}
+
+La funzione legge il valore del semaforo indicato dall'argomento \param{sem} e
+lo restituisce nella variabile intera puntata dall'argomento
+\param{sval}. Qualora ci siano uno o più processi bloccati in attesa sul
+semaforo lo standard prevede che la funzione possa restituire un valore nullo
+oppure il numero di processi bloccati in una \func{sem\_wait} sul suddetto
+semaforo; nel caso di Linux vale la prima opzione.
+
+Questa funzione può essere utilizzata per avere un suggerimento sullo stato di
+un semaforo, ovviamente non si può prendere il risultato riportato in
+\param{sval} che come indicazione, il valore del semaforo infatti potrebbe
+essere già stato modificato al ritorno della funzione.
+
+% TODO verificare comportamento sem_getvalue
+
+Una volta che non ci sia più la necessità di operare su un semaforo se ne può
+terminare l'uso con la funzione \funcd{sem\_close}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_close(sem\_t *sem)}
+
+\fdesc{Chiude un semaforo.}
+}
+
+{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}] l'argomento \param{sem} non indica un semaforo
+ valido.
+ \end{errlist}
+}
+\end{funcproto}
+
+La funzione chiude il semaforo indicato dall'argomento \param{sem}, che non
+potrà più essere utilizzato nelle altre funzioni. La chiusura comporta anche
+che tutte le risorse che il sistema poteva avere assegnato al processo
+nell'uso del semaforo vengono immediatamente rilasciate. Questo significa che
+un eventuale altro processo bloccato sul semaforo a causa della acquisizione
+dello stesso da parte del processo che chiama \func{sem\_close} potrà essere
+immediatamente riavviato.
+
+Si tenga presente poi che come avviene per i file, all'uscita di un processo
+anche tutti i semafori che questo aveva aperto vengono automaticamente chiusi.
+Questo comportamento risolve il problema che si aveva con i semafori del
+\textit{SysV IPC} (di cui si è parlato in sez.~\ref{sec:ipc_sysv_sem}) per i
+quali le risorse possono restare bloccate. Si tenga infine presente che, a
+differenza di quanto avviene per i file, in caso di una chiamata ad
+\func{execve} tutti i semafori vengono chiusi automaticamente.
+
+Come per i semafori del \textit{SysV-IPC} anche quelli POSIX hanno una
+persistenza di sistema; questo significa che una volta che si è creato un
+semaforo con \func{sem\_open} questo continuerà ad esistere fintanto che il
+kernel resta attivo (vale a dire fino ad un successivo riavvio) a meno che non
+lo si cancelli esplicitamente. Per far questo si può utilizzare la funzione
+\funcd{sem\_unlink}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_unlink(const char *name)}
+
+\fdesc{Rimuove un semaforo.}
+}
+
+{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{EACCES}] non si hanno i permessi necessari a cancellare il
+ semaforo.
+ \item[\errcode{ENAMETOOLONG}] il nome indicato è troppo lungo.
+ \item[\errcode{ENOENT}] il semaforo \param{name} non esiste.
+ \end{errlist}
+}
+\end{funcproto}
+
+La funzione rimuove il semaforo indicato dall'argomento \param{name}, che
+prende un valore identico a quello usato per creare il semaforo stesso con
+\func{sem\_open}. Il semaforo viene rimosso dal filesystem immediatamente; ma
+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:link_symlink_rename}.
+
+Una delle caratteristiche peculiari dei semafori POSIX è che questi possono
+anche essere utilizzati anche in forma anonima, senza necessità di fare
+ricorso ad un nome sul filesystem o ad altri indicativi. In questo caso si
+dovrà porre la variabile che contiene l'indirizzo del semaforo in un tratto di
+memoria che sia accessibile a tutti i processi in gioco. La funzione che
+consente di inizializzare un semaforo anonimo è \funcd{sem\_init}, il cui
+prototipo è:
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_init(sem\_t *sem, int pshared, unsigned int value)}
+\fdesc{Inizializza un semaforo anonimo.}
+}
+
+{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{value} eccede
+ \const{SEM\_VALUE\_MAX}.
+ \item[\errcode{ENOSYS}] il valore di \param{pshared} non è nullo ed il
+ sistema non supporta i semafori per i processi.
+ \end{errlist}
+}
+\end{funcproto}
+
+La funzione inizializza un semaforo all'indirizzo puntato dall'argomento
+\param{sem}, e come per \func{sem\_open} consente di impostare un valore
+iniziale con \param{value}. L'argomento \param{pshared} serve ad indicare se
+il semaforo deve essere utilizzato dai \itindex{thread} \textit{thread} di uno
+stesso processo (con un valore nullo) o condiviso fra processi diversi (con un
+valore non nullo).
+
+Qualora il semaforo debba essere condiviso dai \textit{thread} di uno stesso
+processo (nel qual caso si parla di \textit{thread-shared semaphore}),
+occorrerà che \param{sem} sia l'indirizzo di una variabile visibile da tutti i
+\textit{thread}, si dovrà usare cioè una variabile globale o una variabile
+allocata dinamicamente nello \textit{heap}.
+
+Qualora il semaforo debba essere condiviso fra più processi (nel qual caso si
+parla di \textit{process-shared semaphore}) la sola scelta possibile per
+renderlo visibile a tutti è di porlo in un tratto di memoria condivisa. Questo
+potrà essere ottenuto direttamente sia con \func{shmget} (vedi
+sez.~\ref{sec:ipc_sysv_shm}) che con \func{shm\_open} (vedi
+sez.~\ref{sec:ipc_posix_shm}), oppure, nel caso che tutti i processi in gioco
+abbiano un genitore comune, con una mappatura anonima con \func{mmap} (vedi
+sez.~\ref{sec:file_memory_map}) a cui essi poi potranno accedere (si ricordi
+che i tratti di memoria condivisa vengono mantenuti nei processi figli
+attraverso la funzione \func{fork}).
+
+Una volta inizializzato il semaforo anonimo con \func{sem\_init} lo si potrà
+utilizzare nello stesso modo dei semafori normali con \func{sem\_wait} e
+\func{sem\_post}. Si tenga presente però che inizializzare due volte lo stesso
+semaforo può dar luogo ad un comportamento indefinito.
+
+Qualora non si intenda più utilizzare un semaforo anonimo questo può essere
+eliminato dal sistema; per far questo di deve utilizzare una apposita
+funzione, \funcd{sem\_destroy}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{semaphore.h}
+\fdecl{int sem\_destroy(sem\_t *sem)}
+\fdesc{Elimina un semaforo anonimo.}
+}
+{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}] l'argomento \param{sem} non indica un semaforo
+ valido.
+ \end{errlist}
+}
+\end{funcproto}
+
+La funzione prende come unico argomento l'indirizzo di un semaforo che deve
+essere stato inizializzato con \func{sem\_init}; non deve quindi essere
+applicata a semafori creati con \func{sem\_open}. Inoltre si deve essere
+sicuri che il semaforo sia effettivamente inutilizzato, la distruzione di un
+semaforo su cui sono presenti processi (o \itindex{thread} \textit{thread}) in
+attesa (cioè bloccati in una \func{sem\_wait}) provoca un comportamento
+indefinito.
+
+Si tenga presente infine che utilizzare un semaforo che è stato distrutto con
+\func{sem\_destroy} di nuovo può dare esito a comportamenti indefiniti. Nel
+caso ci si trovi in una tale evenienza occorre reinizializzare il semaforo una
+seconda volta con \func{sem\_init}.
+
+Come esempio di uso sia della memoria condivisa che dei semafori POSIX si sono
+scritti due semplici programmi con i quali è possibile rispettivamente
+monitorare il contenuto di un segmento di memoria condivisa e modificarne il
+contenuto.
+
+\begin{figure}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/message_getter.c}
+ \end{minipage}
+ \normalsize
+ \caption{Sezione principale del codice del programma
+ \file{message\_getter.c}.}
+ \label{fig:ipc_posix_sem_shm_message_server}
+\end{figure}
+
+Il corpo principale del primo dei due, il cui codice completo è nel file
+\file{message\_getter.c} dei sorgenti allegati, è riportato in
+fig.~\ref{fig:ipc_posix_sem_shm_message_server}; si è tralasciata la parte che
+tratta la gestione delle opzioni a riga di comando (che consentono di
+impostare un nome diverso per il semaforo e il segmento di memoria condivisa)
+ed il controllo che al programma venga fornito almeno un argomento, contenente
+la stringa iniziale da inserire nel segmento di memoria condivisa.
+
+Lo scopo del programma è quello di creare un segmento di memoria condivisa su
+cui registrare una stringa, e tenerlo sotto osservazione stampando la stessa
+una volta al secondo. Si utilizzerà un semaforo per proteggere l'accesso in
+lettura alla stringa, in modo che questa non possa essere modificata
+dall'altro programma prima di averla finita di stampare.
+
+La parte iniziale del programma contiene le definizioni (\texttt{\small 1-8})
+del gestore del segnale usato per liberare le risorse utilizzate, delle
+variabili globali contenenti i nomi di default del segmento di memoria
+condivisa e del semaforo (il default scelto è \texttt{messages}), e delle
+altre variabili utilizzate dal programma.
+
+Come prima istruzione (\texttt{\small 10}) si è provveduto ad installare un
+gestore di segnale che consentirà di effettuare le operazioni di pulizia
+(usando la funzione \func{Signal} illustrata in
+fig.~\ref{fig:sig_Signal_code}), dopo di che (\texttt{\small 12-16}) si è
+creato il segmento di memoria condivisa con la funzione \func{CreateShm} che
+abbiamo appena trattato in sez.~\ref{sec:ipc_posix_shm}, uscendo con un
+messaggio in caso di errore.
+
+Si tenga presente che la funzione \func{CreateShm} richiede che il segmento
+non sia già presente e fallirà qualora un'altra istanza, o un altro programma
+abbia già allocato un segmento con quello stesso nome. Per semplicità di
+gestione si è usata una dimensione fissa pari a 256 byte, definita tramite la
+costante \texttt{MSGMAXSIZE}.
+
+Il passo successivo (\texttt{\small 17-21}) è quello della creazione del
+semaforo che regola l'accesso al segmento di memoria condivisa con
+\func{sem\_open}; anche in questo caso si gestisce l'uscita con stampa di un
+messaggio in caso di errore. Anche per il semaforo, avendo specificato la
+combinazione di flag \code{O\_CREAT|O\_EXCL} come secondo argomento, si esce
+qualora fosse già esistente; altrimenti esso verrà creato con gli opportuni
+permessi specificati dal terzo argomento, (indicante lettura e scrittura in
+notazione ottale). Infine il semaforo verrà inizializzato ad un valore nullo
+(il quarto argomento), corrispondete allo stato in cui risulta bloccato.
+
+A questo punto (\texttt{\small 22}) si potrà inizializzare il messaggio posto
+nel segmento di memoria condivisa usando la stringa passata come argomento al
+programma. Essendo il semaforo stato creato già bloccato non ci si dovrà
+preoccupare di eventuali \textit{race condition} qualora il programma di
+modifica del messaggio venisse lanciato proprio in questo momento. Una volta
+inizializzato il messaggio occorrerà però rilasciare il semaforo
+(\texttt{\small 24-27}) per consentirne l'uso; in tutte queste operazioni si
+provvederà ad uscire dal programma con un opportuno messaggio in caso di
+errore.
+
+Una volta completate le inizializzazioni il ciclo principale del programma
+(\texttt{\small 29-47}) viene ripetuto indefinitamente (\texttt{\small 29})
+per stampare sia il contenuto del messaggio che una serie di informazioni di
+controllo. Il primo passo (\texttt{\small 30-34}) è quello di acquisire (con
+\func{sem\_getvalue}, con uscita in caso di errore) e stampare il valore del
+semaforo ad inizio del ciclo; seguito (\texttt{\small 35-36}) dal tempo
+corrente.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/HandSigInt.c}
+ \end{minipage}
+ \normalsize
+ \caption{Codice del gestore di segnale del programma
+ \file{message\_getter.c}.}
+ \label{fig:ipc_posix_sem_shm_message_server_handler}
+\end{figure}
+
+Prima della stampa del messaggio invece si deve acquisire il semaforo
+(\texttt{\small 30-33}) per evitare accessi concorrenti alla stringa da parte
+del programma di modifica. Una volta eseguita la stampa (\texttt{\small 41})
+il semaforo dovrà essere rilasciato (\texttt{\small 42-45}). Il passo finale
+(\texttt{\small 46}) è attendere per un secondo prima di eseguire da capo il
+ciclo.
+
+Per uscire in maniera corretta dal programma sarà necessario fermarlo con una
+interruzione da tastiera (\texttt{C-c}), che corrisponde all'invio del segnale
+\signal{SIGINT}, per il quale si è installato (\texttt{\small 10}) una
+opportuna funzione di gestione, riportata in
+fig.~\ref{fig:ipc_posix_sem_shm_message_server_handler}. La funzione è molto
+semplice e richiama le funzioni di rimozione sia per il segmento di memoria
+condivisa che per il semaforo, garantendo così che possa essere riaperto
+ex-novo senza errori in un futuro riutilizzo del comando.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/message_setter.c}
+ \end{minipage}
+ \normalsize
+ \caption{Sezione principale del codice del programma
+ \file{message\_setter.c}.}
+ \label{fig:ipc_posix_sem_shm_message_setter}
+\end{figure}
+
+Il secondo programma di esempio è \file{message\_setter.c}, di cui si è
+riportato il corpo principale in
+fig.~\ref{fig:ipc_posix_sem_shm_message_setter},\footnote{al solito il codice
+ completo è nel file dei sorgenti allegati.} dove si è tralasciata, non
+essendo significativa per quanto si sta trattando, la parte relativa alla
+gestione delle opzioni a riga di comando e degli argomenti, che sono identici
+a quelli usati da \file{message\_getter}, con l'unica aggiunta di un'opzione
+``\texttt{-t}'' che consente di indicare un tempo di attesa (in secondi) in
+cui il programma si ferma tenendo bloccato il semaforo.
+
+Una volta completata la gestione delle opzioni e degli argomenti (ne deve
+essere presente uno solo, contenente la nuova stringa da usare come
+messaggio), il programma procede (\texttt{\small 10-14}) con l'acquisizione
+del segmento di memoria condivisa usando la funzione \func{FindShm} (trattata
+in sez.~\ref{sec:ipc_posix_shm}) che stavolta deve già esistere. Il passo
+successivo (\texttt{\small 16-19}) è quello di aprire il semaforo, e a
+differenza di \file{message\_getter}, in questo caso si richiede a
+\func{sem\_open} che questo esista, passando uno zero come secondo ed unico
+argomento.
+
+Una volta completate con successo le precedenti inizializzazioni, il passo
+seguente (\texttt{\small 21-24}) è quello di acquisire il semaforo, dopo di
+che sarà possibile eseguire la sostituzione del messaggio (\texttt{\small 25})
+senza incorrere in possibili \textit{race condition} con la stampa dello
+stesso da parte di \file{message\_getter}.
+
+Una volta effettuata la modifica viene stampato (\texttt{\small 26}) il tempo
+di attesa impostato con l'opzione ``\texttt{-t}'' dopo di che (\texttt{\small
+ 27}) viene eseguita la stessa, senza rilasciare il semaforo che resterà
+quindi bloccato (causando a questo punto una interruzione delle stampe
+eseguite da \file{message\_getter}). Terminato il tempo di attesa si rilascerà
+(\texttt{\small 29-32}) il semaforo per poi uscire.
+
+Per verificare il funzionamento dei programmi occorrerà lanciare per primo
+\file{message\_getter}\footnote{lanciare per primo \file{message\_setter} darà
+ luogo ad un errore, non essendo stati creati il semaforo ed il segmento di
+ memoria condivisa.} che inizierà a stampare una volta al secondo il
+contenuto del messaggio ed i suoi dati, con qualcosa del tipo:
+\begin{Console}
+piccardi@hain:~/gapil/sources$ \textbf{./message_getter messaggio}
+sem=1, Fri Dec 31 14:12:41 2010
+message: messaggio
+sem=1, Fri Dec 31 14:12:42 2010
+message: messaggio
+...
+\end{Console}
+%$
+proseguendo indefinitamente fintanto che non si prema \texttt{C-c} per farlo
+uscire. Si noti come il valore del semaforo risulti sempre pari ad 1 (in
+quanto al momento esso sarà sempre libero).
+
+A questo punto si potrà lanciare \file{message\_setter} per cambiare il
+messaggio, nel nostro caso per rendere evidente il funzionamento del blocco
+richiederemo anche una attesa di 3 secondi, ed otterremo qualcosa del tipo:
+\begin{Console}
+piccardi@hain:~/gapil/sources$ \textbf{./message_setter -t 3 ciao}
+Sleeping for 3 seconds
+\end{Console}
+%$
+dove il programma si fermerà per 3 secondi prima di rilasciare il semaforo e
+terminare.
+
+L'effetto di questo programma si potrà però apprezzare meglio nell'uscita di
+\file{message\_getter}, che verrà interrotta per questo stesso tempo, prima di
+ricominciare con il nuovo testo:
+\begin{Console}
+...
+sem=1, Fri Dec 31 14:16:27 2010
+message: messaggio
+sem=1, Fri Dec 31 14:16:28 2010
+message: messaggio
+sem=0, Fri Dec 31 14:16:29 2010
+message: ciao
+sem=1, Fri Dec 31 14:16:32 2010
+message: ciao
+sem=1, Fri Dec 31 14:16:33 2010
+message: ciao
+...
+\end{Console}
+%$
+
+E si noterà come nel momento in cui si lancia \file{message\_setter} le stampe
+di \file{message\_getter} si bloccheranno, come corretto, dopo aver registrato
+un valore nullo per il semaforo. Il programma infatti resterà bloccato nella
+\func{sem\_wait} (quella di riga (\texttt{\small 37}) in
+fig.~\ref{fig:ipc_posix_sem_shm_message_server}) fino alla scadenza
+dell'attesa di \file{message\_setter} (con l'esecuzione della \func{sem\_post}
+della riga (\texttt{\small 29}) di
+fig.~\ref{fig:ipc_posix_sem_shm_message_setter}), e riprenderanno con il nuovo
+testo alla terminazione di quest'ultimo.
+
+
+% LocalWords: like fifo System POSIX RPC Calls Common Object Request Brocker
+% LocalWords: Architecture descriptor kernel unistd int filedes errno EMFILE
+% LocalWords: ENFILE EFAULT BUF sez fig fork Stevens siblings EOF read SIGPIPE
+% LocalWords: EPIPE shell CGI Gateway Interface HTML JPEG URL mime type gs dup
+% LocalWords: barcode PostScript race condition stream BarCodePage WriteMess
+% LocalWords: size PS switch wait popen pclose stdio const char command NULL
+% LocalWords: EINVAL cap fully buffered Ghostscript l'Encapsulated epstopsf of
+% LocalWords: PDF EPS lseek ESPIPE PPM Portable PixMap format pnmcrop PNG pnm
+% LocalWords: pnmmargin png BarCode inode filesystem l'inode mknod mkfifo RDWR
+% LocalWords: ENXIO deadlock client reinviate fortunes fortunefilename daemon
+% LocalWords: FortuneServer FortuneParse FortuneClient pid libgapil LD librt
+% LocalWords: PATH linker pathname ps tmp killall fortuned crash socket domain
+% LocalWords: socketpair BSD sys protocol sv EAFNOSUPPORT EPROTONOSUPPORT AF
+% LocalWords: EOPNOTSUPP SOCK Process Comunication ipc perm key exec pipefd SZ
+% LocalWords: header ftok proj stat libc SunOS glibc XPG dell'inode number uid
+% LocalWords: cuid cgid gid tab MSG shift group umask seq MSGMNI SEMMNI SHMMNI
+% LocalWords: shmmni msgmni sem sysctl IPCMNI IPCTestId msgget EACCES EEXIST
+% LocalWords: CREAT EXCL EIDRM ENOENT ENOSPC ENOMEM novo proc MSGMAX msgmax ds
+% LocalWords: MSGMNB msgmnb linked list msqid msgid linux msg qnum lspid lrpid
+% LocalWords: rtime ctime qbytes first last cbytes msgctl semctl shmctl ioctl
+% LocalWords: cmd struct buf EPERM RMID msgsnd msgbuf msgp msgsz msgflg EAGAIN
+% LocalWords: NOWAIT EINTR mtype mtext long message sizeof LENGTH ts sleep BIG
+% LocalWords: msgrcv ssize msgtyp NOERROR EXCEPT ENOMSG multiplexing select ls
+% LocalWords: poll polling queue MQFortuneServer write init HandSIGTERM l'IPC
+% LocalWords: MQFortuneClient mqfortuned mutex risorse' inter semaphore semget
+% LocalWords: nsems SEMMNS SEMMSL semid otime semval sempid semncnt semzcnt nr
+% LocalWords: SEMVMX SEMOPM semop SEMMNU SEMUME SEMAEM semnum union semun arg
+% LocalWords: ERANGE SETALL SETVAL GETALL array GETNCNT GETPID GETVAL GETZCNT
+% LocalWords: sembuf sops unsigned nsops UNDO flg nsop num undo pending semadj
+% LocalWords: sleeper scheduler running next semundo MutexCreate semunion lock
+% LocalWords: MutexFind wrapper MutexRead MutexLock MutexUnlock unlock locking
+% LocalWords: MutexRemove shmget SHMALL SHMMAX SHMMIN shmid shm segsz atime FD
+% 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 ipcs NFS SETPIPE
+% 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
+% LocalWords: SHARED ANONYMOUS thread patch names strace system call userid Di
+% LocalWords: groupid Michal Wronski Krzysztof Benedyczak wrona posix mqueue
+% LocalWords: lmqueue gcc mount mqd name oflag attr maxmsg msgsize receive ptr
+% LocalWords: send WRONLY NONBLOCK close mqdes EBADF getattr setattr mqstat to
+% LocalWords: omqstat curmsgs flags timedsend len prio timespec abs EMSGSIZE
+% LocalWords: ETIMEDOUT timedreceive getaddr notify sigevent notification l'I
+% LocalWords: EBUSY sigev SIGNAL signo value sigval siginfo all'userid MESGQ
+% LocalWords: Konstantin Knizhnik futex tmpfs ramfs cache shared swap CONFIG
+% LocalWords: lrt blocks PAGECACHE TRUNC CLOEXEC mmap ftruncate munmap FindShm
+% LocalWords: CreateShm RemoveShm LIBRARY Library libmqueue FAILED has fclose
+% LocalWords: ENAMETOOLONG qualchenome RESTART trywait XOPEN SOURCE timedwait
+% LocalWords: process getvalue sval execve pshared ENOSYS heap PAGE destroy it
+% LocalWords: xffffffff Arrays owner perms Queues used bytes messages device
+% LocalWords: Cannot find such Segments getter Signal MSGMAXSIZE been stable
+% LocalWords: for now it's break Berlin sources Let's an accidental feature fs
+% LocalWords: Larry Wall Escape the Hell William ipctestid Identifier segment
+% LocalWords: violation dell'I SIGINT setter Fri Dec Sleeping seconds ECHILD
+% LocalWords: SysV capability short RESOURCE INFO UNDEFINED EFBIG semtimedop
+% LocalWords: scan HUGETLB huge page NORESERVE copy RLIMIT MEMLOCK REMAP UTC
+% LocalWords: readmon Hierarchy defaults queues MSGQUEUE effective fstat
+% LocalWords: fchown fchmod Epoch January
%%% Local Variables: