%% ipc.tex
%%
%% Copyright (C) 2000-2004 Simone Piccardi.  Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
%% with no Front-Cover Texts, and with no Back-Cover Texts.  A copy of the
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
\chapter{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 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
sez.~\ref{sec:sys_file_limits}). Lo schema di funzionamento di una pipe è
illustrato in fig.~\ref{fig:ipc_pipe_singular}, in cui sono illustrati i due
capi della pipe, associati a ciascun file descriptor, con le frecce che
indicano la direzione del flusso dei dati.

\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 sez.~\ref{sec:file_sharing}
riguardo al comportamento dei file descriptor nei processi figli, è immediato
capire come una pipe possa diventare un meccanismo di intercomunicazione. Un
processo figlio infatti condivide gli stessi file descriptor del padre,
compresi quelli associati ad una pipe (secondo la situazione illustrata in
fig.~\ref{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 \const{SIGPIPE}, e la funzione di scrittura
restituirà un errore di \errcode{EPIPE} (al ritorno del gestore, o qualora il
segnale sia ignorato o bloccato).

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


\subsection{Un esempio dell'uso delle pipe}
\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 fig.~\ref{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 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 \textit{race condition}\index{\textit{race~condition}} in caso di
accesso simultaneo a detto file.\footnote{il problema potrebbe essere superato
  determinando in anticipo un nome appropriato per il file temporaneo, che
  verrebbe utilizzato dai vari sotto-processi, e cancellato alla fine della
  loro esecuzione; ma a questo 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
sez.~\ref{sec:file_dup}, in particolare di \func{dup2}. È attraverso queste
funzioni infatti che è possibile dirottare gli stream standard dei processi
(che abbiamo visto in sez.~\ref{sec:file_std_descr} e
sez.~\ref{sec:file_std_stream}) sulla pipe. In
fig.~\ref{fig:ipc_barcodepage_code} abbiamo riportato il corpo del programma,
il cui codice completo è disponibile nel file \file{BarCodePage.c} che si
trova nella directory dei sorgenti.


\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15cm}
    \includecodesample{listati/BarCodePage.c}
  \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
  fig.~\ref{fig:ipc_barcodepage_code}; essa si incarica semplicemente di
  formattare l'uscita alla maniera dei CGI, aggiungendo l'opportuno
  \textit{mime type}, e formattando il messaggio in HTML, in modo che
  quest'ultimo possa essere visualizzato correttamente da un browser.}

Una volta create le pipe, il programma può creare (\texttt{\small 13-17}) il
primo processo figlio, che si incaricherà (\texttt{\small 19--25}) di eseguire
\cmd{barcode}. Quest'ultimo legge dallo standard input una stringa di
caratteri, la converte nell'immagine PostScript del codice a barre ad essa
corrispondente, e poi scrive il risultato direttamente sullo standard output.

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 cap.~\ref{cha:files_std_interface}, anche se è collegato ad
una pipe e non ad un file, e viene sempre aperto in modalità
\textit{fully-buffered} (vedi sez.~\ref{sec:file_buffering}); l'unica
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 fig.~\ref{fig:ipc_barcodepage_code} per
quanto funzionante, è (volutamente) codificato in maniera piuttosto complessa,
inoltre nella pratica sconta un problema di \cmd{gs} che non è in
grado\footnote{nella versione GNU Ghostscript 6.53 (2002-02-13).} di
riconoscere correttamente l'Encapsulated PostScript, per cui deve essere usato
il PostScript e tutte le volte viene generata una pagina intera, invece che
una immagine delle dimensioni corrispondenti al codice a barre.

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
fig.~\ref{fig:ipc_barcode_code}.  Come si può notare l'ordine di invocazione
dei programmi è l'inverso di quello in cui ci si aspetta che vengano
effettivamente eseguiti. Questo non comporta nessun problema dato che la
lettura su una pipe è bloccante, per cui ciascun processo, per quanto lanciato
per primo, si bloccherà in attesa di ricevere sullo standard input il
risultato dell'elaborazione del precedente, benchè quest'ultimo venga invocato
dopo.

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15cm}
    \includecodesample{listati/BarCode.c}
  \end{minipage} 
  \normalsize 
  \caption{Codice completo del \textit{CGI} \file{BarCode.c}.}
  \label{fig:ipc_barcode_code}
\end{figure}

Nel nostro caso il primo passo (\texttt{\small 14}) è scrivere il mime-type
sullo standard output; a questo punto il processo padre non necessita più di
eseguire ulteriori operazioni sullo standard output e può tranquillamente
provvedere alla redirezione.

Dato che i vari programmi devono essere lanciati in successione, si è
approntato un ciclo (\texttt{\small 15--19}) che esegue le operazioni in
sequenza: prima crea una pipe (\texttt{\small 17}) per la scrittura eseguendo
il programma con \func{popen}, in modo che essa sia collegata allo standard
input, e poi redirige (\texttt{\small 18}) lo standard output su detta pipe.

In questo modo il primo processo ad essere invocato (che è l'ultimo della
catena) scriverà ancora sullo standard output del processo padre, ma i
successivi, a causa di questa redirezione, scriveranno sulla pipe associata
allo standard input del processo invocato nel ciclo precedente.

Alla fine tutto quello che resta da fare è lanciare (\texttt{\small 21}) il
primo processo della catena, che nel caso è \cmd{barcode}, e scrivere
(\texttt{\small 23}) la stringa del codice a barre sulla pipe, che è collegata
al suo standard input, infine si può eseguire (\texttt{\small 24--27}) un
ciclo che chiuda, nell'ordine inverso rispetto a quello in cui le si sono
create, tutte le pipe create con \func{pclose}.


\subsection{Le \textit{pipe} con nome, o \textit{fifo}}
\label{sec:ipc_named_pipe}

Come accennato in sez.~\ref{sec:ipc_pipes} il problema delle \textit{pipe} è
che esse possono essere utilizzate solo da processi con un progenitore comune
o nella relazione padre/figlio; per superare questo problema lo standard
POSIX.1 ha definito dei nuovi oggetti, le \textit{fifo}, che hanno le stesse
caratteristiche delle pipe, ma che invece di essere strutture interne del
kernel, visibili solo attraverso un file descriptor, sono accessibili
attraverso un 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 sez.~\ref{sec:ipc_pipes}.

Abbiamo già visto in sez.~\ref{sec:file_mknod} le funzioni \func{mknod} e
\func{mkfifo} che permettono di creare una fifo; per utilizzarne una un
processo non avrà che da aprire il relativo file speciale o in lettura o
scrittura; nel primo caso sarà collegato al capo di uscita della fifo, e dovrà
leggere, nel secondo al capo di ingresso, e dovrà scrivere.

Il kernel crea una singola pipe per ciascuna fifo che sia stata aperta, che può
essere acceduta contemporaneamente da più processi, sia in lettura che in
scrittura. Dato che per funzionare deve essere aperta in entrambe le
direzioni, per una fifo di norma la funzione \func{open} si blocca se viene
eseguita quando l'altro capo non è aperto.

Le fifo però possono essere anche aperte in modalità \textsl{non-bloccante},
nel qual caso l'apertura del capo in lettura avrà successo solo quando anche
l'altro capo è aperto, mentre l'apertura del capo in scrittura restituirà
l'errore di \errcode{ENXIO} fintanto che non verrà aperto il capo in lettura.

In Linux è possibile aprire le fifo anche in lettura/scrittura,\footnote{lo
  standard POSIX lascia indefinito il comportamento in questo caso.}
operazione che avrà sempre successo immediato qualunque sia la modalità di
apertura (bloccante e non bloccante); questo può essere utilizzato per aprire
comunque una fifo in scrittura anche se non ci sono ancora processi il
lettura; è possibile anche usare la fifo all'interno di un solo processo, nel
qual caso però occorre stare molto attenti alla possibili situazioni di
stallo.\footnote{se si cerca di leggere da una fifo che non contiene dati si
  avrà un deadlock\index{\textit{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
sez.~\ref{sec:ipc_pipes}).

A parte il caso precedente, che resta probabilmente il più comune, Stevens
riporta in \cite{APUE} altre due casistiche principali per l'uso delle fifo:
\begin{itemize}
\item Da parte dei comandi di shell, per evitare la creazione di file
  temporanei quando si devono inviare i dati di uscita di un processo
  sull'input di parecchi altri (attraverso l'uso del comando \cmd{tee}).
  
\item Come canale di comunicazione fra client ed server (il modello
  \textit{client-server} è illustrato in sez.~\ref{sec:net_cliserv}).
\end{itemize}

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 fig.~\ref{fig:ipc_fifo_server_arch} in cui i client inviano le
richieste al server su una fifo nota mentre le risposte vengono reinviate dal
server a ciascuno di essi su una fifo temporanea creata per l'occasione.

\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
fig.~\ref{fig:ipc_fifo_server}, dove si è tralasciata la parte che tratta la
gestione delle opzioni a riga di comando, che effettua il settaggio delle
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}
    \includecodesample{listati/FortuneServer.c}
  \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 fig.~\ref{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 la procedura di
inizializzazione è completata. A questo punto si può chiamare (\texttt{\small
  23}) la funzione \func{daemon} per far proseguire l'esecuzione del programma
in background come demone.  Si può quindi procedere (\texttt{\small 24--33})
alla apertura della fifo: si noti che questo viene fatto due volte, prima in
lettura e poi in scrittura, per evitare di dover gestire all'interno del ciclo
principale il caso in cui il server è in ascolto ma non ci sono client che
effettuano richieste.  Si ricordi infatti che quando una 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, ed in questo
stato la funzione \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 di
  una fifo in modalità non bloccante, per evitare il rischio di uno stallo: se
  infatti nessuno apre la fifo in scrittura il processo non ritornerà mai
  dalla \func{open}. Nel nostro caso questo rischio non esiste, mentre è
  necessario potersi bloccare in lettura in attesa di una richiesta.} si
esegue una seconda apertura in scrittura (\texttt{\small 29--32}), scartando
il relativo file descriptor, che non sarà mai usato, in questo modo però la
fifo resta comunque aperta anche in scrittura, cosicché le successive chiamate
a \func{read} possono bloccarsi.

A questo punto si può entrare nel ciclo principale del programma che fornisce
le risposte ai client (\texttt{\small 34--50}); questo viene eseguito
indefinitamente (l'uscita del server viene effettuata inviando un segnale, in
modo da passare attraverso la routine di chiusura che cancella la fifo).

Il server è progettato per accettare come richieste dai client delle stringhe
che contengono il nome della fifo sulla quale deve essere inviata la risposta.
Per cui prima (\texttt{\small 35--39}) si esegue la lettura dalla stringa di
richiesta dalla fifo nota (che a questo punto si bloccherà tutte le volte che
non ci sono richieste). Dopo di che, una volta terminata la stringa
(\texttt{\small 40}) e selezionato (\texttt{\small 41}) un numero casuale per
ricavare la frase da inviare, si procederà (\texttt{\small 42--46})
all'apertura della fifo per la risposta, che poi \texttt{\small 47--48}) vi
sarà scritta. Infine (\texttt{\small 49}) si chiude la fifo di risposta che
non serve più.

Il codice del client è invece riportato in fig.~\ref{fig:ipc_fifo_client},
anche in questo caso si è omessa la gestione delle opzioni e la funzione che
stampa a video le informazioni di utilizzo ed esce, riportando solo la sezione
principale del programma e le definizioni delle variabili. Il codice completo
è nel file \file{FortuneClient.c} dei sorgenti allegati.

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15cm}
    \includecodesample{listati/FortuneClient.c}
  \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.

Verifichiamo allora il comportamento dei nostri programmi, in questo, come in
altri esempi precedenti, si fa uso delle varie funzioni di servizio, che sono
state raccolte nella libreria \file{libgapil.so}, per poter usare quest'ultima
occorrerà definire la speciale variabile di ambiente \code{LD\_LIBRARY\_PATH}
in modo che il linker dinamico possa accedervi.

In generale questa variabile indica il
\index{\textit{pathname}}\textit{pathname} della directory contenente la
libreria. Nell'ipotesi (che daremo sempre per verificata) che si facciano le
prove direttamente nella directory dei sorgenti (dove di norma vengono creati
sia i programmi che la libreria), il comando da dare sarà \code{export
  LD\_LIBRARY\_PATH=./}; a questo punto potremo lanciare il server, facendogli
leggere una decina di frasi, con:
\begin{verbatim}
[piccardi@gont sources]$ ./fortuned -n10
\end{verbatim}

Avendo usato \func{daemon} per eseguire il server in background il comando
ritornerà immediatamente, ma potremo verificare con \cmd{ps} che in effetti il
programma resta un esecuzione in background, e senza avere associato un
terminale di controllo (si ricordi quanto detto in sez.~\ref{sec:sess_daemon}):
\begin{verbatim}
[piccardi@gont sources]$ ps aux
...
piccardi 27489  0.0  0.0  1204  356 ?        S    01:06   0:00 ./fortuned -n10
piccardi 27492  3.0  0.1  2492  764 pts/2    R    01:08   0:00 ps aux
\end{verbatim}%$
e si potrà verificare anche che in \file{/tmp} è stata creata la fifo di
ascolto \file{fortune.fifo}. A questo punto potremo interrogare il server con
il programma client; otterremo così:
\begin{verbatim}
[piccardi@gont sources]$ ./fortune
Linux ext2fs has been stable for a long time, now it's time to break it
        -- Linuxkongreß '95 in Berlin
[piccardi@gont sources]$ ./fortune
Let's call it an accidental feature.
        --Larry Wall
[piccardi@gont sources]$ ./fortune
.........    Escape the 'Gates' of Hell
  `:::'                  .......  ......
   :::  *                  `::.    ::'
   ::: .::  .:.::.  .:: .::  `::. :'
   :::  ::   ::  ::  ::  ::    :::.
   ::: .::. .::  ::.  `::::. .:'  ::.
...:::.....................::'   .::::..
        -- William E. Roadcap
[piccardi@gont sources]$ ./fortune
Linux ext2fs has been stable for a long time, now it's time to break it
        -- Linuxkongreß '95 in Berlin
\end{verbatim}%$
e ripetendo varie volte il comando otterremo, in ordine casuale, le dieci
frasi tenute in memoria dal server.

Infine per chiudere il server basterà inviare un segnale di terminazione con
\code{killall fortuned} e potremo verificare che il gestore del segnale ha
anche correttamente cancellato la fifo di ascolto da \file{/tmp}.

Benché il nostro sistema client-server funzioni, la sua struttura è piuttosto
complessa e continua ad avere vari inconvenienti\footnote{lo stesso Stevens,
  che esamina questa architettura in \cite{APUE}, nota come sia impossibile
  per il server sapere se un client è andato in crash, con la possibilità di
  far restare le fifo temporanee sul filesystem, di come sia necessario
  intercettare \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
cap.~\ref{cha:socket_intro}) o ricorrendo a meccanismi di comunicazione
diversi, come quelli che esamineremo in seguito.



\subsection{La funzione \func{socketpair}}
\label{sec:ipc_socketpair}

Un meccanismo di comunicazione molto simile alle pipe, ma che non presenta il
problema della unidirezionalità del flusso dei dati, è quello dei cosiddetti
\textsl{socket locali} (o \textit{Unix domain socket}). Tratteremo l'argomento
dei \textit{socket}\index{socket} in cap.~\ref{cha:socket_intro},\footnote{si
  tratta comunque di oggetti di comunicazione che, come le pipe, sono
  utilizzati attraverso dei file descriptor.} nell'ambito dell'interfaccia
generale che essi forniscono per la programmazione di rete; e vedremo anche
(in~sez.~\ref{sec:sock_sa_local}) come si possono definire dei file speciali
(di tipo \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 sez.~\ref{sec:xxx_fd_passing}).


\section{Il sistema di 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 fra processi} di System V, cui da qui in
avanti faremo riferimento come \textit{SysV IPC} (dove IPC è la sigla di
\textit{Inter-Process Comunication}).



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

La principale caratteristica del \textit{SysV IPC} è quella di essere basato
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 sez.~\ref{sec:ipc_sysv_id_use}). L'identificatore viene restituito
dalle funzioni che creano l'oggetto, ed è quindi locale al processo che le ha
eseguite. Dato che l'identificatore viene assegnato dinamicamente dal kernel
non è possibile prevedere quale sarà, né utilizzare un qualche valore statico,
si pone perciò il problema di come processi diversi possono accedere allo
stesso oggetto.

Per risolvere il problema nella struttura \struct{ipc\_perm} che il kernel
associa a ciascun oggetto, viene mantenuto anche un campo apposito che
contiene anche una \textsl{chiave}, identificata da una variabile del tipo
primitivo \type{key\_t}, da specificare in fase di creazione dell'oggetto, e
tramite la quale è possibile ricavare l'identificatore.\footnote{in sostanza
  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 fig.~\ref{fig:ipc_ipc_perm},
mantiene varie proprietà ed informazioni associate all'oggetto.

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15cm}
    \includestruct{listati/ipc_perm.h}
  \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 \index{\textit{pathname}}\textit{pathname} di un file
effettivamente esistente e di un numero di progetto \param{proj\_id)}, che di
norma viene specificato come carattere, dato che ne vengono utilizzati solo
gli 8 bit meno significativi.\footnote{nelle libc4 e libc5, come avviene in
  SunOS, l'argomento \param{proj\_id} è dichiarato tipo \ctyp{char}, 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
sez.~\ref{sec:ipc_posix}.


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

Oltre alle chiavi, abbiamo visto che ad ogni oggetto sono associate in
\struct{ipc\_perm} ulteriori informazioni, come gli identificatori del creatore
(nei campi \var{cuid} e \var{cgid}) e del proprietario (nei campi \var{uid} e
\var{gid}) dello stesso, e un insieme di permessi (nel campo \var{mode}). In
questo modo è possibile definire un controllo di accesso sugli oggetti di IPC,
simile a quello che si ha per i file (vedi sez.~\ref{sec:file_perm_overview}).

Benché questo controllo di accesso sia molto simile a quello dei file, restano
delle importanti differenze. La prima è che il permesso di esecuzione non
esiste (e se specificato viene ignorato), per cui si può parlare solo di
permessi di lettura e scrittura (nel caso dei semafori poi quest'ultimo è più
propriamente un permesso di modifica). I valori di \var{mode} sono gli stessi
ed hanno lo stesso significato di quelli riportati in
tab.~\ref{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
sez.~\ref{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 fig.~\ref{fig:ipc_ipc_perm} è qualificato con un criptico
``\textsl{numero di sequenza}'', ne parliamo adesso dato che esso è
strettamente attinente alle modalità con cui il kernel assegna gli
identificatori degli oggetti del sistema di IPC.

Quando il sistema si avvia, alla creazione di ogni nuovo oggetto di IPC viene
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}
    \includecodesample{listati/IPCTestId.c}
  \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 fig.~\ref{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 sez.~\ref{sec:ipc_sysv_access_control}.
Se si imposta anche il bit corrispondente a \const{IPC\_EXCL} la funzione avrà
successo solo se l'oggetto non esiste già, fallendo con un errore di
\errcode{EEXIST} altrimenti.

Si tenga conto che l'uso di \const{IPC\_PRIVATE} non impedisce ad altri
processi di accedere alla coda (se hanno privilegi sufficienti) una volta che
questi possano indovinare o ricavare (ad esempio per tentativi)
l'identificatore ad essa associato. Per come sono implementati gli oggetti di
IPC infatti non esiste una maniera che  garantisca l'accesso esclusivo ad una
coda di messaggi.  Usare \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
tab.~\ref{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 fig.~\ref{fig:ipc_mq_schema} si
è riportato lo schema con cui queste strutture vengono mantenute dal
kernel.\footnote{lo schema illustrato in fig.~\ref{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}
    \includestruct{listati/msqid_ds.h}
  \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 fig.~\ref{fig:ipc_msqid_ds}. In questa struttura il
kernel mantiene le principali informazioni riguardo lo stato corrente della
coda.\footnote{come accennato questo vale fino ai kernel della serie 2.2.x,
  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
  fig.~\ref{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 fig.~\ref{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 sez.~\ref{sec:ipc_sysv_access_control}, per quanto riguarda
gli altri campi invece:
\begin{itemize*}
\item il campo \var{msg\_qnum}, che esprime il numero di messaggi presenti
  sulla coda, viene inizializzato a 0.
\item i campi \var{msg\_lspid} e \var{msg\_lrpid}, che esprimono
  rispettivamente il \acr{pid} dell'ultimo processo che ha inviato o ricevuto
  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 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
fig.~\ref{fig:ipc_msbuf} che è quella che deve contenere effettivamente il
messaggio.  La dimensione massima per il testo di un messaggio non può
comunque superare il limite \const{MSGMAX}.

La struttura di fig.~\ref{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 fig.~\ref{fig:ipc_msbuf}, adattando
alle proprie esigenze il campo \var{mtype}, (o ridefinendo come si vuole il
corpo del messaggio, anche con più campi o con strutture più complesse) avendo
però la cura di mantenere nel primo campo un valore di tipo \ctyp{long} che ne
indica il tipo.

Si tenga presente che la lunghezza che deve essere indicata in questo
argomento è solo quella del messaggio, non quella di tutta la struttura, se
cioè \var{message} è una propria struttura che si passa alla funzione,
\param{msgsz} dovrà essere uguale a \code{sizeof(message)-sizeof(long)}, (se
consideriamo il caso dell'esempio in fig.~\ref{fig:ipc_msbuf}, \param{msgsz}
dovrà essere pari a \const{LENGTH}).

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15cm}
    \includestruct{listati/msgbuf.h}
  \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
fig.~\ref{fig:ipc_mq_schema}. Alla chiamata di \func{msgsnd} il nuovo messaggio
sarà aggiunto in fondo alla lista inserendo una nuova struttura \struct{msg},
il puntatore \var{msg\_last} di \struct{msqid\_ds} verrà aggiornato, come pure
il puntatore al messaggio successivo per quello che era il precedente ultimo
messaggio; il valore di \var{mtype} verrà mantenuto in \var{msg\_type} ed il
valore di \param{msgsz} in \var{msg\_ts}; il testo del messaggio sarà copiato
all'indirizzo specificato da \var{msg\_spot}.

Il valore dell'argomento \param{flag} permette di specificare il comportamento
della funzione. Di norma, quando si specifica un valore nullo, la funzione
ritorna immediatamente a meno che si sia ecceduto il valore di
\var{msg\_qbytes}, o il limite di sistema sul numero di messaggi, nel qual
caso si blocca mandando il processo in stato di \textit{sleep}.  Se si
specifica per \param{flag} il valore \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 fig.~\ref{fig:ipc_msbuf}.  Una volta estratto, il messaggio sarà rimosso
dalla coda.  L'argomento \param{msgsz} indica la lunghezza massima del testo
del messaggio (equivalente al valore del parametro \const{LENGTH} nell'esempio
di fig.~\ref{fig:ipc_msbuf}).

Se il testo del messaggio ha lunghezza inferiore a \param{msgsz} esso viene
rimosso dalla coda; in caso contrario, se \param{msgflg} è impostato a
\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 fig.~\ref{fig:ipc_mq_schema},
restituendo il primo messaggio incontrato che corrisponde ai criteri
specificati (che quindi, visto come i messaggi vengono sempre inseriti dalla
coda, è quello meno recente); in particolare:
\begin{itemize}
\item se \param{msgtyp} è 0 viene estratto il messaggio in cima alla coda, cioè
  quello fra i presenti che è stato inserito per primo. 
\item se \param{msgtyp} è positivo viene estratto il primo messaggio il cui
  tipo (il valore del campo \var{mtype}) corrisponde al valore di
  \param{msgtyp}.
\item se \param{msgtyp} è negativo viene estratto il primo fra i messaggi con
  il valore più basso del tipo, fra tutti quelli il cui tipo ha un valore
  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
fig.~\ref{fig:ipc_mq_fortune_server}).

L'altro problema è non facendo uso di file descriptor le tecniche di
\textit{I/O multiplexing} descritte in sez.~\ref{sec:file_multiplexing} non
possono essere utilizzate, e non si ha a disposizione niente di analogo alle
funzioni \func{select} e \func{poll}. Questo rende molto scomodo usare più di
una di queste strutture alla volta; ad esempio non si può scrivere un server
che aspetti un messaggio su più di una coda senza fare ricorso ad una tecnica
di \textit{polling}\index{\textit{polling}} che esegua un ciclo di attesa su
ciascuna di esse.

Come esempio dell'uso delle code di messaggi possiamo riscrivere il nostro
server di \textit{fortunes} usando queste al posto delle fifo. In questo caso
useremo una sola coda di messaggi, usando il tipo di messaggio per comunicare
in maniera indipendente con client diversi.

\begin{figure}[!bht]
  \footnotesize \centering
  \begin{minipage}[c]{15.6cm}
    \includecodesample{listati/MQFortuneServer.c}
  \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 fig.~\ref{fig:ipc_mq_fortune_server} si è riportato un estratto delle parti
principali del codice del nuovo server (il codice completo è nel file
\file{MQFortuneServer.c} nei sorgenti allegati). Il programma è basato su un
uso accorto della caratteristica di poter associate un ``tipo'' ai messaggi
per permettere una comunicazione indipendente fra il server ed i vari client,
usando il \acr{pid} di questi ultimi come identificativo. Questo è possibile
in quanto, al contrario di una fifo, la lettura di una coda di messaggi può
non essere sequenziale, proprio grazie alla classificazione dei messaggi sulla
base del loro tipo.

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 prima (\texttt{\small 32}) chiama
la funzione \func{daemon} per andare in background e poi esegue in permanenza
il ciclo principale (\texttt{\small 33--40}). Questo inizia (\texttt{\small
  34}) con il porsi in attesa di un messaggio di richiesta da parte di un
client; si noti infatti come \func{msgrcv} richieda un messaggio con
\var{mtype} uguale a 1: questo è il valore usato per le richieste dato che
corrisponde al \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 35}) selezionando una frase a caso, copiandola (\texttt{\small
  36}) nella struttura \var{msgbuf\_write} usata per la risposta e
calcolandone (\texttt{\small 37}) la dimensione.

Per poter permettere a ciascun client di ricevere solo la risposta indirizzata
a lui il tipo del messaggio in uscita viene inizializzato (\texttt{\small 38})
al valore del \acr{pid} del client ricevuto nel messaggio di richiesta.
L'ultimo passo del ciclo (\texttt{\small 39}) è inviare sulla coda il
messaggio di risposta. Si tenga conto che se la coda è piena anche questa
funzione potrà bloccarsi fintanto che non venga liberato dello spazio.

Si noti che il programma può terminare solo grazie ad una interruzione da
parte di un segnale; in tal caso verrà eseguito (\texttt{\small 45--48}) il
gestore \code{HandSIGTERM}, che semplicemente si limita a cancellare la coda
(\texttt{\small 46}) ed ad uscire (\texttt{\small 47}).

\begin{figure}[!bht]
  \footnotesize \centering
  \begin{minipage}[c]{15.6cm}
    \includecodesample{listati/MQFortuneClient.c}
  \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 fig.~\ref{fig:ipc_mq_fortune_client} si è riportato un estratto il codice
del programma client.  Al solito il codice completo è con i sorgenti allegati,
nel file \file{MQFortuneClient.c}.  Come sempre si sono rimosse le parti
relative alla gestione delle opzioni, ed in questo caso, anche la
dichiarazione delle variabili, che, per la parte relative alle strutture usate
per la comunicazione tramite le code, sono le stesse viste in
fig.~\ref{fig:ipc_mq_fortune_server}.

Il client in questo caso è molto semplice; la prima parte del programma
(\texttt{\small 4--9}) si occupa di accedere alla coda di messaggi, ed è
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.
 
Proviamo allora il nostro nuovo sistema, al solito occorre definire
\code{LD\_LIBRAY\_PATH} per accedere alla libreria \file{libgapil.so}, dopo di
che, in maniera del tutto analoga a quanto fatto con il programma che usa le
fifo, potremo far partire il server con:
\begin{verbatim}
[piccardi@gont sources]$ ./mqfortuned -n10
\end{verbatim}%$
come nel caso precedente, avendo eseguito il server in background, il comando
ritornerà immediatamente; potremo però verificare con \cmd{ps} che il
programma è effettivamente in esecuzione, e che ha creato una coda di
messaggi:
\begin{verbatim}
[piccardi@gont sources]$ ipcs

------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      

------ Semaphore Arrays --------
key        semid      owner      perms      nsems     

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
0x0102dc6a 0          piccardi   666        0            0           
\end{verbatim}
a questo punto potremo usare il client per ottenere le nostre frasi:
\begin{verbatim}
[piccardi@gont sources]$ ./mqfortune
Linux ext2fs has been stable for a long time, now it's time to break it
        -- Linuxkongreß '95 in Berlin
[piccardi@gont sources]$ ./mqfortune
Let's call it an accidental feature.
        --Larry Wall
\end{verbatim}
con un risultato del tutto equivalente al precedente. Infine potremo chiudere
il server inviando il segnale di terminazione con il comando \code{killall
  mqfortuned} verificando che effettivamente la coda di messaggi viene rimossa.

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 sez.~\ref{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 sez.~\ref{sec:ipc_sysv_mq}. L'argomento
\param{nsems} permette di specificare quanti semafori deve contenere l'insieme
quando se ne richieda la creazione, e deve essere nullo quando si effettua una
richiesta dell'identificatore di un insieme già esistente.

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}
    \includestruct{listati/semid_ds.h}
  \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 fig.~\ref{fig:ipc_semid_ds}.\footnote{non si sono riportati i
  campi ad uso interno del kernel, che vedremo in
  fig.~\ref{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
sez.~\ref{sec:ipc_sysv_access_control} (si ricordi che in questo caso il
permesso di scrittura è in realtà permesso di alterare il semaforo), per
quanto riguarda gli altri campi invece:
\begin{itemize*}
\item il campo \var{sem\_nsems}, che esprime il numero di semafori
  nell'insieme, viene inizializzato al valore di \param{nsems}.
\item il campo \var{sem\_ctime}, che esprime il tempo di creazione
  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 fig.~\ref{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}
    \includestruct{listati/sem.h}
  \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 fig.~\ref{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 tab.~\ref{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}
    \includestruct{listati/semun.h}
  \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
fig.~\ref{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
tab.~\ref{tab:ipc_semctl_returns} viene invece restituito il valore richiesto,
corrispondente al campo della struttura \struct{sem} indicato nella seconda
colonna della tabella.

Le operazioni ordinarie sui semafori, come l'acquisizione o il rilascio degli
stessi (in sostanza tutte quelle non comprese nell'uso di \func{semctl})
vengono effettuate con la funzione \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}
    \includestruct{listati/sembuf.h}
  \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
fig.~\ref{fig:ipc_sembuf}) che il programma chiamante deve avere cura di
allocare in un opportuno vettore. La struttura permette di indicare il
semaforo su cui operare, il tipo di operazione, ed un flag di controllo.
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 fig.~\ref{fig:ipc_sem_schema}.  Si è
presa come riferimento l'architettura usata fino al kernel 2.2.x che è più
semplice (ed illustrata in dettaglio in \cite{tlk}); nel kernel 2.4.x la
struttura del \textit{SysV IPC} è stata modificata, ma le definizioni relative
a queste strutture restano per compatibilità.\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{\textit{scheduler}} per passare all'esecuzione di un altro
processo.

Se invece tutte le operazioni possono avere successo queste vengono eseguite
immediatamente, dopo di che il kernel esegue una scansione della coda di
attesa (a partire da \var{sem\_pending}) per verificare se qualcuna delle
operazioni sospese in precedenza può essere eseguita, nel qual caso la
struttura \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 fig.~\ref{fig:ipc_mutex_create}. Utilizzeremo l'interfaccia per
creare un insieme contenente un singolo semaforo, per il quale poi useremo un
valore unitario per segnalare la disponibilità della risorsa, ed un valore
nullo per segnalarne l'indisponibilità. 

\begin{figure}[!bht]
  \footnotesize \centering
  \begin{minipage}[c]{15cm}
    \includecodesample{listati/Mutex.c}
  \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
semaforo; il valore di ritorno di quest'ultima viene passato all'indietro.

Chiamare \func{MutexLock} decrementa il valore del semaforo: se questo è
libero (ha già valore 1) sarà bloccato (valore nullo), se è bloccato la
chiamata a \func{semop} si bloccherà fintanto che la risorsa non venga
rilasciata. Chiamando \func{MutexUnlock} il valore del semaforo sarà
incrementato di uno, sbloccandolo qualora fosse bloccato.  

Si noti che occorre eseguire sempre prima \func{MutexLock} e poi
\func{MutexUnlock}, perché se per un qualche errore si esegue più volte
quest'ultima il valore del semaforo crescerebbe oltre 1, e \func{MutexLock}
non avrebbe più l'effetto aspettato (bloccare la risorsa quando questa è
considerata libera).  Infine si tenga presente che usare \func{MutexRead} per
controllare il valore dei mutex prima di proseguire in una operazione di
sblocco non servirebbe comunque, dato che l'operazione non sarebbe atomica.
Vedremo in sez.~\ref{sec:ipc_lock_file} come sia possibile ottenere
un'interfaccia analoga a quella appena illustrata, senza incorrere in questi
problemi, usando il 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 sez.~\ref{sec:ipc_sysv_mq}. L'argomento
\param{size} specifica invece la dimensione, in byte, del segmento, che viene
comunque arrotondata al multiplo superiore di \const{PAGE\_SIZE}.

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}
    \includestruct{listati/shmid_ds.h}
  \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 fig.~\ref{fig:ipc_shmid_ds}.  Come nel caso
delle code di messaggi quando si crea un nuovo segmento di memoria condivisa
con \func{shmget} questa struttura viene inizializzata, in particolare il
campo \var{shm\_perm} viene inizializzato come illustrato in
sez.~\ref{sec:ipc_sysv_access_control}, e valgono le considerazioni ivi fatte
relativamente ai permessi di accesso; per quanto riguarda gli altri campi
invece:
\begin{itemize}
\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 tab.~\ref{tab:ipc_shm_limits} si sono riportate le
costanti simboliche associate a ciascuno di essi, il loro significato, i
valori preimpostati, e, quando presente, il file in \file{/proc/sys/kernel/}
che permettono di cambiarne il valore. 


\begin{table}[htb]
  \footnotesize
  \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} non è un identificatore valido o
      \param{cmd} non è un comando valido.
    \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}] Si è tentato il comando \const{IPC\_STAT} ma il
      valore del group-ID o dell'user-ID è troppo grande per essere
      memorizzato nella struttura puntata dal \param{buf}.  
    \item[\errcode{EFAULT}] L'indirizzo specificato con \param{buf} non è
      valido.
    \end{errlist}
}
\end{functions}

Il comando specificato attraverso l'argomento \param{cmd} determina i diversi
effetti della funzione; i possibili valori che esso può assumere, ed il
corrispondente comportamento della funzione, 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
  che il processo chiamante abbia il permesso di lettura sulla segmento.
\item[\const{IPC\_RMID}] Marca il segmento di memoria condivisa per la
  rimozione, questo verrà cancellato effettivamente solo quando l'ultimo
  processo ad esso agganciato si sarà staccato. Questo comando può essere
  eseguito solo da un processo con user-ID effettivo corrispondente o al
  creatore del segmento, o al proprietario del segmento, o all'amministratore.
\item[\const{IPC\_SET}] Permette di modificare i permessi ed il proprietario
  del segmento.  Per modificare i valori di \var{shm\_perm.mode},
  \var{shm\_perm.uid} e \var{shm\_perm.gid} occorre essere il proprietario o
  il creatore del segmento, 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{\textit{memory~locking}}\footnote{impedisce cioè che la
    memoria usata per il segmento venga salvata su disco dal meccanismo della
    memoria virtuale\index{memoria~virtuale}; si ricordi quanto trattato in
    sez.~\ref{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}\index{\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 di messaggi e
gli insiemi di semafori, gli ultimi due sono delle estensioni specifiche
previste da Linux, che permettono di abilitare e disabilitare il meccanismo
della memoria virtuale\index{memoria~virtuale} per il segmento.

L'argomento \param{buf} viene utilizzato solo con i comandi \const{IPC\_STAT}
e \const{IPC\_SET} nel qual caso esso dovrà puntare ad una struttura
\struct{shmid\_ds} precedentemente allocata, in cui nel primo caso saranno
scritti i dati del segmento di memoria restituiti dalla funzione e da cui, nel
secondo caso, verranno letti i dati da impostare sul segmento.

Una volta che lo si è creato, per utilizzare un segmento di memoria condivisa
l'interfaccia prevede due funzioni, \funcd{shmat} e \func{shmdt}. La prima di
queste serve ad agganciare un segmento al processo chiamante, in modo che
quest'ultimo possa inserirlo nel suo spazio di indirizzi per potervi accedere;
il suo prototipo è:
\begin{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
fig.~\ref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si
ricordi quanto illustrato al proposito in sez.~\ref{sec:proc_mem_layout}). In
particolare l'indirizzo finale del segmento dati (quello impostato da
\func{brk}, vedi sez.~\ref{sec:proc_mem_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 sez.~\ref{sec:proc_fork} un segmento di memoria condivisa
agganciato ad un processo viene ereditato da un figlio attraverso una
\func{fork}, dato che quest'ultimo riceve una copia dello spazio degli
indirizzi del padre. Invece, dato che attraverso una \func{exec} viene
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.

\begin{figure}[!bht]
  \footnotesize \centering
  \begin{minipage}[c]{15.6cm}
    \includecodesample{listati/SharedMem.c}
  \end{minipage} 
  \normalsize 
  \caption{Il codice delle funzioni che permettono di creare, trovare e
    rimuovere un segmento di memoria condivisa.}
  \label{fig:ipc_sysv_shm_func}
\end{figure}

Come esempio di uso di queste funzioni vediamo come implementare una serie di
funzioni di libreria che ne semplifichino l'uso, automatizzando le operazioni
più comuni; il codice, contenuto nel file \file{SharedMem.c}, è riportato in
fig.~\ref{fig:ipc_sysv_shm_func}.

La prima funzione (\texttt{\small 3--16}) è \func{ShmCreate} che, data una
chiave, crea il segmento di memoria condivisa restituendo il puntatore allo
stesso. La funzione comincia (\texttt{\small 6}) con il chiamare
\func{shmget}, usando il flag \const{IPC\_CREATE} per creare il segmento
qualora non esista, ed assegnandogli i privilegi specificati dall'argomento
\var{perm} e la dimensione specificata dall'argomento \var{shm\_size}.  In
caso di errore (\texttt{\small 7--9}) si ritorna immediatamente un puntatore
nullo, altrimenti (\texttt{\small 10}) si prosegue agganciando il segmento di
memoria condivisa al processo con \func{shmat}. In caso di errore
(\texttt{\small 11--13}) si restituisce di nuovo un puntatore nullo, infine
(\texttt{\small 14}) si inizializza con \func{memset} il contenuto del
segmento al valore costante specificato dall'argomento \var{fill}, e poi si
ritorna il puntatore al segmento stesso.

La seconda funzione (\texttt{\small 17--31}) è \func{ShmFind}, che, data una
chiave, restituisce l'indirizzo del segmento ad essa associato. Anzitutto
(\texttt{\small 22}) si richiede l'identificatore del segmento con
\func{shmget}, ritornando (\texttt{\small 23--25}) un puntatore nullo in caso
di errore. Poi si prosegue (\texttt{\small 26}) agganciando il segmento al
processo con \func{shmat}, restituendo (\texttt{\small 27--29}) di nuovo un
puntatore nullo in caso di errore, se invece non ci sono errori si restituisce
il puntatore ottenuto da \func{shmat}.

La terza funzione (\texttt{\small 32--51}) è \func{ShmRemove} che, data la
chiave ed il puntatore associati al segmento di memoria condivisa, prima lo
sgancia dal processo e poi lo rimuove. Il primo passo (\texttt{\small 37}) è
la chiamata a \func{shmdt} per sganciare il segmento, restituendo
(\texttt{\small 38--39}) un valore -1 in caso di errore. Il passo successivo
(\texttt{\small 41}) è utilizzare \func{shmget} per ottenre l'identificatore
associato al segmento data la chiave \var{key}. Al solito si restituisce un
valore di -1 (\texttt{\small 42--45}) in caso di errore, mentre se tutto va
bene si conclude restituendo un valore nullo.

Benché la memoria condivisa costituisca il meccanismo di intercomunicazione
fra processi più veloce, essa non è sempre il più appropriato, dato che, come
abbiamo visto, si avrà comunque la necessità di una sincronizzazione degli
accessi.  Per questo motivo, quando la comunicazione fra processi è
sequenziale, altri meccanismi come le 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 sez.~\ref{sec:ipc_sysv_mq} per la
  comunicazione non sequenziale si possono usare le code di messaggi,
  attraverso l'uso del campo \var{mtype}, ma solo se quest'ultima può essere
  effettuata in forma di messaggio.} o quando non può avvenire secondo una
modalità predefinita.

Un esempio classico di uso della memoria condivisa è quello del
``\textit{monitor}'', in cui viene per scambiare informazioni fra un processo
server, che vi scrive dei dati di interesse generale che ha ottenuto, e i
processi client interessati agli stessi dati che così possono leggerli in
maniera completamente asincrona.  Con questo schema di funzionamento da una
parte si evita che ciascun processo client debba compiere l'operazione,
potenzialmente onerosa, di ricavare e trattare i dati, e dall'altra si evita
al processo server di dover gestire l'invio a tutti i client di tutti i dati
(non potendo il server sapere quali di essi servono effettivamente al singolo
client).

Nel nostro caso implementeremo un ``\textsl{monitor}'' di una directory: un
processo si incaricherà di tenere sotto controllo alcuni parametri relativi ad
una directory (il numero dei file contenuti, la dimensione totale, quante
directory, link simbolici, file normali, ecc.) che saranno salvati in un
segmento di memoria condivisa cui altri processi potranno accedere per
ricavare la parte di informazione che interessa.

In fig.~\ref{fig:ipc_dirmonitor_main} si è riportata la sezione principale del
corpo del programma server, insieme alle definizioni delle altre funzioni
usate nel programma e delle variabili globali, omettendo tutto quello che
riguarda la gestione delle opzioni e la stampa delle istruzioni di uso a
video; al solito il codice completo si trova con i sorgenti allegati nel file
\file{DirMonitor.c}.

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15.6cm}
    \includecodesample{listati/DirMonitor.c}
  \end{minipage} 
  \normalsize 
  \caption{Codice della funzione principale del programma \file{DirMonitor.c}.}
  \label{fig:ipc_dirmonitor_main}
\end{figure}

Il programma usa delle variabili globali (\texttt{\small 2--14}) per mantenere
i valori relativi agli oggetti usati per la comunicazione inter-processo; si è
definita inoltre una apposita struttura \struct{DirProp} che contiene i dati
relativi alle proprietà che si vogliono mantenere nella memoria condivisa, per
l'accesso da parte dei client.

Il programma, dopo la sezione, omessa, relativa alla gestione delle opzioni da
riga di comando (che si limitano alla eventuale stampa di un messaggio di
aiuto a video ed all'impostazione della durata dell'intervallo con cui viene
ripetuto il calcolo delle proprietà della directory) controlla (\texttt{\small
  20--23}) che sia stato specificato il parametro necessario contenente il
nome della directory da tenere sotto controllo, senza il quale esce
immediatamente con un messaggio di errore.

Poi, per verificare che il parametro specifichi effettivamente una directory,
si esegue (\texttt{\small 24--26}) su di esso una \func{chdir}, uscendo
immediatamente in caso di errore.  Questa funzione serve anche per impostare
la directory di lavoro del programma nella directory da tenere sotto
controllo, in vista del successivo uso della funzione
\func{daemon}.\footnote{si noti come si è potuta fare questa scelta,
  nonostante le indicazioni illustrate in sez.~\ref{sec:sess_daemon}, per il
  particolare scopo del programma, che necessita comunque di restare
  all'interno di una directory.} Infine (\texttt{\small 27--29}) si installano
i gestori per i vari segnali di terminazione che, avendo a che fare con un
programma che deve essere eseguito come server, sono il solo strumento
disponibile per concluderne l'esecuzione.

Il passo successivo (\texttt{\small 30--39}) è quello di creare gli oggetti di
intercomunicazione necessari. Si inizia costruendo (\texttt{\small 30}) la
chiave da usare come riferimento con il nome del programma,\footnote{si è
  usato un riferimento relativo alla home dell'utente, supposto che i sorgenti
  di GaPiL siano stati installati direttamente in essa. Qualora si effettui
  una installazione diversa si dovrà correggere il programma.} dopo di che si
richiede (\texttt{\small 31}) la creazione di un segmento di memoria condivisa
con usando la funzione \func{ShmCreate} illustrata in precedenza (una pagina
di memoria è sufficiente per i dati che useremo), uscendo (\texttt{\small
  32--35}) qualora la creazione ed il successivo agganciamento al processo non
abbia successo. Con l'indirizzo \var{shmptr} così ottenuto potremo poi
accedere alla memoria condivisa, che, per come abbiamo lo abbiamo definito,
sarà vista nella forma data da \struct{DirProp}. Infine (\texttt{\small
  36--39}) utilizzando sempre la stessa chiave, si crea, tramite le funzioni
di interfaccia già descritte in sez.~\ref{sec:ipc_sysv_sem}, anche un mutex,
che utilizzeremo per regolare l'accesso alla memoria condivisa.

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15.6cm}
    \includecodesample{listati/ComputeValues.c}
  \end{minipage} 
  \normalsize 
  \caption{Codice delle funzioni ausiliarie usate da \file{DirMonitor.c}.}
  \label{fig:ipc_dirmonitor_sub}
\end{figure}

Completata l'inizializzazione e la creazione degli oggetti di
intercomunicazione il programma entra nel ciclo principale (\texttt{\small
  40--49}) dove vengono eseguite indefinitamente le attività di monitoraggio.
Il primo passo (\texttt{\small 41}) è eseguire \func{daemon} per proseguire
con l'esecuzione in background come si conviene ad un programma demone; si
noti che si è mantenuta, usando un valore non nullo del primo argomento, la
directory di lavoro corrente.  Una volta che il programma è andato in
background l'esecuzione prosegue (\texttt{\small 42--48}) all'interno di un
ciclo infinito: si inizia (\texttt{\small 43}) bloccando il mutex con
\func{MutexLock} per poter accedere alla memoria condivisa (la funzione si
bloccherà automaticamente se qualche client sta leggendo), poi (\texttt{\small
  44}) si cancellano i valori precedentemente immagazzinati nella memoria
condivisa con \func{memset}, e si esegue (\texttt{\small 45}) un nuovo calcolo
degli stessi utilizzando la funzione \func{DirScan}; infine (\texttt{\small
  46}) si sblocca il mutex con \func{MutexUnlock}, e si attende
(\texttt{\small 47}) per il periodo di tempo specificato a riga di comando con
l'opzione \code{-p} con una \func{sleep}.

Si noti come per il calcolo dei valori da mantenere nella memoria condivisa si
sia usata ancora una volta la funzione \func{DirScan}, già utilizzata (e
descritta in dettaglio) in sez.~\ref{sec:file_dir_read}, che ci permette di
effettuare la scansione delle voci della directory, chiamando per ciascuna di
esse la funzione \func{ComputeValues}, che esegue tutti i calcoli necessari.

Il codice di quest'ultima è riportato in fig.~\ref{fig:ipc_dirmonitor_sub}.
Come si vede la funzione (\texttt{\small 2--16}) è molto semplice e si limita
a chiamare (\texttt{\small 5}) la funzione \func{stat} sul file indicato da
ciascuna voce, per ottenerne i dati, che poi utilizza per incrementare i vari
contatori nella memoria condivisa, cui accede grazie alla variabile globale
\var{shmptr}.

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

In fig.~\ref{fig:ipc_dirmonitor_sub} è riportato anche il codice
(\texttt{\small 17--23}) del gestore dei segnali di terminazione, usato per
chiudere il programma. Esso, oltre a provocare l'uscita del programma, si
incarica anche di cancellare tutti gli oggetti di intercomunicazione non più
necessari.  Per questo anzitutto (\texttt{\small 19}) acquisisce il mutex con
\func{MutexLock}, per evitare di operare mentre un client sta ancora leggendo
i dati, dopo di che (\texttt{\small 20}) distacca e rimuove il segmento di
memoria condivisa usando \func{ShmRemove}.  Infine (\texttt{\small 21})
rimuove il mutex con \func{MutexRemove} ed esce (\texttt{\small 22}).

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15.6 cm}
    \includecodesample{listati/ReadMonitor.c}
  \end{minipage} 
  \normalsize 
  \caption{Codice del programma client del monitor delle proprietà di una
    directory, \file{ReadMonitor.c}.}
  \label{fig:ipc_dirmonitor_client}
\end{figure}

Il codice del client usato per leggere le informazioni mantenute nella memoria
condivisa è riportato in fig.~\ref{fig:ipc_dirmonitor_client}. Al solito si è
omessa la sezione di gestione delle opzioni e la funzione che stampa a video
le istruzioni; il codice completo è nei sorgenti allegati, nel file
\file{ReadMonitor.c}.

Una volta conclusa la gestione delle opzioni a riga di comando il programma
rigenera (\texttt{\small 7}) con \func{ftok} la stessa chiave usata dal server
per identificare il segmento di memoria condivisa ed il mutex, poi
(\texttt{\small 8}) richiede con \func{ShmFind} l'indirizzo della memoria
condivisa agganciando al contempo il segmento al processo, Infine
(\texttt{\small 17--20}) con \func{MutexFind} si richiede l'identificatore del
mutex.  Completata l'inizializzazione ed ottenuti i riferimenti agli oggetti
di intercomunicazione necessari viene eseguito il corpo principale del
programma (\texttt{\small 21--33}); si comincia (\texttt{\small 22})
acquisendo il mutex con \func{MutexLock}; qui avviene il blocco del processo
se la memoria condivisa non è disponibile.  Poi (\texttt{\small 23--31}) si
stampano i vari valori mantenuti nella memoria condivisa attraverso l'uso di
\var{shmptr}.  Infine (\texttt{\small 41}) con \func{MutexUnlock} si rilascia
il mutex, prima di uscire.

Verifichiamo allora il funzionamento dei nostri programmi; al solito, usando
le funzioni di libreria occorre definire opportunamente
\code{LD\_LIBRARY\_PATH}; poi si potrà lanciare il server con:
\begin{verbatim}
[piccardi@gont sources]$ ./dirmonitor ./
\end{verbatim}%$
ed avendo usato \func{daemon} il comando ritornerà immediatamente. Una volta
che il server è in esecuzione, possiamo passare ad invocare il client per
verificarne i risultati, in tal caso otterremo:
\begin{verbatim}
[piccardi@gont sources]$ ./readmon 
Ci sono 68 file dati
Ci sono 3 directory
Ci sono 0 link
Ci sono 0 fifo
Ci sono 0 socket
Ci sono 0 device a caratteri
Ci sono 0 device a blocchi
Totale  71 file, per 489831 byte
\end{verbatim}%$
ed un rapido calcolo (ad esempio con \code{ls -a | wc} per contare i file) ci
permette di verificare che il totale dei file è giusto. Un controllo con
\cmd{ipcs} ci permette inoltre di verificare la presenza di un segmento di
memoria condivisa e di un semaforo:
\begin{verbatim}
[piccardi@gont sources]$ ipcs
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0xffffffff 54067205   piccardi  666        4096       1                       

------ Semaphore Arrays --------
key        semid      owner      perms      nsems     
0xffffffff 229376     piccardi  666        1         

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
\end{verbatim}%$

Se a questo punto aggiungiamo un file, ad esempio con \code{touch prova},
potremo verificare che, passati nel peggiore dei casi almeno 10 secondi (o
l'eventuale altro intervallo impostato per la rilettura dei dati) avremo:
\begin{verbatim}
[piccardi@gont sources]$ ./readmon 
Ci sono 69 file dati
Ci sono 3 directory
Ci sono 0 link
Ci sono 0 fifo
Ci sono 0 socket
Ci sono 0 device a caratteri
Ci sono 0 device a blocchi
Totale  72 file, per 489887 byte
\end{verbatim}%$

A questo punto possiamo far uscire il server inviandogli un segnale di
\const{SIGTERM} con il comando \code{killall dirmonitor}, a questo punto
ripetendo la lettura, otterremo un errore:
\begin{verbatim}
[piccardi@gont sources]$ ./readmon 
Cannot find shared memory: No such file or directory
\end{verbatim}%$
e inoltre potremo anche verificare che anche gli oggetti di intercomunicazione
visti in precedenza sono stati regolarmente  cancellati:
\begin{verbatim}
[piccardi@gont sources]$ ipcs
------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      

------ Semaphore Arrays --------
key        semid      owner      perms      nsems     

------ Message Queues --------
key        msqid      owner      perms      used-bytes   messages    
\end{verbatim}%$



%% Per capire meglio il funzionamento delle funzioni facciamo ancora una volta
%% riferimento alle strutture con cui il kernel implementa i segmenti di memoria
%% condivisa; uno schema semplificato della struttura è illustrato in
%% fig.~\ref{fig:ipc_shm_struct}. 

%% \begin{figure}[htb]
%%   \centering
%%   \includegraphics[width=10cm]{img/shmstruct}
%%    \caption{Schema dell'implementazione dei segmenti di memoria condivisa in
%%     Linux.}
%%   \label{fig:ipc_shm_struct}
%% \end{figure}




\section{Tecniche alternative}
\label{sec:ipc_alternatives}

Come abbiamo detto in sez.~\ref{sec:ipc_sysv_generic}, e ripreso nella
descrizione dei singoli oggetti che ne fan parte, il \textit{SysV IPC}
presenta numerosi problemi; in \cite{APUE}\footnote{in particolare nel
  capitolo 14.}  Stevens 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 sez.~\ref{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 sez.~\ref{sec:ipc_sysv_sem} i semafori del \textit{SysV IPC}
presentano una interfaccia inutilmente complessa e con alcuni difetti
strutturali, per questo quando si ha una semplice esigenza di sincronizzazione
per la quale basterebbe un semaforo binario (quello che abbiamo definito come
\textit{mutex}), per indicare la disponibilità o meno di una risorsa, senza la
necessità di un contatore come i semafori, si possono utilizzare metodi
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
sez.~\ref{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{\textit{race~condition}}.} che essa ritorni un errore quando
usata con i flag di \const{O\_CREAT} e \const{O\_EXCL}. In tal modo la
creazione di un \textsl{file di lock} può essere eseguita atomicamente, il
processo che crea il file con successo si può considerare come titolare del
lock (e della risorsa ad esso associata) mentre il rilascio si può eseguire
con una chiamata ad \func{unlink}.

Un esempio dell'uso di questa funzione è mostrato dalle funzioni
\func{LockFile} ed \func{UnlockFile} riportate in fig.~\ref{fig:ipc_file_lock}
(sono contenute in \file{LockFile.c}, un'altro dei sorgenti allegati alla
guida) che permettono rispettivamente di creare e rimuovere un \textsl{file di
  lock}. Come si può notare entrambe le funzioni sono elementari; la prima
(\texttt{\small 4--10}) si limita ad aprire il file di lock (\texttt{\small
  9}) nella modalità descritta, mentre la seconda (\texttt{\small 11--17}) lo
cancella con \func{unlink}.

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15.6cm}
    \includecodesample{listati/LockFile.c}
  \end{minipage} 
  \normalsize 
  \caption{Il codice delle funzioni \func{LockFile} e \func{UnlockFile} che
    permettono di creare e rimuovere un \textsl{file di lock}.}
  \label{fig:ipc_file_lock}
\end{figure}

Uno dei limiti di questa tecnica è che, come abbiamo già accennato in
sez.~\ref{sec:file_open}, 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{\textit{polling}}, ed è quindi molto inefficiente.

La tecnica dei file di lock ha comunque una sua utilità, e può essere usata
con successo quando l'esigenza è solo quella di segnalare l'occupazione di una
risorsa, senza necessità di attendere che questa si liberi; ad esempio la si
usa spesso per evitare interferenze sull'uso delle porte seriali da parte di
più programmi: qualora si trovi un file di lock il programma che cerca di
accedere alla seriale si limita a segnalare che la risorsa non è
disponibile.\index{file!di lock|)}


\subsection{La sincronizzazione con il \textit{file locking}}
\label{sec:ipc_lock_file}

Dato che i file di lock\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 sez.~\ref{sec:file_locking}) usando \func{fcntl} su un file
creato per l'occasione per ottenere un write lock. In questo modo potremo
usare il lock come un \textit{mutex}: per bloccare la risorsa basterà
acquisire il lock, per sbloccarla basterà rilasciare il lock. Una richiesta
fatta con un write lock metterà automaticamente il processo in stato di
attesa, senza necessità di ricorrere al
\textit{polling}\index{\textit{polling}} per determinare la disponibilità
della risorsa, e al rilascio della stessa da parte del processo che la
occupava si otterrà il nuovo lock atomicamente.

Questo approccio presenta il notevole vantaggio che alla terminazione di un
processo tutti i lock acquisiti vengono rilasciati automaticamente (alla
chiusura dei relativi file) e non ci si deve preoccupare di niente; inoltre
non consuma risorse permanentemente allocate nel sistema. Lo svantaggio è che,
dovendo fare ricorso a delle operazioni sul filesystem, esso è in genere
leggermente più lento.

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15.6cm}
    \includecodesample{listati/MutexLocking.c}
  \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 fig.~\ref{fig:ipc_flock_mutex};
si è mantenuta volutamente una struttura analoga alle precedenti funzioni che
usano i semafori, anche se le due interfacce non possono essere completamente
equivalenti, specie per quanto riguarda la rimozione del mutex.

La prima funzione (\texttt{\small 1--5}) è \func{CreateMutex}, e serve a
creare il mutex; la funzione è estremamente semplice, e si limita
(\texttt{\small 4}) a creare, con una opportuna chiamata ad \func{open}, il
file che sarà usato per il successivo file locking, assicurandosi che non
esista già (nel qual caso segnala un errore); poi restituisce il file
descriptor che sarà usato dalle altre funzioni per acquisire e rilasciare il
mutex.

La seconda funzione (\texttt{\small 6--10}) è \func{FindMutex}, che, come la
precedente, è stata definita per mantenere una analogia con la corrispondente
funzione basata sui semafori. Anch'essa si limita (\texttt{\small 9}) ad
aprire il file da usare per il file locking, solo che in questo caso le
opzioni di \func{open} sono tali che il file in questione deve esistere di
già.

La terza funzione (\texttt{\small 11--22}) è \func{LockMutex} e serve per
acquisire il mutex. La funzione definisce (\texttt{\small 14}) e inizializza
(\texttt{\small 16--19}) la struttura \var{lock} da usare per acquisire un
write lock sul file, che poi (\texttt{\small 21}) viene richiesto con
\func{fcntl}, restituendo il valore di ritorno di quest'ultima. Se il file è
libero il lock viene acquisito e la funzione ritorna immediatamente;
altrimenti \func{fcntl} si bloccherà (si noti che la si è chiamata con
\func{F\_SETLKW}) fino al rilascio del lock.

La quarta funzione (\texttt{\small 24--34}) è \func{UnlockMutex} e serve a
rilasciare il mutex. La funzione è analoga alla precedente, solo che in questo
caso si inizializza (\texttt{\small 28--31}) la struttura \var{lock} per il
rilascio del lock, che viene effettuato (\texttt{\small 33}) con la opportuna
chiamata a \func{fcntl}. Avendo usato il file locking in semantica POSIX (si
riveda quanto detto sez.~\ref{sec:file_posix_lock}) solo il processo che ha
precedentemente eseguito il lock può sbloccare il mutex.

La quinta funzione (\texttt{\small 36--39}) è \func{RemoveMutex} e serve a
cancellare il mutex. Anche questa funzione è stata definita per mantenere una
analogia con le funzioni basate sui semafori, e si limita a cancellare
(\texttt{\small 38}) il file con una chiamata ad \func{unlink}. Si noti che in
questo caso la funzione non ha effetto sui mutex già ottenuti con precedenti
chiamate a \func{FindMutex} o \func{CreateMutex}, che continueranno ad essere
disponibili fintanto che i relativi file descriptor restano aperti. Pertanto
per rilasciare un mutex occorrerà prima chiamare \func{UnlockMutex} oppure
chiudere il file usato per il lock.

La sesta funzione (\texttt{\small 41--55}) è \func{ReadMutex} e serve a
leggere lo stato del mutex. In questo caso si prepara (\texttt{\small 46--49})
la solita struttura \var{lock} come l'acquisizione del lock, ma si effettua
(\texttt{\small 51}) la chiamata a \func{fcntl} usando il comando
\const{F\_GETLK} per ottenere lo stato del lock, e si restituisce
(\texttt{\small 52}) il valore di ritorno in caso di errore, ed il valore del
campo \var{l\_type} (che descrive lo stato del lock) altrimenti
(\texttt{\small 54}). Per questo motivo la funzione restituirà -1 in caso di
errore e uno dei due valori \const{F\_UNLCK} o \const{F\_WRLCK}\footnote{non
  si dovrebbe mai avere il terzo valore possibile, \const{F\_RDLCK}, dato che
  la nostra interfaccia usa solo i write lock. Però è sempre possibile che
  siano richiesti altri lock sul file al di fuori dell'interfaccia, nel qual
  caso si potranno avere, ovviamente, interferenze indesiderate.} in caso di
successo, ad indicare che il mutex è, rispettivamente, libero o occupato.

Basandosi sulla semantica dei file lock POSIX valgono tutte le considerazioni
relative al comportamento di questi ultimi fatte in
sez.~\ref{sec:file_posix_lock}; questo significa ad esempio che, al contrario
di quanto avveniva con l'interfaccia basata sui semafori, chiamate multiple a
\func{UnlockMutex} o \func{LockMutex} non si cumulano e non danno perciò
nessun inconveniente.


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

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

In sez.~\ref{sec:file_memory_map} abbiamo visto come sia possibile mappare il
contenuto di un file nella memoria di un processo, e che, quando viene usato
il flag \const{MAP\_SHARED}, le modifiche effettuate al contenuto del file
vengono viste da tutti i processi che lo hanno mappato. Utilizzare questa
tecnica per creare una memoria condivisa fra processi diversi è estremamente
inefficiente, in quanto occorre passare attraverso il disco. Però abbiamo
visto anche che se si esegue la mappatura con il flag \const{MAP\_ANONYMOUS}
la regione mappata non viene associata a nessun file, anche se quanto scritto
rimane in memoria e può essere riletto; allora, dato che un processo figlio
mantiene nel suo spazio degli indirizzi anche le regioni mappate, esso sarà
anche in grado di accedere a quanto in esse è contenuto.

In questo modo diventa possibile creare una memoria condivisa fra processi
diversi, purché questi abbiano almeno un progenitore comune che ha effettuato
il \textit{memory mapping} anonimo.\footnote{nei sistemi derivati da SysV una
  funzionalità simile a questa viene implementata mappando il file speciale
  \file{/dev/zero}. In tal caso i valori scritti nella regione mappata non
  vengono ignorati (come accade qualora si scriva direttamente sul file), ma
  restano in memoria e possono essere riletti secondo le stesse modalità usate
  nel \textit{memory mapping} anonimo.} Vedremo come utilizzare questa tecnica
più avanti, quando realizzeremo una nuova versione del monitor visto in
sez.~\ref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete.



\section{Il sistema di 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 sez.~\ref{sec:ipc_sysv_generic} e per i singoli
oggetti nei paragrafi successivi, lo standard POSIX.1b ha introdotto dei nuovi
meccanismi di comunicazione, che vanno sotto il nome di POSIX IPC, definendo
una interfaccia completamente nuova, che tratteremo in questa sezione.


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

In Linux non tutti gli oggetti del POSIX IPC sono pienamente supportati nel
kernel ufficiale; solo la memoria condivisa è presente con l'interfaccia
completa, ma solo a partire dal kernel 2.4.x, i semafori sono forniti dalle
\acr{glibc} nella sezione che implementa i thread POSIX, le code di messaggi
non hanno alcun tipo di supporto ufficiale.  Per queste ultime esistono
tuttavia dei patch e una libreria aggiuntiva.

La caratteristica fondamentale dell'interfaccia POSIX è l'abbandono dell'uso
degli identificatori e delle chiavi visti nel SysV IPC, per passare ai
\textit{Posix IPC names}\index{\textit{Posix~IPC~names}}, che sono
sostanzialmente equivalenti ai nomi dei file. Tutte le funzioni che creano un
oggetto di IPC Posix prendono come primo argomento una stringa che indica uno
di questi nomi; lo standard è molto generico riguardo l'implementazione, ed i
nomi stessi possono avere o meno una corrispondenza sul filesystem; tutto
quello che è richiesto è che:
\begin{itemize}
\item i nomi devono essere conformi alle regole che caratterizzano i
  \index{\textit{pathname}}\textit{pathname}, in particolare non essere più
  lunghi di \const{PATH\_MAX} byte e terminati da un carattere nullo.
\item se il nome inizia per una \texttt{/} chiamate differenti allo stesso
  nome fanno riferimento allo stesso oggetto, altrimenti l'interpretazione del
  nome dipende dall'implementazione.
\item l'interpretazione di ulteriori \texttt{/} presenti nel nome dipende
  dall'implementazione.
\end{itemize}

Data la assoluta genericità delle specifiche, il comportamento delle funzioni
è pertanto subordinato in maniera quasi completa alla relativa
implementazione.\footnote{tanto che Stevens in \cite{UNP2} cita questo caso
  come un esempio della maniera standard usata dallo standard POSIX per
  consentire implementazioni non standardizzabili.} Nel caso di Linux, sia per
quanto riguarda la memoria condivisa, che per quanto riguarda le code di
messaggi, tutto viene creato usando come radici delle opportune directory
(rispettivamente \file{/dev/shm} e \file{/dev/mqueue}, per i dettagli si
faccia riferimento a sez.~\ref{sec:ipc_posix_shm} e
sez.~\ref{sec:ipc_posix_mq}) ed i nomi specificati nelle relative funzioni
sono considerati come un \index{\textit{pathname}!assoluto}\textit{pathname}
assoluto (comprendente eventuali sottodirectory) rispetto a queste radici.

Il vantaggio degli oggetti di IPC POSIX è comunque che essi vengono inseriti
nell'albero dei file, e possono essere maneggiati con le usuali funzioni e
comandi di accesso ai file,\footnote{questo è ancora più vero nel caso di
  Linux, che usa una implementazione che lo consente, non è detto che
  altrettanto valga per altri kernel. In particolare sia la memoria condivisa
  che per le code di messaggi, come si può facilmente evincere con uno
  \cmd{strace}, le system call utilizzate sono le stesse, in quanto esse sono
  realizzate con dei file in speciali filesystem.}  che funzionano come su dei
file normali.

In particolare i permessi associati agli oggetti di IPC POSIX sono identici ai
permessi dei file, e il controllo di accesso segue esattamente la stessa
semantica (quella illustrata in sez.~\ref{sec:file_access_control}), invece di
quella particolare (si ricordi quanto visto in
sez.~\ref{sec:ipc_sysv_access_control}) usata per gli oggetti del SysV IPC. Per
quanto riguarda l'attribuzione dell'utente e del gruppo proprietari
dell'oggetto alla creazione di quest'ultimo essa viene effettuata secondo la
semantica SysV (essi corrispondono cioè a userid e groupid effettivi del
processo che esegue la creazione).



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

Le code di messaggi non sono ancora supportate nel kernel ufficiale, esiste
però una implementazione sperimentale di Michal Wronski e Krzysztof
Benedyczak,\footnote{i patch al kernel e la relativa libreria possono essere
  trovati su \href{http://www.mat.uni.torun.pl/~wrona/posix_ipc}
  {http://www.mat.uni.torun.pl/\tild{}wrona/posix\_ipc}, questi sono stati
  inseriti nel kernel ufficiale a partire dalla versione 2.6.6-rc1.}.  In
generale, come le corrispettive del SysV IPC, le code di messaggi sono poco
usate, dato che i socket\index{socket}, nei casi in cui sono sufficienti, sono
più comodi, e che in casi più complessi la comunicazione può essere gestita
direttamente con mutex e memoria condivisa con tutta la flessibilità che
occorre.

Per poter utilizzare le code di messaggi, oltre ad utilizzare un kernel cui
siano stati opportunamente applicati i relativi patch, occorre utilizzare la
libreria \file{mqueue}\footnote{i programmi che usano le code di messaggi cioè
  devono essere compilati aggiungendo l'opzione \code{-lmqueue} al comando
  \cmd{gcc}, dato che le funzioni non fanno parte della libreria standard, in
  corrispondenza all'inclusione del supporto nel kernel ufficiale, anche le
  relative funzioni sono state inserite nelle \acr{glibc} a partire dalla
  versione 2.3.4.}  che contiene le funzioni dell'interfaccia
POSIX.\footnote{in realtà l'implementazione è realizzata tramite delle
  speciali chiamate ad \func{ioctl} sui file del filesystem speciale su cui
  vengono mantenuti questi oggetti di IPC.}


La libreria inoltre richiede la presenza dell'apposito filesystem di tipo
\texttt{mqueue} montato su \file{/dev/mqueue}; questo può essere fatto
aggiungendo ad \file{/etc/fstab} una riga come:
\begin{verbatim}
mqueue   /dev/mqueue       mqueue    defaults        0      0
\end{verbatim}
ed esso sarà utilizzato come radice sulla quale vengono risolti i nomi delle
code di messaggi che iniziano con una \texttt{/}. Le opzioni di mount
accettate sono \texttt{uid}, \texttt{gid} e \texttt{mode} che permettono
rispettivamente di impostare l'utente, il gruppo ed i permessi associati al
filesystem.


La funzione che permette di aprire (e crearla se non esiste ancora) una coda
di messaggi POSIX è \funcd{mq\_open}, ed il suo prototipo è:
\begin{functions}
  \headdecl{mqueue.h} 
  
  \funcdecl{mqd\_t mq\_open(const char *name, int oflag)}
  
  \funcdecl{mqd\_t mq\_open(const char *name, int oflag, unsigned long mode,
    struct mq\_attr *attr)}
  
  Apre una coda di messaggi POSIX impostandone le caratteristiche.
  
  \bodydesc{La funzione restituisce il descrittore associato alla coda in caso
    di successo e -1 in caso di errore; nel quel caso \var{errno} assumerà i
    valori:
    \begin{errlist}
    \item[\errcode{EACCESS}] Il processo non ha i privilegi per accedere al
      alla memoria secondo quanto specificato da \param{oflag}.
    \item[\errcode{EEXIST}] Si è specificato \const{O\_CREAT} e
      \const{O\_EXCL} ma la coda già esiste.
    \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale.
    \item[\errcode{EINVAL}] Il file non supporta la funzione, o si è
      specificato \const{O\_CREAT} con una valore non nullo di \param{attr} e
      valori non validi di \var{mq\_maxmsg} e \var{mq\_msgsize}.
    \item[\errcode{ENOENT}] Non si è specificato \const{O\_CREAT} ma la coda
      non esiste.
    \end{errlist}
    ed inoltre \errval{ENOMEM}, \errval{ENOSPC}, \errval{EFAULT},
    \errval{EMFILE} ed \errval{ENFILE}.}
\end{functions}

La funzione apre la coda di messaggi identificata dall'argomento \param{name}
restituendo il descrittore ad essa associato, del tutto analogo ad un file
descriptor, con l'unica differenza che lo standard prevede un apposito tipo
\type{mqd\_t}.\footnote{nella implementazione citata questo è definito come
  \ctyp{int}.} Se la coda esiste già il descrittore farà riferimento allo
stesso oggetto, consentendo così la comunicazione fra due processi diversi.

La funzione è del tutto analoga ad \func{open} ed analoghi sono i valori che
possono essere specificati per \param{oflag}, che deve essere specificato come
maschera binaria; i valori possibili per i vari bit sono quelli visti in
tab.~\ref{tab:file_open_flags} dei quali però \func{mq\_open} riconosce solo i
seguenti:
\begin{basedescript}{\desclabelwidth{2cm}\desclabelstyle{\nextlinelabel}}
\item[\const{O\_RDONLY}] Apre la coda solo per la ricezione di messaggi. Il
  processo potrà usare il descrittore con \func{mq\_receive} ma non con
  \func{mq\_send}.
\item[\const{O\_WRONLY}] Apre la coda solo per la trasmissione di messaggi. Il
  processo potrà usare il descrittore con \func{mq\_send} ma non con
  \func{mq\_receive}.
\item[\const{O\_RDWR}] Apre la coda solo sia per la trasmissione che per la
  ricezione. 
\item[\const{O\_CREAT}] Necessario qualora si debba creare la coda; la
  presenza di questo bit richiede la presenza degli ulteriori argomenti
  \param{mode} e \param{attr}.
\item[\const{O\_EXCL}] Se usato insieme a \const{O\_CREAT} fa fallire la
  chiamata se la coda esiste già, altrimenti esegue la creazione atomicamente.
\item[\const{O\_NONBLOCK}] Imposta la coda in modalità non bloccante, le
  funzioni di ricezione e trasmissione non si bloccano quando non ci sono le
  risorse richieste, ma ritornano immediatamente con un errore di
  \errcode{EAGAIN}.
\end{basedescript}

I primi tre bit specificano la modalità di apertura della coda, e sono fra
loro esclusivi. Ma qualunque sia la modalità in cui si è aperta una coda,
questa potrà essere riaperta più volte in una modalità diversa, e vi si potrà
sempre accedere attraverso descrittori diversi, esattamente come si può fare
per i file normali.

Se la coda non esiste e la si vuole creare si deve specificare
\const{O\_CREAT}, in tal caso occorre anche specificare i permessi di
creazione con l'argomento \param{mode}; i valori di quest'ultimo sono identici
a quelli usati per \func{open}, anche se per le code di messaggi han senso
solo i permessi di lettura e scrittura. Oltre ai permessi di creazione possono
essere specificati anche gli attributi specifici della coda tramite
l'argomento \param{attr}; quest'ultimo è un puntatore ad una apposita
struttura \struct{mq\_attr}, la cui definizione è riportata in
fig.~\ref{fig:ipc_mq_attr}.

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15cm}
    \includestruct{listati/mq_attr.h}
  \end{minipage} 
  \normalsize
  \caption{La struttura \structd{mq\_attr}, contenente gli attributi di una
    coda di messaggi POSIX.}
  \label{fig:ipc_mq_attr}
\end{figure}

Per ls creazione della coda i campi della struttura che devono essere
specificati sono \var{mq\_msgsize} e \var{mq\_maxmsg}, che indicano
rispettivamente la dimensione massima di un messaggio ed il numero massimo di
messaggi che essa può contenere. Il valore dovrà essere positivo e minore dei
rispettivi limiti di sistema \const{MQ\_MAXMSG} e \const{MQ\_MSGSIZE},
altrimenti la funzione fallirà con un errore di \errcode{EINVAL}.  Qualora si
specifichi per \param{attr} un puntatore nullo gli attributi della coda
saranno impostati ai valori predefiniti.

Quando l'accesso alla coda non è più necessario si può chiudere il relativo
descrittore con la funzione \funcd{mq\_close}, il cui prototipo è:
\begin{prototype}{mqueue.h}
{int mq\_close(mqd\_t mqdes)}

Chiude la coda \param{mqdes}.
  
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
  errore; nel quel caso \var{errno} assumerà i valori \errval{EBADF} o
  \errval{EINTR}.}
\end{prototype}

La funzione è analoga a \func{close},\footnote{in Linux, dove le code sono
  implementate come file su un filesystem dedicato, è esattamente la stessa
  funzione.} dopo la sua esecuzione il processo non sarà più in grado di usare
il descrittore della coda, ma quest'ultima continuerà ad esistere nel sistema
e potrà essere acceduta con un'altra chiamata a \func{mq\_open}. All'uscita di
un processo tutte le code aperte, così come i file, vengono chiuse
automaticamente. Inoltre se il processo aveva agganciato una richiesta di
notifica sul descrittore che viene chiuso, questa sarà rilasciata e potrà
essere richiesta da qualche altro processo.


Quando si vuole effettivamente rimuovere una coda dal sistema occorre usare la
funzione \funcd{mq\_unlink}, il cui prototipo è:
\begin{prototype}{mqueue.h}
{int mq\_unlink(const char *name)}

Rimuove una coda di messaggi.
  
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
  errore; nel quel caso \var{errno} assumerà gli stessi valori riportati da
  \func{unlink}.}
\end{prototype}

Anche in questo caso il comportamento della funzione è analogo a quello di
\func{unlink} per i file,\footnote{di nuovo l'implementazione di Linux usa
  direttamente \func{unlink}.} la funzione rimove la coda \param{name}, così
che una successiva chiamata a \func{mq\_open} fallisce o crea una coda
diversa. 

Come per i file ogni coda di messaggi ha un contatore di riferimenti, per cui
la coda non viene effettivamente rimossa dal sistema fin quando questo non si
annulla. Pertanto anche dopo aver eseguito con successo \func{mq\_unlink} la
coda resterà accessibile a tutti i processi che hanno un descrittore aperto su
di essa.  Allo stesso modo una coda ed i suoi contenuti resteranno disponibili
all'interno del sistema anche quando quest'ultima non è aperta da nessun
processo (questa è una delle differenze più rilevanti nei confronti di pipe e
fifo).

La sola differenza fra code di messaggi POSIX e file normali è che, essendo il
filesystem delle code di messaggi virtuale e basato su oggetti interni al
kernel, il suo contenuto viene perduto con il riavvio del sistema.

Come accennato in precedenza ad ogni coda di messaggi è associata una
struttura \struct{mq\_attr}, che può essere letta e modificata attraverso le
due funzioni \funcd{mq\_getattr} e \funcd{mq\_setattr}, i cui prototipi sono:
\begin{functions}
  \headdecl{mqueue.h} 
  
  \funcdecl{int mq\_getattr(mqd\_t mqdes, struct mq\_attr *mqstat)}
  Legge gli attributi di una coda di messaggi POSIX.
  
  \funcdecl{int mq\_setattr(mqd\_t mqdes, const struct mq\_attr *mqstat,
    struct mq\_attr *omqstat)}
  Modifica gli attributi di una coda di messaggi POSIX.
  
  \bodydesc{Entrambe le funzioni restituiscono 0 in caso di successo e -1 in
    caso di errore; nel quel caso \var{errno} assumerà i valori \errval{EBADF}
    o \errval{EINVAL}.}
\end{functions}

La funzione \func{mq\_getattr} legge i valori correnti degli attributi della
coda nella struttura puntata da \param{mqstat}; di questi l'unico relativo
allo stato corrente della coda è \var{mq\_curmsgs} che indica il numero di
messaggi da essa contenuti, gli altri indicano le caratteristiche generali
della stessa.

La funzione \func{mq\_setattr} permette di modificare gli attributi di una
coda tramite i valori contenuti nella struttura puntata da \param{mqstat}, ma
può essere modificato solo il campo \var{mq\_flags}, gli altri campi vengono
ignorati. In particolare i valori di \var{mq\_maxmsg} e \var{mq\_msgsize}
possono essere specificati solo in fase ci creazione della coda.  Inoltre i
soli valori possibili per \var{mq\_flags} sono 0 e \const{O\_NONBLOCK}, per
cui alla fine la funzione può essere utilizzata solo per abilitare o
disabilitare la modalità non bloccante. L'argomento \param{omqstat} viene
usato, quando diverso da \val{NULL}, per specificare l'indirizzo di una
struttura su cui salvare i valori degli attributi precedenti alla chiamata
della funzione.

Per inserire messaggi su di una coda sono previste due funzioni,
\funcd{mq\_send} e \funcd{mq\_timedsend}, i cui prototipi sono:
\begin{functions}
  \headdecl{mqueue.h} 
  
  \funcdecl{int mq\_send(mqd\_t mqdes, const char *msg\_ptr, size\_t msg\_len,
    unsigned int msg\_prio)} 
  Esegue l'inserimento di un messaggio su una coda.
  
  \funcdecl{int mq\_timedsend(mqd\_t mqdes, const char *msg\_ptr, size\_t
    msg\_len, unsigned msg\_prio, const struct timespec *abs\_timeout)}   
  Esegue l'inserimento di un messaggio su una coda entro il tempo
  \param{abs\_timeout}.

  
  \bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso di
    errore; nel quel caso \var{errno} assumerà i valori:
    \begin{errlist}
    \item[\errcode{EAGAIN}] Si è aperta la coda con \const{O\_NONBLOCK}, e la
      coda è piena.
    \item[\errcode{EMSGSIZE}] La lunghezza del messaggio \param{msg\_len}
      eccede il limite impostato per la coda.
    \item[\errcode{ENOMEM}] Il kernel non ha memoria sufficiente. Questo
      errore può avvenire quando l'inserimento del messaggio
    \item[\errcode{EINVAL}] Si è specificato un valore nullo per
      \param{msg\_len}, o un valore di \param{msg\_prio} fuori dai limiti, o
      un valore non valido per \param{abs\_timeout}.
    \item[\errcode{ETIMEDOUT}] L'inserimento del messaggio non è stato
      effettuato entro il tempo stabilito.
    \end{errlist}    
    ed inoltre \errval{EBADF} ed \errval{EINTR}.}
\end{functions}

Entrambe le funzioni richiedono un puntatore al testo del messaggio
nell'argomento \param{msg\_ptr} e la relativa lunghezza in \param{msg\_len}.
Se quest'ultima eccede la dimensione massima specificata da \var{mq\_msgsize}
le funzioni ritornano immediatamente con un errore di \errcode{EMSGSIZE}.

L'argomento \param{msg\_prio} indica la priorità dell'argomento; i messaggi di
priorità maggiore vengono inseriti davanti a quelli di priorità inferiore (e
quindi saranno riletti per primi). A parità del valore della priorità il
messaggio sarà inserito in coda a tutti quelli con la stessa priorità. Il
valore della priorità non può eccedere il limite di sistema
\const{MQ\_PRIO\_MAX}, che nel caso è pari a 32768.

Qualora la coda sia piena, entrambe le funzioni si bloccano, a meno che non
sia stata selezionata in fase di apertura la modalità non bloccante, nel qual
caso entrambe ritornano \errcode{EAGAIN}. La sola differenza fra le due
funzioni è che la seconda, passato il tempo massimo impostato con l'argomento
\param{abs\_timeout}, ritorna comunque con un errore di \errcode{ETIMEDOUT}.


Come per l'inserimento, anche per l'estrazione dei messaggi da una coda sono
previste due funzioni, \funcd{mq\_receive} e \funcd{mq\_timedreceive}, i cui
prototipi sono:
\begin{functions}
  \headdecl{mqueue.h} 
  
  \funcdecl{ssize\_t mq\_receive(mqd\_t mqdes, char *msg\_ptr, size\_t
    msg\_len, unsigned int *msg\_prio)}   
  Effettua la ricezione di un messaggio da una coda.
  
  \funcdecl{ssize\_t mq\_timedreceive(mqd\_t mqdes, char *msg\_ptr, size\_t
    msg\_len, unsigned int *msg\_prio, const struct timespec *abs\_timeout)}
  Effettua la ricezione di un messaggio da una coda entro il tempo
  \param{abs\_timeout}.
  
  \bodydesc{Le funzioni restituiscono il numero di byte del messaggio in caso
    di successo e -1 in caso di errore; nel quel caso \var{errno} assumerà i
    valori:
    \begin{errlist}
    \item[\errcode{EAGAIN}] Si è aperta la coda con \const{O\_NONBLOCK}, e la
      coda è vuota.
    \item[\errcode{EMSGSIZE}] La lunghezza del messaggio sulla coda eccede il
      valore \param{msg\_len} specificato per la ricezione.
    \item[\errcode{EINVAL}] Si è specificato un valore nullo per
      \param{msg\_ptr}, o un valore non valido per \param{abs\_timeout}.
    \item[\errcode{ETIMEDOUT}] La ricezione del messaggio non è stata
      effettuata entro il tempo stabilito.
    \end{errlist}    
    ed inoltre \errval{EBADF}, \errval{EINTR}, \errval{ENOMEM}, o
    \errval{EINVAL}.}
\end{functions}

La funzione estrae dalla coda il messaggio a priorità più alta, o il più
vecchio fra quelli della stessa priorità. Una volta ricevuto il messaggio
viene tolto dalla coda e la sua dimensione viene restituita come valore di
ritorno.

Se la dimensione specificata da \param{msg\_len} non è sufficiente a contenere
il messaggio, entrambe le funzioni, al contrario di quanto avveniva nelle code
di messaggi di SysV, ritornano un errore di \errcode{EMSGSIZE} senza estrarre
il messaggio.  È pertanto opportuno eseguire sempre una chiamata a
\func{mq\_getaddr} prima di eseguire una ricezione, in modo da ottenere la
dimensione massima dei messaggi sulla coda, per poter essere in grado di
allocare dei buffer sufficientemente ampi per la lettura.

Se si specifica un puntatore per l'argomento \param{msg\_prio} il valore della
priorità del messaggio viene memorizzato all'indirizzo da esso indicato.
Qualora non interessi usare la priorità dei messaggi si può specificare
\var{NULL}, ed usare un valore nullo della priorità nelle chiamate a
\func{mq\_send}.

Si noti che con le code di messaggi POSIX non si ha la possibilità di
selezionare quale messaggio estrarre con delle condizioni sulla priorità, a
differenza di quanto avveniva con le code di messaggi di SysV che permettono
invece la selezione in base al valore del campo \var{mtype}. Qualora non
interessi usare la priorità dei messaggi si

Qualora la coda sia vuota entrambe le funzioni si bloccano, a meno che non si
sia selezionata la modalità non bloccante; in tal caso entrambe ritornano
immediatamente con l'errore \errcode{EAGAIN}. Anche in questo caso la sola
differenza fra le due funzioni è che la seconda non attende indefinitamente e
passato il tempo massimo \param{abs\_timeout} ritorna comunque con un errore
di \errcode{ETIMEDOUT}.

Uno dei problemi sottolineati da Stevens in \cite{UNP2}, comuni ad entrambe le
tipologie di code messaggi, è che non è possibile per chi riceve identificare
chi è che ha inviato il messaggio, in particolare non è possibile sapere da
quale utente esso provenga. Infatti, in mancanza di un meccanismo interno al
kernel, anche se si possono inserire delle informazioni nel messaggio, queste
non possono essere credute, essendo completamente dipendenti da chi lo invia.
Vedremo però come, attraverso l'uso del meccanismo di notifica, sia possibile
superare in parte questo problema.

Una caratteristica specifica delle code di messaggi POSIX è la possibilità di
usufruire di un meccanismo di notifica asincrono; questo può essere attivato
usando la funzione \funcd{mq\_notify}, il cui prototipo è:
\begin{prototype}{mqueue.h}
{int mq\_notify(mqd\_t mqdes, const struct sigevent *notification)}

Attiva il meccanismo di notifica per la coda \param{mqdes}.
  
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
  errore; nel quel caso \var{errno} assumerà i valori: 
    \begin{errlist}
    \item[\errcode{EBUSY}] C'è già un processo registrato per la notifica.
    \item[\errcode{EBADF}] Il descrittore non fa riferimento ad una coda di
      messaggi.
    \end{errlist}}
\end{prototype}

Il meccanismo di notifica permette di segnalare in maniera asincrona ad un
processo la presenza di dati sulla coda, in modo da evitare la necessità di
bloccarsi nell'attesa. Per far questo un processo deve registrarsi con la
funzione \func{mq\_notify}, ed il meccanismo è disponibile per un solo
processo alla volta per ciascuna coda.

Il comportamento di \func{mq\_notify} dipende dal valore dell'argomento
\param{notification}, che è un puntatore ad una apposita struttura
\struct{sigevent}, (definita in fig.~\ref{fig:file_sigevent}) introdotta dallo
standard POSIX.1b per gestire la notifica di eventi; per altri dettagli si può
vedere quanto detto in sez.~\ref{sec:file_asyncronous_io} a proposito dell'uso
della stessa struttura per l'invio dei segnali usati per l'I/O asincrono.

Attraverso questa struttura si possono impostare le modalità con cui viene
effettuata la notifica; in particolare il campo \var{sigev\_notify} deve
essere posto a \const{SIGEV\_SIGNAL}\footnote{il meccanismo di notifica basato
  sui thread, specificato tramite il valore \const{SIGEV\_THREAD}, non è
  implementato.} ed il campo \var{sigev\_signo} deve indicare il valore del
segnale che sarà inviato al processo. Inoltre il campo \var{sigev\_value} è il
puntatore ad una struttura \struct{sigval\_t} (definita in
fig.~\ref{fig:sig_sigval}) che permette di restituire al gestore del segnale un
valore numerico o un indirizzo,\footnote{per il suo uso si riveda la
  trattazione fatta in sez.~\ref{sec:sig_real_time} a proposito dei segnali
  real-time.} posto che questo sia installato nella forma estesa vista in
sez.~\ref{sec:sig_sigaction}.

La funzione registra il processo chiamante per la notifica se
\param{notification} punta ad una struttura \struct{sigevent} opportunamente
inizializzata, o cancella una precedente registrazione se è \val{NULL}. Dato
che un solo processo alla volta può essere registrato, la funzione fallisce
con \errcode{EBUSY} se c'è un altro processo già registrato.  Si tenga
presente inoltre che alla chiusura del descrittore associato alla coda (e
quindi anche all'uscita del processo) ogni eventuale registrazione di notifica
presente viene cancellata.

La notifica del segnale avviene all'arrivo di un messaggio in una coda vuota
(cioè solo se sulla coda non ci sono messaggi) e se non c'è nessun processo
bloccato in una chiamata a \func{mq\_receive}, in questo caso infatti il
processo bloccato ha la precedenza ed il messaggio gli viene immediatamente
inviato, mentre per il meccanismo di notifica tutto funziona come se la coda
fosse rimasta vuota.

Quando un messaggio arriva su una coda vuota al processo che si era registrato
viene inviato il segnale specificato da \code{notification->sigev\_signo}, e
la coda diventa disponibile per una ulteriore registrazione.  Questo comporta
che se si vuole mantenere il meccanismo di notifica occorre ripetere la
registrazione chiamando nuovamente \func{mq\_notify} all'interno del gestore
del segnale di notifica. A differenza della situazione simile che si aveva con
i segnali non affidabili,\footnote{l'argomento è stato affrontato in
  \ref{sec:sig_semantics}.} questa caratteristica non configura una
race-condition perché l'invio di un segnale avviene solo se la coda è vuota;
pertanto se si vuole evitare di correre il rischio di perdere eventuali
ulteriori segnali inviati nel lasso di tempo che occorre per ripetere la
richiesta di notifica basta avere cura di eseguire questa operazione prima di
estrarre i messaggi presenti dalla coda.

L'invio del segnale di notifica avvalora alcuni campi di informazione
restituiti al gestore attraverso la struttura \struct{siginfo\_t} (definita in
fig.~\ref{fig:sig_siginfo_t}). In particolare \var{si\_pid} viene impostato al
valore del \acr{pid} del processo che ha emesso il segnale, \var{si\_uid}
all'userid effettivo, \var{si\_code} a \const{SI\_MESGQ}, e \var{si\_errno} a
0. Questo ci dice che, se si effettua la ricezione dei messaggi usando
esclusivamente il meccanismo di notifica, è possibile ottenere le informazioni
sul processo che ha inserito un messaggio usando un gestore per il segnale in
forma estesa\footnote{di nuovo si faccia riferimento a quanto detto al
  proposito in sez.~\ref{sec:sig_sigaction} e sez.~\ref{sec:sig_real_time}.}



\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.\footnote{questo
  significa che i semafori sono visibili solo all'interno dei thread creati da
  un singolo processo, e non possono essere usati come meccanismo di
  sincronizzazione fra processi diversi.} Esiste però anche una libreria
realizzata da Konstantin Knizhnik, che reimplementa l'interfaccia POSIX usando
i semafori di SysV IPC, e che non vale comunque la pena di usare visto che i
problemi sottolineati in sez.~\ref{sec:ipc_sysv_sem} rimangono, anche se
mascherati.

In realtà a partire dal kernel 2.5.7 è stato introdotto un meccanismo di
sincronizzazione completamente nuovo, basato sui cosiddetti
\textit{futex}\footnote{la sigla sta per \textit{faxt user mode mutex}.}, con
il quale dovrebbe essere possibile implementare una versione nativa dei
semafori; esso è già stato usato con successo per reimplementare in maniera
più efficiente tutte le direttive di sincronizzazione previste per i thread
POSIX. L'interfaccia corrente è stata stabilizzata a partire dal kernel
2.5.40.




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

La memoria condivisa è l'unico degli oggetti di IPC POSIX già presente nel
kernel ufficiale; in realtà il supporto a questo tipo di oggetti è realizzato
attraverso il filesystem \texttt{tmpfs}, uno speciale filesystem che mantiene
tutti i suoi contenuti in memoria,\footnote{il filesystem \texttt{tmpfs} è
  diverso da un normale RAM disk, anch'esso disponibile attraverso il
  filesystem \texttt{ramfs}, proprio perché realizza una interfaccia
  utilizzabile anche per la memoria condivisa; esso infatti non ha dimensione
  fissa, ed usa direttamente la cache interna del kernel (che viene usata
  anche per la shared memory in stile SysV). In più i suoi contenuti, essendo
  trattati direttamente dalla memoria virtuale\index{memoria~virtuale} possono
  essere salvati sullo swap automaticamente.} che viene attivato abilitando
l'opzione \texttt{CONFIG\_TMPFS} in fase di compilazione del kernel.


Per potere utilizzare l'interfaccia POSIX per le code di messaggi le
\acr{glibc}\footnote{le funzioni sono state introdotte con le glibc-2.2.}
richiedono di compilare i programmi con l'opzione \code{-lrt}; inoltre è
necessario che in \file{/dev/shm} sia montato un filesystem \texttt{tmpfs};
questo di norma viene eseguita aggiungendo una riga tipo:
\begin{verbatim}
tmpfs   /dev/shm        tmpfs   defaults        0      0
\end{verbatim}
ad \file{/etc/fstab}. In realtà si può montare un filesystem \texttt{tmpfs}
dove si vuole, per usarlo come RAM disk, con un comando del tipo:
\begin{verbatim}
mount -t tmpfs -o size=128M,nr_inodes=10k,mode=700 tmpfs /mytmpfs
\end{verbatim}

Il filesystem riconosce, oltre quelle mostrate, le opzioni \texttt{uid} e
\texttt{gid} che identificano rispettivamente utente e gruppo cui assegnarne
la titolarità, e \texttt{nr\_blocks} che permette di specificarne la
dimensione in blocchi, cioè in multipli di \const{PAGECACHE\_SIZE} che in
questo caso è l'unità di allocazione elementare.

La funzione che permette di aprire un segmento di memoria condivisa POSIX, ed
eventualmente di crearlo se non esiste ancora, è \funcd{shm\_open}; il suo
prototipo è:
\begin{prototype}{mqueue.h}
{int shm\_open(const char *name, int oflag, mode\_t mode)}

Apre un segmento di memoria condivisa.
  
\bodydesc{La funzione restituisce un file descriptor positivo in caso di
  successo e -1 in caso di errore; nel quel caso \var{errno} assumerà gli
  stessi valori riportati da \func{open}.}
\end{prototype}

La funzione apre un segmento di memoria condivisa identificato dal nome
\param{name}. Come già spiegato in sez.~\ref{sec:ipc_posix_generic} questo nome
può essere specificato in forma standard solo facendolo iniziare per \file{/}
e senza ulteriori \file{/}, Linux supporta comunque nomi generici, che
verranno intepretati prendendo come radice \file{/dev/shm}.\footnote{occorre
  pertanto evitare di specificare qualcosa del tipo \file{/dev/shm/nome}
  all'interno di \param{name}, perché questo comporta, da parte delle routine
  di libereria, il tentativo di accedere a \file{/dev/shm/dev/shm/nome}.}

La funzione è del tutto analoga ad \func{open} ed analoghi sono i valori che
possono essere specificati per \param{oflag}, che deve essere specificato come
maschera binaria comprendente almeno uno dei due valori \const{O\_RDONLY} e
\const{O\_RDWR}; i valori possibili per i vari bit sono quelli visti in
tab.~\ref{tab:file_open_flags} dei quali però \func{shm\_open} riconosce solo
i seguenti:
\begin{basedescript}{\desclabelwidth{2.0cm}\desclabelstyle{\nextlinelabel}}
\item[\const{O\_RDONLY}] Apre il file descriptor associato al segmento di
  memoria condivisa per l'accesso in sola lettura.
\item[\const{O\_RDWR}] Apre il file descriptor associato al segmento di
  memoria condivisa per l'accesso in lettura e scrittura.
\item[\const{O\_CREAT}] Necessario qualora si debba creare il segmento di
  memoria condivisa se esso non esiste; in questo caso viene usato il valore
  di \param{mode} per impostare i permessi, che devono essere compatibili con
  le modalità con cui si è aperto il file.
\item[\const{O\_EXCL}] Se usato insieme a \const{O\_CREAT} fa fallire la
  chiamata a \func{shm\_open} se il segmento esiste già, altrimenti esegue la
  creazione atomicamente.
\item[\const{O\_TRUNC}] Se il segmento di memoria condivisa esiste già, ne
  tronca le dimensioni a 0 byte.
\end{basedescript}

In caso di successo la funzione restituisce un file descriptor associato al
segmento di memoria condiviso con le stesse modalità di
\func{open}\footnote{in realtà, come accennato, \func{shm\_open} è un semplice
  wrapper per \func{open}, usare direttamente quest'ultima avrebbe lo stesso
  effetto.}  viste in sez.~\ref{sec:file_open}; in particolare viene impostato
il flag \const{FD\_CLOEXEC}.  Chiamate effettuate da diversi processi usando
lo stesso nome, restituiranno file descriptor associati allo stesso segmento
(così come, nel caso di file di dati, essi sono associati allo stesso inode).
In questo modo è possibile effettuare una chiamata ad \func{mmap} sul file
descriptor restituito da \func{shm\_open} ed i processi vedranno lo stesso
segmento di memoria condivisa.

Quando il nome non esiste il segmento può essere creato specificando
\const{O\_CREAT}; in tal caso il segmento avrà (così come i nuovi file)
lunghezza nulla. Dato che un segmento di lunghezza nulla è di scarsa utilità,
per impostarne la dimensione si deve usare \func{ftruncate} (vedi
sez.~\ref{sec:file_file_size}), prima di mapparlo in memoria con \func{mmap}.
Si tenga presente che una volta chiamata \func{mmap} si può chiudere il file
descriptor (con \func{close}), senza che la mappatura ne risenta.


Come per i file, quando si vuole effettivamente rimuovere segmento di memoria
condivisa, occorre usare la funzione \funcd{shm\_unlink}, il cui prototipo è:
\begin{prototype}{mqueue.h}
{int shm\_unlink(const char *name)}

Rimuove un segmento di memoria condivisa.
  
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
  errore; nel quel caso \var{errno} assumerà gli stessi valori riportati da
  \func{unlink}.}
\end{prototype}

La funzione è del tutto analoga ad \func{unlink}, e si limita a cancellare il
nome del segmento da \file{/dev/shm}, senza nessun effetto né sui file
descriptor precedentemente aperti con \func{shm\_open}, né sui segmenti già
mappati in memoria; questi verranno cancellati automaticamente dal sistema
solo con le rispettive chiamate a \func{close} e \func{munmap}.  Una volta
eseguita questa funzione però, qualora si richieda l'apertura di un segmento
con lo stesso nome, la chiamata a \func{shm\_open} fallirà, a meno di non aver
usato \const{O\_CREAT}, in quest'ultimo caso comunque si otterrà un file
descriptor che fa riferimento ad un segmento distinto da eventuali precedenti.

\begin{figure}[!htb]
  \footnotesize \centering
  \begin{minipage}[c]{15.6cm}
    \includecodesample{listati/MemShared.c}
  \end{minipage} 
  \normalsize 
  \caption{Il codice delle funzioni di gestione dei segmenti di memoria
    condivisa POSIX.}
  \label{fig:ipc_posix_shmmem}
\end{figure}

Come esempio per l'uso di queste funzioni vediamo come è possibile riscrivere
una interfaccia semplificata analoga a quella vista in
fig.~\ref{fig:ipc_sysv_shm_func} per la memoria condivisa in stile SysV. Il
codice, riportato in fig.~\ref{fig:ipc_posix_shmmem}, è sempre contenuto nel
file \file{SharedMem.c} dei sorgenti allegati.

La prima funzione (\texttt{\small 1--24}) è \func{CreateShm} che, dato un nome
nell'argomento \var{name} crea un nuovo segmento di memoria condivisa,
accessibile in lettura e scrittura, e ne restituisce l'indirizzo. Anzitutto si
definiscono (\texttt{\small 8}) i flag per la successiva (\texttt{\small 9})
chiamata a \func{shm\_open}, che apre il segmento in lettura e scrittura
(creandolo se non esiste, ed uscendo in caso contrario) assegnandogli sul
filesystem i permessi specificati dall'argomento \var{perm}. In caso di errore
(\texttt{\small 10--12}) si restituisce un puntatore nullo, altrimenti si
prosegue impostando (\texttt{\small 14}) la dimensione del segmento con
\func{ftruncate}. Di nuovo (\texttt{\small 15--16}) si esce immediatamente
restituendo un puntatore nullo in caso di errore. Poi si passa (\texttt{\small
  18}) a mappare in memoria il segmento con \func{mmap} specificando dei
diritti di accesso corrispondenti alla modalità di apertura.  Di nuovo si
restituisce (\texttt{\small 19--21}) un puntatore nullo in caso di errore,
altrimenti si inizializza (\texttt{\small 22}) il contenuto del segmento al
valore specificato dall'argomento \var{fill} con \func{memset}, e se ne
restituisce (\texttt{\small 23}) l'indirizzo.

La seconda funzione (\texttt{\small 25--40}) è \func{FindShm} che trova un
segmento di memoria condiviso già esistente, restituendone l'indirizzo. In
questo caso si apre (\texttt{\small 31}) il segmento con \func{shm\_open}
richiedendo che il segmento sia già esistente, in caso di errore
(\texttt{\small 31--33}) si ritorna immediatamente un puntatore nullo.
Ottenuto il file descriptor del segmento lo si mappa (\texttt{\small 35}) in
memoria con \func{mmap}, restituendo (\texttt{\small 36--38}) un puntatore
nullo in caso di errore, o l'indirizzo (\texttt{\small 39}) dello stesso in
caso di successo.

La terza funzione (\texttt{\small 40--45}) è \func{RemoveShm}, e serve a
cancellare un segmento di memoria condivisa. Dato che al contrario di quanto
avveniva con i segmenti del SysV IPC gli oggetti allocati nel kernel vengono
rilasciati automaticamente quando nessuna li usa più, tutto quello che c'è da
fare (\texttt{\small 44}) in questo caso è chiamare \func{shm\_unlink},
retituendo al chiamante il valore di ritorno.



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