%% ipc.tex
%%
%% Copyright (C) 2000-2002 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 "Prefazione",
%% 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{La comunicazione fra processi}
\label{cha:IPC}


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
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.


\section{La comunicazione 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
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.


\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 \funcd{pipe}, ed il suo prototipo è:
\begin{prototype}{unistd.h}
{int pipe(int filedes[2])} 
  
Crea una coppia di file descriptor associati ad una \textit{pipe}.
  
  \bodydesc{La funzione restituisce zero in caso di successo e -1 per un
    errore, nel qual caso \var{errno} potrà assumere i valori \errval{EMFILE},
    \errval{ENFILE} e \errval{EFAULT}.}
\end{prototype}

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 \const{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]
  \centering
  \includegraphics[height=5cm]{img/pipe}
  \caption{Schema della struttura di una 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.

\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}.}
  \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 \errcode{EPIPE}, e la funzione di scrittura
restituirà un errore di \errcode{EPIPE} (al ritorno del gestore, o qualora il
segnale sia ignorato o bloccato).

La dimensione del buffer della pipe (\const{PIPE\_BUF}) ci dà inoltre un'altra
importante informazione riguardo il comportamento delle operazioni di lettura
e scrittura su di una pipe; esse infatti sono atomiche fintanto che la
quantità di dati da scrivere non supera questa dimensione. Qualora ad esempio
si effettui una scrittura di una quantità di dati superiore l'operazione verrà
effettuata in più riprese, consentendo l'intromissione di scritture effettuate
da altri processi.


\subsection{Un esempio dell'uso delle pipe}
\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.

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}
ed il risultato dell'elaborazione deve essere presentato (con una intestazione
che ne descrive il mime-type) sullo standard output, in modo che il web-server
possa reinviarlo al browser che ha effettuato la richiesta, che in questo modo
è in grado di visualizzarlo opportunamente.

Per realizzare quanto voluto useremo in sequenza i programmi \cmd{barcode} e
\cmd{gs}, il primo infatti è in grado di generare immagini PostScript di
codici a barre corrispondenti ad una qualunque stringa, mentre il secondo
serve per poter effettuare la conversione della stessa immagine in formato
JPEG. Usando una pipe potremo inviare l'output del primo sull'input del
secondo, secondo lo schema mostrato in \figref{fig:ipc_pipe_use}, in cui la
direzione del flusso dei dati è data dalle frecce continue.

\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.}
  \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\index{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
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.


\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}
  \end{minipage} 
  \normalsize 
  \caption{Sezione principale del codice del \textit{CGI} 
    \file{BarCodePage.c}.}
  \label{fig:ipc_barcodepage_code}
\end{figure}

La prima operazione del programma (\texttt{\small 4--12}) è quella di creare
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.

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}).

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.

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.

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.


\subsection{Le funzioni \func{popen} e \func{pclose}}
\label{sec:ipc_popen}

Come si è visto la modalità più comune di utilizzo di una pipe è quella di
utilizzarla per fare da tramite fra output ed input di due programmi invocati
in sequenza; per questo motivo lo standard POSIX.2 ha introdotto due funzioni
che permettono di sintetizzare queste operazioni. La prima di esse si chiama
\funcd{popen} ed il suo prototipo è:
\begin{prototype}{stdio.h}
{FILE *popen(const char *command, const char *type)}

Esegue il programma \param{command}, di cui, a seconda di \param{type},
restituisce, lo standard input o lo standard output nella pipe collegata allo
stream restituito come valore di ritorno.
  
\bodydesc{La funzione restituisce l'indirizzo dello stream associato alla pipe
  in caso di successo e \val{NULL} per un errore, nel qual caso \var{errno}
  potrà assumere i valori relativi alle sottostanti invocazioni di \func{pipe}
  e \func{fork} o \errcode{EINVAL} se \param{type} non è valido.}
\end{prototype}

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 \capref{cha:files_std_interface}, anche se è collegato ad una
pipe e non ad un inode\index{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, \funcd{pclose}, il cui prototipo è:
\begin{prototype}{stdio.h}
{int pclose(FILE *stream)}

Chiude il file \param{stream}, restituito da una precedente \func{popen}
attendendo la terminazione del processo ad essa associato.
  
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
  errore; nel quel caso il valore di \var{errno} deriva dalle sottostanti
  chiamate.}
\end{prototype}
\noindent che oltre alla chiusura dello stream si incarica anche di attendere
(tramite \func{wait4}) la conclusione del processo creato dalla precedente
\func{popen}.

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.

Se si vuole generare una immagine di dimensioni appropriate si deve usare un
approccio diverso. Una possibilità sarebbe quella di ricorrere ad ulteriore
programma, \cmd{epstopsf}, per convertire in PDF un file EPS (che può essere
generato da \cmd{barcode} utilizzando lo switch \cmd{-E}).  Utilizzando un PDF
al posto di un EPS \cmd{gs} esegue la conversione rispettando le dimensioni
originarie del codice a barre e produce un JPEG di dimensioni corrette.

Questo approccio però non funziona, per via di una delle caratteristiche
principali delle pipe. Per poter effettuare la conversione di un PDF infatti è
necessario, per la struttura del formato, potersi spostare (con \func{lseek})
all'interno del file da convertire; se si esegue la conversione con \cmd{gs}
su un file regolare non ci sono problemi, una pipe però è rigidamente
sequenziale, e l'uso di \func{lseek} su di essa fallisce sempre con un errore
di \errcode{ESPIPE}, rendendo impossibile la conversione.  Questo ci dice che
in generale la concatenazione di vari programmi funzionerà soltanto quando
tutti prevedono una lettura sequenziale del loro input.

Per questo motivo si è dovuto utilizzare un procedimento diverso, eseguendo
prima la conversione (sempre con \cmd{gs}) del PS in un altro formato
intermedio, il PPM,\footnote{il \textit{Portable PixMap file format} è un
  formato usato spesso come formato intermedio per effettuare conversioni, è
  infatti molto facile da manipolare, dato che usa caratteri ASCII per
  memorizzare le immagini, anche se per questo è estremamente inefficiente.}
dal quale poi si può ottenere un'immagine di dimensioni corrette attraverso
vari programmi di manipolazione (\cmd{pnmcrop}, \cmd{pnmmargin}) che può
essere infine trasformata in PNG (con \cmd{pnm2png}).

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
effettivamente eseguiti. Questo non comporta nessun problema dato che la
lettura su una pipe è bloccante, per cui ciascun processo, per quanto lanciato
per primo, si bloccherà in attesa di ricevere sullo standard input il
risultato dell'elaborazione del precedente, benchè quest'ultimo venga
invocato dopo.

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15cm}
    \begin{lstlisting}{}
int main(int argc, char *argv[], char *envp[])
{
    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 stdout */ 
    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}
  \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}.


\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\index{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\index{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 \errcode{ENXIO} fintanto che non verrà aperto il capo in lettura.

In Linux è possibile aprire le fifo anche in lettura/scrittura,\footnote{lo
  standard POSIX lascia indefinito il comportamento in questo caso.}
operazione che avrà sempre successo immediato qualunque sia la modalità di
apertura (bloccante e non bloccante); questo può essere utilizzato per aprire
comunque una fifo in scrittura anche se non ci sono ancora processi il
lettura; è possibile anche usare la fifo all'interno di un solo processo, nel
qual caso però occorre stare molto attenti alla possibili situazioni di
stallo.\footnote{se si cerca di leggere da una fifo che non contiene dati si
  avrà un deadlock\index{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 \const{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}
\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
``\textsl{nota}'', per le risposte non si può fare altrettanto, dato che, per
la struttura sequenziale delle fifo, i client dovrebbero sapere, prima di
leggerli, quando i dati inviati sono destinati a loro.

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]
  \centering
  \includegraphics[height=9cm]{img/fifoserver}
  \caption{Schema dell'utilizzo delle 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]
  \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}
  \end{minipage} 
  \normalsize 
  \caption{Sezione principale del codice del server di \textit{fortunes}
    basato sulle fifo.}
  \label{fig:ipc_fifo_server}
\end{figure}

Il server richiede (\texttt{\small 12}) che sia stata impostata una dimensione
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.

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
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 \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
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
principale del programma e le definizioni delle variabili. Il codice completo
è nel file \file{FortuneClient.c} dei sorgenti allegati.

\begin{figure}[!htb]
  \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}
  \end{minipage} 
  \normalsize 
  \caption{Sezione principale del codice del client di \textit{fortunes}
    basato sulle 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
(\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 \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
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
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 \const{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.



\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}\index{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 \funcd{socketpair} infatti consente di creare una coppia di file
descriptor connessi fra di loro (tramite un socket\index{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\index{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:
  \begin{errlist}
  \item[\errcode{EAFNOSUPPORT}] I socket\index{socket} locali non sono
    supportati.
  \item[\errcode{EPROTONOSUPPORT}] Il protocollo specificato non è supportato.
  \item[\errcode{EOPNOTSUPP}] Il protocollo specificato non supporta la
  creazione di coppie di socket\index{socket}.
  \end{errlist}
  ed inoltre \errval{EMFILE},  \errval{EFAULT}.
}
\end{functions}

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\index{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 \const{AF\_UNIX}, \const{SOCK\_STREAM} e \val{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\index{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 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}).


\section{La comunicazione 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.

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}).



\subsection{Considerazioni generali}
\label{sec:ipc_sysv_generic}

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
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 \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
  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.

\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}
  \end{minipage} 
  \normalsize 
  \caption{La struttura \structd{ipc\_perm}, come definita in
    \file{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 è
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
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 è
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
qualcun altro.  Dato che non esiste una convenzione su come assegnare queste
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{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}

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)}
con i 16 bit meno significativi dell'inode\index{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 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
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
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 \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
contatore di riferimenti per la cancellazione automatica, il principale
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}.


\subsection{Il controllo di accesso}
\label{sec:ipc_sysv_access_control}

Oltre alle chiavi, abbiamo visto 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 \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ù
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 \const{MSG\_R} (\texttt{0400}) e
  \const{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.

Quando l'oggetto viene creato i campi \var{cuid} e \var{uid} di
\struct{ipc\_perm} ed i campi \var{cgid} e \var{gid} vengono settati
rispettivamente al valore dell'user-ID e del group-ID 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
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.

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'user-ID 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 group-ID 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
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.


\subsection{Gli identificatori ed il loro utilizzo}
\label{sec:ipc_sysv_id_use}

L'unico campo di \struct{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
identificatori degli oggetti del sistema di IPC.

Quando il sistema si avvia, alla creazione di ogni nuovo oggetto di IPC viene
assegnato un numero progressivo, pari al numero di oggetti di quel tipo
esistenti. Se il comportamento fosse sempre questo sarebbe identico a quello
usato nell'assegnazione dei file descriptor nei processi, ed i valori degli
identificatori tenderebbero ad essere riutilizzati spesso e restare di piccole
dimensioni (inferiori al numero massimo di oggetti disponibili).

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
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
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{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,\footnote{fino
  al kernel 2.2.x questi valori, definiti dalle costanti \const{MSGMNI},
  \const{SEMMNI} e \const{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 \func{sysctl}.} 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 \const{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.

\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}
  \end{minipage} 
  \normalsize 
  \caption{Sezione principale del programma di test per l'assegnazione degli
    identificatori degli oggetti di IPC \file{IPCTestId.c}.}
  \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
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 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.


\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, ed il loro scopo principale è appunto
quello di permettere a processi diversi di scambiarsi dei dati.

La funzione che permette di richiedere al sistema l'identificatore di una coda
di messaggi esistente (o di crearne una se questa non esiste) è
\funcd{msgget}; 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:
  \begin{errlist}
  \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.
  \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[\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}.
}
\end{functions}

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
all'oggetto, eccetto il caso in cui si specifichi il valore
\const{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 \const{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
effettuare una ricerca sugli oggetti esistenti, restituendo l'identificatore
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ò
essere nullo e deve essere fornito come maschera binaria, impostando il bit
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 \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 \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{Significato} \\
    \hline
    \hline
    \const{MSGMNI}&   16& \file{msgmni} & Numero massimo di code di
                                          messaggi. \\
    \const{MSGMAX}& 8192& \file{msgmax} & Dimensione massima di un singolo
                                          messaggio.\\
    \const{MSGMNB}&16384& \file{msgmnb} & Dimensione massima del contenuto di 
                                          una coda.\\
    \hline
  \end{tabular}
  \caption{Valori delle costanti associate ai limiti delle code di messaggi.}
  \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{sysctl} o scrivendo nei
file \file{msgmax}, \file{msgmnb} e \file{msgmni} di \file{/proc/sys/kernel/}.


\begin{figure}[htb]
  \centering \includegraphics[width=15cm]{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.}

\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}
  \end{minipage} 
  \normalsize 
  \caption{La struttura \structd{msqid\_ds}, associata a ciascuna coda di
    messaggi.}
  \label{fig:ipc_msqid_ds}
\end{figure}

A ciascuna coda è associata una struttura \struct{msgid\_ds}, la cui
definizione, è riportata in \secref{fig:ipc_msqid_ds}. In questa struttura il
kernel mantiene le principali informazioni riguardo lo stato corrente della
coda.\footnote{come accennato questo vale fino ai kernel della serie 2.2.x,
  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_msqid_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}
\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
  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
  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
  contenuto della coda (in byte) viene inizializzato al valore preimpostato
  del sistema (\const{MSGMNB}).
\item 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 \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{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:
  \begin{errlist}
  \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 \errval{EFAULT} ed \errval{EINVAL}.
}
\end{functions}

La funzione permette di accedere ai valori della struttura \struct{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[\const{IPC\_STAT}] Legge le informazioni riguardo la coda nella
  struttura 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 \errcode{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 user-ID effettivo corrispondente al creatore o al proprietario della
  coda, o all'amministratore.
\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 \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; lo
  stesso vale per \var{msg\_qbytes}, ma l'amministratore ha la facoltà di
  incrementarne il valore a limiti superiori a \const{MSGMNB}.
\end{basedescript}


Una volta che si abbia a disposizione l'identificatore, per inviare un
messaggio su una coda si utilizza la funzione \funcd{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)} 

  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:
  \begin{errlist}
  \item[\errcode{EACCES}] Non si hanno i privilegi di accesso sulla coda.
  \item[\errcode{EIDRM}] La coda è stata cancellata.
  \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{EINTR}] La funzione è stata interrotta da un segnale.
  \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 \const{MSGMAX}.
  \end{errlist}
  ed inoltre \errval{EFAULT} ed \errval{ENOMEM}.
}
\end{functions}

La funzione inserisce il messaggio sulla coda specificata da \param{msqid}; 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 \struct{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 \const{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 \const{LENGTH}).

\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}
  \end{minipage} 
  \normalsize 
  \caption{Schema della struttura \structd{msgbuf}, da utilizzare come
    argomento per inviare/ricevere messaggi.}
  \label{fig:ipc_msbuf}
\end{figure}

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 \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 \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 \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
una condizione di errore anche in due altri casi: quando la coda viene rimossa
(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 \struct{msqid\_ds}, in particolare
vengono modificati:
\begin{itemize*}
\item Il valore di \var{msg\_lspid}, che viene impostato al \acr{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 è
\funcd{msgrcv}; il suo prototipo è:
\begin{functions}
  \headdecl{sys/types.h} 
  \headdecl{sys/ipc.h} 
  \headdecl{sys/msg.h} 

  \funcdecl{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:
  \begin{errlist}
  \item[\errcode{EACCES}] Non si hanno i privilegi di accesso sulla coda.
  \item[\errcode{EIDRM}] La coda è stata cancellata.
  \item[\errcode{E2BIG}] Il testo del messaggio è più lungo di \param{msgsz} e
    non si è specificato \const{MSG\_NOERROR} in \param{msgflg}.
  \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 \errval{EFAULT}.
}
\end{functions}

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 \const{LENGTH} nell'esempio di
\figref{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
\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 \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},
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:
\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
  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
  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 \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
\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 \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 \struct{msqid\_ds}, in particolare
vengono modificati:
\begin{itemize*}
\item Il valore di \var{msg\_lrpid}, che viene impostato al \acr{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
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.

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.

\begin{figure}[!bht]
  \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}
  \end{minipage} 
  \normalsize 
  \caption{Sezione principale del codice del server di \textit{fortunes}
    basato sulle \textit{message queue}.}
  \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
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.

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}) 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
(\texttt{\small 23}) vengono lette nel vettore in memoria con la stessa
funzione \code{FortuneParse()} usata anche per il server basato sulle 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
una chiave per identificare la coda di messaggi (si usa il nome del file dei
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 \const{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à,
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.

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 gestore
\code{HandSIGTERM}, che semplicemente si limita a cancellare la coda
(\texttt{\small 44}) ed ad uscire (\texttt{\small 45}).

\begin{figure}[!bht]
  \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}
  \end{minipage} 
  \normalsize 
  \caption{Sezione principale del codice del client di \textit{fortunes}
    basato sulle \textit{message queue}.}
  \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}.

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)
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.
 
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\index{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}
\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).

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
\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,
utilizzando il valore del contatore come indicatore del ``numero di risorse''
ancora disponibili.

Il sistema di comunicazione inter-processo 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 è
\funcd{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[\errcode{ENOSPC}] Si è cercato di creare una insieme di semafori
      quando è stato superato o il limite per il numero totale di semafori
      (\const{SEMMNS}) o quello per il numero totale degli insiemi
      (\const{SEMMNI}) nel sistema.
    \item[\errcode{EINVAL}] L'argomento \param{nsems} è minore di zero o
      maggiore del limite sul numero di semafori per ciascun 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{ENOENT}, \errval{EEXIST},
    \errval{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 è
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{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.

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.

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 l'operazione atomicamente.

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.


\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}
  \end{minipage} 
  \normalsize 
  \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 \struct{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:
\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
  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
\struct{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}
  \end{minipage} 
  \normalsize 
  \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*}
\item[\var{semval}] il valore numerico del semaforo.
\item[\var{sempid}] il \acr{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*}

\begin{table}[htb]
  \footnotesize
  \centering
  \begin{tabular}[c]{|c|r|p{8cm}|}
    \hline
    \textbf{Costante} & \textbf{Valore} & \textbf{Significato} \\
    \hline
    \hline
    \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}. \\
    \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}
  \caption{Valori delle costanti associate ai limiti degli insiemi di
    semafori, definite in \file{linux/sem.h}.} 
  \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) è \funcd{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[\errcode{EACCES}] Il processo non ha i privilegi per eseguire
      l'operazione richiesta.
    \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 ha privilegi sufficienti ad eseguire l'operazione.
    \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}.
}
\end{functions}

La funzione può avere tre o quattro parametri, 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}. 

\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}
  \end{minipage} 
  \normalsize 
  \caption{La definizione dei possibili valori di una \direct{union}
    \structd{semun}, usata come quarto argomento della funzione
    \func{semctl}.}
  \label{fig:ipc_semun}
\end{figure}

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 \struct{semun}, la cui
definizione, con i possibili valori che può assumere, è riportata in
\figref{fig:ipc_semun}.

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 \errcode{EINVAL}) per questo argomento sono i
seguenti:
\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
\item[\const{IPC\_STAT}] Legge i dati dell'insieme di semafori, copiando il
  contenuto della relativa struttura \struct{semid\_ds} 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 stato di
  \textit{sleep} vengono svegliati, ritornando con un errore di
  \errcode{EIDRM}.  L'user-ID effettivo del processo deve corrispondere o al
  creatore o al proprietario dell'insieme, o all'amministratore. L'argomento
  \param{semnum} viene ignorato.
\item[\const{IPC\_SET}] Permette di modificare i permessi ed il proprietario
  dell'insieme. I valori devono essere passati in una struttura
  \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}. L'user-ID effettivo del processo deve
  corrispondere o al creatore o al proprietario dell'insieme, o
  all'amministratore.  L'argomento \param{semnum} viene ignorato.
\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
  \struct{sem}); va invocata con tre argomenti.  Occorre avere il permesso di
  lettura.
\item[\const{GETPID}] Restituisce come valore di ritorno della funzione il
  \acr{pid} dell'ultimo processo che ha compiuto una operazione sul semaforo
  \param{semnum} dell'insieme \param{semid} (corrispondente al campo
  \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 \struct{sem}); va invocata con tre
  argomenti.  Occorre avere il permesso di lettura.
\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 \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[\const{SETVAL}] Inizializza il semaforo \param{semnum} al valore passato
  dall'argomento \param{arg.val}, aggiornando il campo \var{sem\_ctime} di
  \struct{semid\_ds}.  Si devono avere i privilegi di scrittura sul semaforo.
\end{basedescript}

Quando si imposta il valore di un semaforo (sia che lo si faccia per tutto
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.

\begin{table}[htb]
  \footnotesize
  \centering
  \begin{tabular}[c]{|c|l|}
    \hline
    \textbf{Operazione}  & \textbf{Valore restituito} \\
    \hline
    \hline
    \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}.} 
  \label{tab:ipc_semctl_returns}
\end{table}

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 \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 \funcd{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[\errcode{EACCES}] Il processo non ha i privilegi per eseguire
      l'operazione richiesta.
    \item[\errcode{EIDRM}] L'insieme di semafori è stato cancellato.
    \item[\errcode{ENOMEM}] Si è richiesto un \const{SEM\_UNDO} ma il sistema
      non ha le risorse per allocare la struttura di ripristino.
    \item[\errcode{EAGAIN}] Un'operazione comporterebbe il blocco del processo,
      ma si è specificato \const{IPC\_NOWAIT} in \var{sem\_flg}.
    \item[\errcode{EINTR}] La funzione, bloccata in attesa dell'esecuzione
      dell'operazione, viene interrotta da un segnale.
    \item[\errcode{E2BIG}] L'argomento \param{nsops} è maggiore del numero
      massimo di operazioni \const{SEMOPM}.
    \item[\errcode{ERANGE}] Per alcune operazioni il valore risultante del
      semaforo viene a superare il limite massimo \const{SEMVMX}.
  \end{errlist}
  ed inoltre \errval{EFAULT} ed \errval{EINVAL}.
}
\end{functions}

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
effettuare viene specificato con l'argomento \param{nsop}, mentre il loro
contenuto viene passato con un puntatore ad un vettore di strutture
\struct{sembuf} nell'argomento \param{sops}. Le operazioni richieste vengono
effettivamente eseguite se e soltanto se è possibile effettuarle tutte quante.

\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}
  \end{minipage} 
  \normalsize 
  \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 \struct{sembuf} (la cui definizione è riportata in
\figref{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.
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 \const{IPC\_NOWAIT} e
\const{SEM\_UNDO}.  Impostando \const{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 \errcode{EAGAIN}.  Impostando \const{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 \errcode{ERANGE} qualora si sia superato il
  limite \const{SEMVMX}) ed il processo non viene bloccato in nessun caso.
  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 \const{IPC\_NOWAIT} la
  funzione ritorna con un errore di \errcode{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:
  \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 \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
    \errcode{EINTR}.
  \end{itemize*}
  Al processo chiamante è richiesto 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 \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 \const{IPC\_NOWAIT} la funzione ritorna 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 \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 \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
    \errcode{EINTR}.
  \end{itemize*}    
  Al processo chiamante è richiesto il privilegio di alterazione (scrittura)
  sull'insieme di semafori.
\end{basedescript}

In caso di successo della funzione viene aggiornato il campo \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
\const{SEM\_UNDO}. Il meccanismo è implementato tramite una apposita struttura
\struct{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}
  \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
\struct{semid\_ds} ed il relativo vettore di strutture \struct{sem}. Quando si
richiede una operazione viene anzitutto verificato che tutte le operazioni
possono avere successo; se una di esse comporta il blocco del processo il
kernel crea una struttura \struct{sem\_queue} che viene aggiunta in fondo alla
coda di attesa associata a ciascun insieme di semafori\footnote{che viene
  referenziata tramite i campi \var{sem\_pending} e \var{sem\_pending\_last}
  di \struct{semid\_ds}.}. 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
scheduler\index{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 \struct{sem\_queue} viene rimossa e lo stato del processo associato
all'operazione (\var{sleeper}) viene riportato a \textit{running}; il tutto
viene ripetuto fin quando non ci sono più operazioni eseguibili o si è
svuotata la coda.

Per gestire il meccanismo del ripristino tutte le volte che per un'operazione
si è specificato il flag \const{SEM\_UNDO} viene mantenuta per ciascun insieme
di semafori una apposita struttura \struct{sem\_undo} che 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
  \struct{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.

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{Mutex.c} allegato ai sorgenti, è
riportato in \figref{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à. 

\begin{figure}[!bht]
  \footnotesize \centering
  \begin{minipage}[c]{15cm}
    \begin{lstlisting}{} 
/* Function MutexCreate: create a mutex/semaphore */
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 */
int MutexFind(key_t ipc_key) 
{
    return semget(ipc_key,1,0);
}
/* Function MutexRead: read the current value of the mutex/semaphore */
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_UNDO};                                      /* flag (in this case 0) */
/* Function MutexLock: to lock a mutex/semaphore */
int MutexLock(int sem_id) 
{
    return semop(sem_id, &sem_lock, 1);
}
/* Function MutexUnlock: to unlock a mutex/semaphore */
int MutexUnlock(int sem_id) 
{
    return semop(sem_id, &sem_ulock, 1);
}
/* Function MutexRemove: remove a mutex/semaphore */
int MutexRemove(int sem_id) 
{
    return semctl(sem_id, 0, IPC_RMID);
}
    \end{lstlisting}
  \end{minipage} 
  \normalsize 
  \caption{Il codice delle funzioni che permettono di creare o recuperare
    l'identificatore di un semaforo da utilizzare come \textit{mutex}.}
  \label{fig:ipc_mutex_create}
\end{figure}

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 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 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 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 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 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 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
smemaforo; 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). 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_lock_file} come sia possibile ottenere
un'interfaccia analoga a quella appena illustrata, senza incorrere in questi
problemi, usando il file locking\index{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 è \funcd{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[\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 (\const{SHMALL}) per
      la memoria ad essi riservata.
    \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 \errval{EACCES}, \errval{ENOENT}, \errval{EEXIST},
    \errval{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 \const{PAGE\_SIZE}.

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ò
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
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
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}
  \end{minipage} 
  \normalsize 
  \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
\struct{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
relativamente ai permessi di accesso; per quanto riguarda gli altri campi
invece:
\begin{itemize*}
\item il campo \var{shm\_segsz}, che esprime la dimensione del segmento, viene
  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\_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
  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\_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 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/}. In \tabref{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
  \centering
  \begin{tabular}[c]{|c|r|c|p{7cm}|}
    \hline
    \textbf{Costante} & \textbf{Valore} & \textbf{File in \texttt{proc}}
    & \textbf{Significato} \\
    \hline
    \hline
    \const{SHMALL}& 0x200000&\file{shmall}& Numero massimo di pagine che 
                                       possono essere usate per i segmenti di
                                       memoria condivisa. \\
    \const{SHMMAX}&0x2000000&\file{shmmax}& Dimensione massima di un segmento 
                                            di memoria condivisa.\\
    \const{SHMMNI}&     4096&\file{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.\\


    \hline
  \end{tabular}
  \caption{Valori delle costanti associate ai limiti dei segmenti di memoria
    condivisa, insieme al relativo file in \file{/proc/sys/kernel/} ed al
    valore preimpostato presente nel sistema.} 
  \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 è \funcd{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[\errcode{EACCES}] Si è richiesto \const{IPC\_STAT} ma i permessi non
      consentono l'accesso in lettura al segmento.
    \item[\errcode{EINVAL}] O \param{shmid} o \param{cmd} hanno valori non
      validi.
    \item[\errcode{EIDRM}] L'argomento \param{shmid} fa riferimento ad un
      segmento che è stato cancellato.
    \item[\errcode{EPERM}] Si è specificato un comando con \const{IPC\_SET} o
      \const{IPC\_RMID} senza i permessi necessari.
    \item[\errcode{EOVERFLOW}] L'argomento \param{shmid} fa riferimento ad un
      segmento che è stato cancellato.
    \end{errlist}
  ed inoltre \errval{EFAULT}.}
\end{functions}

Il comportamento della funzione dipende dal valore del comando passato
attraverso l'argomento \param{cmd}, i valori possibili sono i seguenti:
\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
\item[\const{IPC\_STAT}] Legge le informazioni riguardo il segmento di memoria
  condivisa nella struttura \struct{shmid\_ds} puntata da \param{buf}. Occorre
  avere il permesso di lettura sulla coda.
\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 user-ID effettivo corrispondente o al
  creatore della coda, o al proprietario della coda, 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
  aggiorna anche il valore del campo \var{shm\_ctime}.
\item[\const{SHM\_LOCK}] Abilita il \textit{memory locking}\index{memory
    locking}\footnote{impedisce cioè che la memoria usata per il segmento
    venga salvata su disco dal meccanismo della memoria virtuale; si ricordi
    quanto trattato in \secref{sec:proc_mem_lock}.} sul segmento di memoria
  condivisa. Solo l'amministratore può utilizzare questo comando.
\item[\const{SHM\_UNLOCK}] Disabilita il \textit{memory locking} sul segmento
  di memoria condivisa. 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 è \funcd{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[\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 \errval{ENOMEM}.}
\end{functions}

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}). In
particolare l'indirizzo finale del segmento dati (quello impostato da
\func{brk}, vedi \secref{sec:proc_mem_sbrk}) 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 è
    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 è \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 \const{SHM\_RND} e
\const{SHM\_RDONLY}, 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, in Linux è equivalente a \const{PAGE\_SIZE}).

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 \const{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
\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
  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*} 

Come accennato in \secref{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
eseguito un diverso programma con uno spazio di indirizzi completamente
diverso, tutti i segmenti agganciati al processo originario vengono
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ò
sganciarlo esplicitamente dal processo usando l'altra funzione
dell'interfaccia, \funcd{shmdt}, il cui prototipo è:
\begin{functions}
  \headdecl{sys/types.h} 
  \headdecl{sys/shm.h}

  \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
    \errval{EINVAL}.}
\end{functions}

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.

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 \acr{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.

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 pipe, le 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 \secref{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 \figref{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}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15cm}
    \begin{lstlisting}{} 
/* computation function for DirScan */
int ComputeValues(struct dirent * direntry);
void HandSIGTERM(int signo);
/* global variables for shared memory segment */
struct DirProp {
    int tot_size;    
    int tot_files;   
    int tot_regular; 
    int tot_fifo;    
    int tot_link;    
    int tot_dir;     
    int tot_block;   
    int tot_char;    
    int tot_sock;
};
struct DirProp *shmptr;
int shmid; 
int mutex;
/* main body */
int main(int argc, char *argv[]) 
{
    int i;
    key_t key;
    ...
    if ((argc - optind) != 1) {          /* There must be remaing parameters */
        printf("Wrong number of arguments %d\n", argc - optind);
        usage();
    }
    Signal(SIGTERM, HandSIGTERM);            /* set handlers for termination */
    Signal(SIGINT, HandSIGTERM);
    Signal(SIGQUIT, HandSIGTERM);
    /* create needed IPC objects */
    key = ftok("./DirMonitor.c", 1);                         /* define a key */
    shmid = shmget(key, 4096, IPC_CREAT|0666);        /* get a shared memory */
    if (shmid < 0) {
        perror("Cannot create shared memory");
        exit(1);
    }
    if ( (shmptr = shmat(shmid, NULL, 0)) == NULL ) {   /* attach to process */
        perror("Cannot attach segment");
    }
    if ((mutex = MutexCreate(key)) == -1) {                   /* get a Mutex */
        perror("Cannot create mutex");
        exit(1);
    }
    /* main loop, monitor directory properties each 10 sec */
    while (1) {
        MutexLock(mutex);                              /* lock shared memory */
        memset(shmptr, 0, sizeof(struct DirProp));    /* erase previous data */
        DirScan(argv[1], ComputeValues);                     /* execute scan */
        MutexUnlock(mutex);                          /* unlock shared memory */
        sleep(pause);                              /* sleep until next watch */
    }
}
    \end{lstlisting}
  \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 4--18}) 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
  25--28}) che sia stato specificato un parametro (il nome della directory da
tenere sotto controllo) senza il quale esce immediatamente con un messaggio di
errore.

Il passo successivo (\texttt{\small 29--31}) è quello di installare i gestori
per i segnali di terminazione, infatti, visto che il programma è progettato
come server, non è prevista una conclusione esplicita nel corpo principale,
per cui, per gestire l'uscita, si è fatto uso di questi ultimi.

Si può poi passare a creare (\texttt{\small 32--45}) gli oggetti di
intercomunicazione necessari. Si ricava (\texttt{\small 33}) una chiave usando
il nome del programma, con questa si ottiene (\texttt{\small 34--38}) un
segmento di memoria condivisa \var{shmid} (uscendo in caso di errore), che si
aggancia (\texttt{\small 39--41}) al processo all'indirizzo \var{shmptr}; sarà
attraverso questo puntatore che potremo accedere alla memoria condivisa, che
sarà vista nella forma data da \struct{DirProp}. Infine con la stessa chiave
si crea (\texttt{\small 42--45}) anche un mutex (utilizzando le funzioni di
interfaccia già descritte in \secref{sec:ipc_sysv_sem}) che utilizzeremo per
regolare l'accesso alla memoria condivisa.

Una volta completata l'inizializzazione e la creazione degli oggetti di
intercomunicazione il programma eseguirà indefinitamente (\texttt{\small
  46--53}) il ciclo principale: si inizia bloccando il mutex (\texttt{\small
  48}) per poter accedere alla memoria condivisa (la funzione si bloccherà
automaticamente se qualche client sta leggendo), poi si cancellano
(\texttt{\small 49}) i valori precedentemente memorizzati, e si esegue
(\texttt{\small 50}) un nuovo calcolo degli stessi; infine si sblocca il mutex
(\texttt{\small 51}), e si attende (\texttt{\small 52}) per il periodo di
tempo specificato a riga di comando con l'opzione \code{-p}.

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15cm}
    \begin{lstlisting}{} 
...
/*
 * Routine  to compute directory properties inside DirScan
 */
int ComputeValues(struct dirent * direntry) 
{
    struct stat data;
    stat(direntry->d_name, &data);                          /* get stat data */
    shmptr->tot_size += data.st_size;
    shmptr->tot_files++;
    if (S_ISREG(data.st_mode)) shmptr->tot_regular++;
    if (S_ISFIFO(data.st_mode)) shmptr->tot_fifo++;
    if (S_ISLNK(data.st_mode)) shmptr->tot_link++;
    if (S_ISDIR(data.st_mode)) shmptr->tot_dir;
    if (S_ISBLK(data.st_mode)) shmptr->tot_block;
    if (S_ISCHR(data.st_mode)) shmptr->tot_char;
    if (S_ISSOCK(data.st_mode)) shmptr->tot_sock;
    return 0;
}
/*
 * Signal Handler to manage termination
 */
void HandSIGTERM(int signo) {
    MutexLock(mutex);
    if (shmdt(shmptr)) {
        perror("Error detaching shared memory");
        exit(1);
    }
    if (shmctl(shmid, IPC_RMID, NULL)) {
        perror("Cannot remove shared memory segment");
        exit(1);
    }
    MutexRemove(mutex);
    exit(0);
}
    \end{lstlisting}
  \end{minipage} 
  \normalsize 
  \caption{Codice delle funzione ausiliarie usate da \file{DirMonitor.c}.}
  \label{fig:ipc_dirmonitor_sub}
\end{figure}

Si noti come per il calcolo dei valori da mantenere nella memoria condivisa si
sia usata ancora una volta la funzione \func{DirScan}, già utilizzata (e
descritta in dettaglio) in \secref{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.

Il codice di quest'ultima è riportato in \figref{fig:ipc_dirmonitor_sub}. Come
si vede la funzione (\texttt{\small 5--19}) è molto semplice e si limita a
chiamare (\texttt{\small 8}) la funzione \func{stat} sul file indicato da
ciascuna voce, per ottenerne i dati, che poi utilizza per incrementare i vari
contatori.

Dato che la funzione è chiamata da \func{DirScan}, si è all'interno del ciclo
principale del programma, con un mutex acquisito, perciò non è necessario
effettuare nessun controllo e si può accedere direttamente alla memoria
condivisa usando \var{shmptr} riempiendo i campi della struttura
\struct{DirProp}; così prima (\texttt{\small 9--10}) si sommano le dimensioni
dei file ed il loro numero, poi utilizzando le macro di
\tabref{tab:file_type_macro}, si contano (\texttt{\small 11--17}) quanti ce ne
sono per ciascun tipo.

In \figref{fig:ipc_dirmonitor_sub} è riportato anche (\texttt{\small 23--35})
il codice del gestore di segnali di terminazione usato per chiudere il
programma, che oltre a provocare l'uscita del programma si incarica anche di
cancellare tutti gli oggetti di intercomunicazione non più necessari.  Nel
caso anzitutto (\texttt{\small 24}) si acquisisce il mutex per evitare di
operare mentre un client sta ancora leggendo i dati, dopo di che prima si
distacca (\texttt{\small 25--28}) il segmento e poi lo si cancella
(\texttt{\small 29--32}). Infine (\texttt{\small 33}) si rimuove il mutex e si
esce.

Il codice del client che permette di leggere le informazioni mantenute nella
memoria condivisa è riportato in \figref{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}.

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15cm}
    \begin{lstlisting}{} 
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>        /* directory */
#include <stdlib.h>        /* C standard library */
#include <unistd.h>

#include "Gapil.h"
#include "macros.h"

int main(int argc, char *argv[]) 
{
    int i;
    key_t key;
    ..
    /* find needed IPC objects */
    key = ftok("./DirMonitor.c", 1);                         /* define a key */
    shmid = shmget(key, 4096, 0);                /* get the shared memory ID */
    if (shmid < 0) {
        perror("Cannot find shared memory");
        exit(1);
    }
    if ( (shmptr = shmat(shmid, NULL, 0)) == NULL ) {   /* attach to process */
        perror("Cannot attach segment");
        exit(1);
    }
    if ((mutex = MutexFind(key)) == -1) {                   /* get the Mutex */
        perror("Cannot find mutex");
        exit(1);
    }
    /* main loop */
    MutexLock(mutex);                                  /* lock shared memory */
    printf("File presenti %d file, per un totale di %d byte\n",
           shmptr->tot_files, shmptr->tot_size);
    printf("Ci sono %d file dati\n", shmptr->tot_regular);
    printf("Ci sono %d directory\n", shmptr->tot_dir);
    printf("Ci sono %d link\n", shmptr->tot_link);
    printf("Ci sono %d fifo\n", shmptr->tot_fifo);
    printf("Ci sono %d socket\n", shmptr->tot_sock);
    printf("Ci sono %d device a caratteri\n", shmptr->tot_char);
    printf("Ci sono %d device a blocchi\n", shmptr->tot_block);
    MutexUnlock(mutex);                              /* unlock shared memory */
}
    \end{lstlisting}
  \end{minipage} 
  \normalsize 
  \caption{Codice del programma client \file{ReadMonitor.c}.}
  \label{fig:ipc_dirmonitor_client}
\end{figure}

Una volta completata la gestione delle opzioni a riga di comando il programma
rigenera (\texttt{\small 16}) la chiave usata per identificare memoria
condivisa e mutex, richiede (\texttt{\small 17}) l'identificatore della
memoria condivisa (che in questo caso deve già esistere), uscendo in caso di
errore (\texttt{\small 18--21}). Una volta ottenuto l'identificatore si può
(\texttt{\small 22--25}) agganciare il segmento al processo (anche in questo
caso uscendo se qualcosa non funziona). Infine (\texttt{\small 26--29}) si
richiede pure l'identificatore del mutex.

Una volta completata l'inizializzazione ed ottenuti i riferimenti agli oggetti
di intercomunicazione necessari viene eseguito il corpo principale del
programma (\texttt{\small 30--41}); si acquisisce (\texttt{\small 31}) il
mutex (qui avviene il blocco se la memoria condivisa non è disponibile), e poi
(\texttt{\small 32--40}) si stampano i vari valori in essa contenuti. Infine
(\texttt{\small 41}) si rilascia il mutex. 


%% 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}. 

%% \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 detto in \secref{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 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.


\subsection{Alternative alle code di messaggi}
\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}) o
utilizzando una coppia di 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\index{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.

\subsection{I \textsl{file di lock}}
\label{sec:ipc_file_lock}

\index{file!di lock|(}
Come illustrato in \secref{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
alternativi.

La prima possibilità, utilizzata fin dalle origini di Unix, è quella di usare
dei \textsl{file di lock} (per i quali esiste anche una opportuna directory,
\file{/var/lock}, nel filesystem standard). Per questo si usa la
caratteristica della funzione \func{open} (illustrata in
\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\index{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 \figref{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}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15cm}
    \begin{lstlisting}{} 
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>                               /* unix standard functions */
/*
 * Function LockFile:
 */
int LockFile(const char* path_name)
{
    return open(path_name, O_EXCL|O_CREAT);
}
/*
 * Function UnlockFile:
 */
int UnlockFile(const char* path_name) 
{
    return unlink(path_name);
}
    \end{lstlisting}
  \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
\secref{sec:file_open}, 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.

Un 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 \textit{polling}\index{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\index{file!di lock} presentano gli inconvenienti
illustrati in precedenza, la tecnica alternativa di sincronizzazione più
comune è quella di fare ricorso al \textit{file locking}\index{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.

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.

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15cm}
    \begin{lstlisting}{} 
/* Function CreateMutex: Create a mutex using file locking. */
int CreateMutex(const char *path_name)
{
    return open(path_name, O_EXCL|O_CREAT);
}
/* Function UnlockMutex: unlock a file. */
int FindMutex(const char *path_name)
{
    return open(path_name, O_RDWR);
}
/* Function LockMutex: lock mutex using file locking. */
int LockMutex(int fd)
{
    struct flock lock;                                /* file lock structure */
    /* first open the file (creating it if not existent) */
    /* set flock structure */
    lock.l_type = F_WRLCK;                        /* set type: read or write */
    lock.l_whence = SEEK_SET;        /* start from the beginning of the file */
    lock.l_start = 0;                  /* set the start of the locked region */
    lock.l_len = 0;                   /* set the length of the locked region */
    /* do locking */
    return fcntl(fd, F_SETLKW, &lock);
}
/* Function UnlockMutex: unlock a file. */
int UnlockMutex(int fd)
{
    struct flock lock;                                /* file lock structure */
    /* set flock structure */
    lock.l_type = F_UNLCK;                               /* set type: unlock */
    lock.l_whence = SEEK_SET;        /* start from the beginning of the file */
    lock.l_start = 0;                  /* set the start of the locked region */
    lock.l_len = 0;                   /* set the length of the locked region */
    /* do locking */
    return fcntl(fd, F_SETLK, &lock);
}
/* Function RemoveMutex: remove a mutex (unlinking the lock file). */
int RemoveMutex(const char *path_name)
{
    return unlink(path_name);
}
/* Function ReadMutex: read a mutex status. */
int ReadMutex(int fd)
{
    int res;
    struct flock lock;                                /* file lock structure */
    /* set flock structure */
    lock.l_type = F_WRLCK;                               /* set type: unlock */
    lock.l_whence = SEEK_SET;        /* start from the beginning of the file */
    lock.l_start = 0;                  /* set the start of the locked region */
    lock.l_len = 0;                   /* set the length of the locked region */
    /* do locking */
    if ( (res = fcntl(fd, F_GETLK, &lock)) ) {
        return res;
    }
    return lock.l_type;
}
    \end{lstlisting}
  \end{minipage} 
  \normalsize 
  \caption{Il codice delle funzioni che permettono per la gestione dei 
    \textit{mutex} con il file locking\index{file!locking}.}
  \label{fig:ipc_flock_mutex}
\end{figure}

Il codice delle varie funzioni usate per implementare un mutex utilizzando il
file locking\index{file!locking} è riportato in \figref{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, si limita
(\texttt{\small 4}) a creare, con una opportuna chiamata ad \func{open}, il
file che sarà usato per il successivo 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, si è definita solo per mantenere una analogia con l'analoga
funzione basata sui semafori, anch'essa si limita (\texttt{\small 9}) ad
aprire il file da usare per il 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--23}) è \func{LockMutex} e serve per
acquisire il mutex. La funzione definisce (\texttt{\small 14} e inizializza
(\texttt{\small 17--20}) la struttura \var{lock} per poter acquisire un write
lock sul file, che poi (\texttt{\small 21}) viene richiesto con \func{fcntl}
(restituendo il codice di ritorno). Se il file è libero il lock è acquisito e
la funzione ritorna immediatamente; altrimenti \func{fcntl} si bloccherà (si
noti che la si è chiamata con \func{F\_SETLKW}) fino al rilascio del lock.

La quarta funzione (\texttt{\small 24--35}) è \func{UnlockMutex} e serve a
rilasciare il mutex. La funzione è analoga alla precedente, solo che in questo
caso si inizializza (\texttt{\small 29--32}) la struttura \var{lock} per il
rilascio del lock, che viene effettuato (\texttt{\small 34}) con la opportuna
chiamata a \func{fcntl}.

La quinta funzione \texttt{\small 36--40}) è \func{RemoveMutex} e serve a
cancellare il mutex. Anche questa funzione è definita per mantenere una
analogia con le funzioni basate sui semafori, e si limita a cancellare
\texttt{\small 39}) 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 saranno aperti.

Basandosi sulla semantica dei file lock POSIX valgono tutte le precisazioni
relative al comportamento di questi ultimi fatte in
\secref{sec:file_posix_lock}; questo significa che, al contrario di quanto
avveniva con l'altra interfaccia basata sui semafori, chiamate multiple a
\func{UnlockMutex} o \func{LockMutex} non hanno nessun inconveniente.


\subsection{Il \textit{memory mapping} anonimo}
\label{sec:ipc_mmap_anonymous}

Abbiamo già visto che quando i processi sono \textsl{correlati}\footnote{se
  cioè hanno almeno un progenitore comune.} l'uso delle 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.

Abbiamo visto in \secref{sec:file_memory_map} che è 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.} Un esempio di utilizzo di questa
tecnica è mostrato in 



\section{La comunicazione 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
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}.


\subsection{Code di messaggi}
\label{sec:ipc_posix_mq}

Le code di messaggi non sono ancora supportate nel kernel
ufficiale;\footnote{esiste però una proposta di implementazione di Krzysztof
  Benedyczak, a partire dal kernel 2.5.50.}  inoltre esse possono essere
implementate, usando la memoria condivisa ed i mutex, con funzioni di
libreria. In generale, come le corrispettive del SysV IPC, sono poco usate,
dato che i socket\index{socket}, nei casi in cui sono sufficienti, sono più
comodi, e negli altri casi la comunicazione può essere gestita direttamente
con mutex e memoria condivisa. Per questo ci limiteremo ad una descrizione
essenziale.



\subsection{Semafori}
\label{sec:ipc_posix_sem}

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 un'altra
versione, realizzata da Konstantin Knizhnik, che reimplementa l'interfaccia
POSIX usando i semafori di SysV IPC. 


\subsection{Memoria condivisa}
\label{sec:ipc_posix_shm}

La memoria condivisa è l'unico degli oggetti di IPC POSIX già presente nel
kernel ufficiale. 


%%% Local Variables: 
%%% mode: latex
%%% TeX-master: "gapil"
%%% End: 
