+Benché le pipe e le fifo siano ancora ampiamente usate, esse scontano il
+limite fondamentale che il meccanismo di comunicazione che forniscono è
+rigidamente sequenziale: una situazione in cui un processo scrive qualcosa che
+molti altri devono poter leggere non può essere implementata con una pipe.
+
+Per questo nello sviluppo di System V vennero introdotti una serie di nuovi
+oggetti per la comunicazione fra processi ed una nuova interfaccia di
+programmazione, che fossero in grado di garantire una maggiore flessibilità.
+In questa sezione esamineremo come Linux supporta quello che viene chiamato il
+\textsl{Sistema di comunicazione inter-processo} di System V, cui da qui in
+avanti faremo riferimento come \textit{SysV IPC} (dove IPC è la sigla di
+\textit{Inter-Process Comunication}).
+
+
+
+\subsection{Considerazioni generali}
+\label{sec:ipc_sysv_generic}
+
+La principale caratteristica del \textit{SysV IPC} è quella di essere basato
+su oggetti permanenti che risiedono nel kernel. Questi, a differenza di quanto
+avviene per i file descriptor, non mantengono un contatore dei riferimenti, e
+non vengono cancellati dal sistema una volta che non sono più in uso.
+
+Questo comporta due problemi: il primo è che, al contrario di quanto avviene
+per pipe e fifo, la memoria allocata per questi oggetti non viene rilasciata
+automaticamente quando non c'è più nessuno che li utilizzi, ed essi devono
+essere cancellati esplicitamente, se non si vuole che restino attivi fino al
+riavvio del sistema. Il secondo problema è che, dato che non c'è, come per i
+file, un contatore del numero di riferimenti che ne indichi l'essere in uso,
+essi possono essere cancellati anche se ci sono dei processi che li stanno
+utilizzando, con tutte le conseguenze (negative) del caso.
+
+Un'ulteriore caratteristica negativa è che gli oggetti usati nel \textit{SysV
+ IPC} vengono creati direttamente dal kernel, e sono accessibili solo
+specificando il relativo \textsl{identificatore}. Questo è un numero
+progressivo (un po' come il \acr{pid} dei processi) che il kernel assegna a
+ciascuno di essi quanto vengono creati (sul procedimento di assegnazione
+torneremo in \secref{sec:ipc_sysv_id_use}). L'identificatore viene restituito
+dalle funzioni che creano l'oggetto, ed è quindi locale al processo che le ha
+eseguite. Dato che l'identificatore viene assegnato dinamicamente dal kernel
+non è possibile prevedere quale sarà, né utilizzare un qualche valore statico,
+si pone perciò il problema di come processi diversi possono accedere allo
+stesso oggetto.
+
+Per risolvere il problema nella struttura \struct{ipc\_perm} che il kernel
+associa a ciascun oggetto, viene mantenuto anche un campo apposito che
+contiene anche una \textsl{chiave}, identificata da una variabile del tipo
+primitivo \type{key\_t}, da specificare in fase di creazione dell'oggetto, e
+tramite la quale è possibile ricavare l'identificatore.\footnote{in sostanza
+ si sposta il problema dell'accesso dalla classificazione in base
+ all'identificatore alla classificazione in base alla chiave, una delle tante
+ complicazioni inutili presenti nel \textit{SysV IPC}.} Oltre la chiave, la
+struttura, la cui definizione è riportata in \figref{fig:ipc_ipc_perm},
+mantiene varie proprietà ed informazioni associate all'oggetto.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm ]{}
+struct ipc_perm
+{
+ key_t key; /* Key. */
+ uid_t uid; /* Owner's user ID. */
+ gid_t gid; /* Owner's group ID. */
+ uid_t cuid; /* Creator's user ID. */
+ gid_t cgid; /* Creator's group ID. */
+ unsigned short int mode; /* Read/write permission. */
+ unsigned short int seq; /* Sequence number. */
+};
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \structd{ipc\_perm}, come definita in
+ \file{sys/ipc.h}.}
+ \label{fig:ipc_ipc_perm}
+\end{figure}
+
+Usando la stessa chiave due processi diversi possono ricavare l'identificatore
+associato ad un oggetto ed accedervi. Il problema che sorge a questo punto è
+come devono fare per accordarsi sull'uso di una stessa chiave. Se i processi
+sono \textsl{parenti} la soluzione è relativamente semplice, in tal caso
+infatti si può usare il valore speciale \texttt{IPC\_PRIVATE} per creare un
+nuovo oggetto nel processo padre, l'identificatore così ottenuto sarà
+disponibile in tutti i figli, e potrà essere passato come parametro attraverso
+una \func{exec}.
+
+Però quando i processi non sono \textsl{parenti} (come capita tutte le volte
+che si ha a che fare con un sistema client-server) tutto questo non è
+possibile; si potrebbe comunque salvare l'identificatore su un file noto, ma
+questo ovviamente comporta lo svantaggio di doverselo andare a rileggere. Una
+alternativa più efficace è quella che i programmi usino un valore comune per
+la chiave (che ad esempio può essere dichiarato in un header comune), ma c'è
+sempre il rischio che questa chiave possa essere stata già utilizzata da
+qualcun altro. Dato che non esiste una convenzione su come assegnare queste
+chiavi in maniera univoca l'interfaccia mette a disposizione una funzione
+apposita, \funcd{ftok}, che permette di ottenere una chiave specificando il
+nome di un file ed un numero di versione; il suo prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{sys/ipc.h}
+
+ \funcdecl{key\_t ftok(const char *pathname, int proj\_id)}
+
+ Restituisce una chiave per identificare un oggetto del \textit{SysV IPC}.
+
+ \bodydesc{La funzione restituisce la chiave in caso di successo e -1
+ altrimenti, nel qual caso \var{errno} sarà uno dei possibili codici di
+ errore di \func{stat}.}
+\end{functions}
+
+La funzione determina un valore della chiave sulla base di \param{pathname},
+che deve specificare il pathname di un file effettivamente esistente e di un
+numero di progetto \param{proj\_id)}, che di norma viene specificato come
+carattere, dato che ne vengono utilizzati solo gli 8 bit meno
+significativi.\footnote{nelle libc4 e libc5, come avviene in SunOS,
+ l'argomento \param{proj\_id} è dichiarato tipo \ctyp{char}, le \acr{glibc}
+ usano il prototipo specificato da XPG4, ma vengono lo stesso utilizzati gli
+ 8 bit meno significativi.}
+
+Il problema è che anche così non c'è la sicurezza che il valore della chiave
+sia univoco, infatti esso è costruito combinando il byte di \param{proj\_id)}
+con i 16 bit meno significativi dell'inode\index{inode} del file
+\param{pathname} (che vengono ottenuti attraverso \func{stat}, da cui derivano
+i possibili errori), e gli 8 bit meno significativi del numero del dispositivo
+su cui è il file. Diventa perciò relativamente facile ottenere delle
+collisioni, specie se i file sono su dispositivi con lo stesso \textit{minor
+ number}, come \file{/dev/hda1} e \file{/dev/sda1}.
+
+In genere quello che si fa è utilizzare un file comune usato dai programmi che
+devono comunicare (ad esempio un header comune, o uno dei programmi che devono
+usare l'oggetto in questione), utilizzando il numero di progetto per ottenere
+le chiavi che interessano. In ogni caso occorre sempre controllare, prima di
+creare un oggetto, che la chiave non sia già stata utilizzata. Se questo va
+bene in fase di creazione, le cose possono complicarsi per i programmi che
+devono solo accedere, in quanto, a parte gli eventuali controlli sugli altri
+attributi di \struct{ipc\_perm}, non esiste una modalità semplice per essere
+sicuri che l'oggetto associato ad una certa chiave sia stato effettivamente
+creato da chi ci si aspetta.
+
+Questo è, insieme al fatto che gli oggetti sono permanenti e non mantengono un
+contatore di riferimenti per la cancellazione automatica, il principale
+problema del \textit{SysV IPC}. Non esiste infatti una modalità chiara per
+identificare un oggetto, come sarebbe stato se lo si fosse associato ad in
+file, e tutta l'interfaccia è inutilmente complessa. Per questo ne è stata
+effettuata una revisione completa nello standard POSIX.1b, che tratteremo in
+\secref{sec:ipc_posix}.
+
+
+\subsection{Il controllo di accesso}
+\label{sec:ipc_sysv_access_control}
+
+Oltre alle chiavi, abbiamo visto che ad ogni oggetto sono associate in
+\struct{ipc\_perm} ulteriori informazioni, come gli identificatori del creatore
+(nei campi \var{cuid} e \var{cgid}) e del proprietario (nei campi \var{uid} e
+\var{gid}) dello stesso, e un insieme di permessi (nel campo \var{mode}). In
+questo modo è possibile definire un controllo di accesso sugli oggetti di IPC,
+simile a quello che si ha per i file (vedi \secref{sec:file_perm_overview}).
+
+Benché questo controllo di accesso sia molto simile a quello dei file, restano
+delle importanti differenze. La prima è che il permesso di esecuzione non
+esiste (e se specificato viene ignorato), per cui si può parlare solo di
+permessi di lettura e scrittura (nel caso dei semafori poi quest'ultimo è più
+propriamente un permesso di modifica). I valori di \var{mode} sono gli stessi
+ed hanno lo stesso significato di quelli riportati in
+\secref{tab:file_mode_flags}\footnote{se però si vogliono usare le costanti
+ simboliche ivi definite occorrerà includere il file \file{sys/stat.h},
+ alcuni sistemi definiscono le costanti \const{MSG\_R} (\texttt{0400}) e
+ \const{MSG\_W} (\texttt{0200}) per indicare i permessi base di lettura e
+ scrittura per il proprietario, da utilizzare, con gli opportuni shift, pure
+ per il gruppo e gli altri, in Linux, visto la loro scarsa utilità, queste
+ costanti non sono definite.} e come per i file definiscono gli accessi per
+il proprietario, il suo gruppo e tutti gli altri.
+
+Quando l'oggetto viene creato i campi \var{cuid} e \var{uid} di
+\struct{ipc\_perm} ed i campi \var{cgid} e \var{gid} vengono settati
+rispettivamente al valore dell'user-ID e del group-ID effettivo del processo che
+ha chiamato la funzione, ma, mentre i campi \var{uid} e \var{gid} possono
+essere cambiati, i campi \var{cuid} e \var{cgid} restano sempre gli stessi.
+
+Il controllo di accesso è effettuato a due livelli. Il primo livello è nelle
+funzioni che richiedono l'identificatore di un oggetto data la chiave. Queste
+specificano tutte un argomento \param{flag}, in tal caso quando viene
+effettuata la ricerca di una chiave, qualora \param{flag} specifichi dei
+permessi, questi vengono controllati e l'identificatore viene restituito solo
+se corrispondono a quelli dell'oggetto. Se ci sono dei permessi non presenti
+in \var{mode} l'accesso sarà negato. Questo controllo però è di utilità
+indicativa, dato che è sempre possibile specificare per \param{flag} un valore
+nullo, nel qual caso l'identificatore sarà restituito comunque.
+
+Il secondo livello di controllo è quello delle varie funzioni che accedono
+direttamente (in lettura o scrittura) all'oggetto. In tal caso lo schema dei
+controlli è simile a quello dei file, ed avviene secondo questa sequenza:
+\begin{itemize}
+\item se il processo ha i privilegi di amministratore l'accesso è sempre
+ consentito.
+\item se l'user-ID effettivo del processo corrisponde o al valore del campo
+ \var{cuid} o a quello del campo \var{uid} ed il permesso per il proprietario
+ in \var{mode} è appropriato\footnote{per appropriato si intende che è
+ settato il permesso di scrittura per le operazioni di scrittura e quello
+ di lettura per le operazioni di lettura.} l'accesso è consentito.
+\item se il group-ID effettivo del processo corrisponde o al
+ valore del campo \var{cgid} o a quello del campo \var{gid} ed il permesso
+ per il gruppo in \var{mode} è appropriato l'accesso è consentito.
+\item se il permesso per gli altri è appropriato l'accesso è consentito.
+\end{itemize}
+solo se tutti i controlli elencati falliscono l'accesso è negato. Si noti che
+a differenza di quanto avviene per i permessi dei file, fallire in uno dei
+passi elencati non comporta il fallimento dell'accesso. Un'ulteriore
+differenza rispetto a quanto avviene per i file è che per gli oggetti di IPC
+il valore di \var{umask} (si ricordi quanto esposto in
+\secref{sec:file_umask}) non ha alcun significato.
+
+
+\subsection{Gli identificatori ed il loro utilizzo}
+\label{sec:ipc_sysv_id_use}
+
+L'unico campo di \struct{ipc\_perm} del quale non abbiamo ancora parlato è
+\var{seq}, che in \figref{fig:ipc_ipc_perm} è qualificato con un criptico
+``\textsl{numero di sequenza}'', ne parliamo adesso dato che esso è
+strettamente attinente alle modalità con cui il kernel assegna gli
+identificatori degli oggetti del sistema di IPC.
+
+Quando il sistema si avvia, alla creazione di ogni nuovo oggetto di IPC viene
+assegnato un numero progressivo, pari al numero di oggetti di quel tipo
+esistenti. Se il comportamento fosse sempre questo sarebbe identico a quello
+usato nell'assegnazione dei file descriptor nei processi, ed i valori degli
+identificatori tenderebbero ad essere riutilizzati spesso e restare di piccole
+dimensioni (inferiori al numero massimo di oggetti disponibili).
+
+Questo va benissimo nel caso dei file descriptor, che sono locali ad un
+processo, ma qui il comportamento varrebbe per tutto il sistema, e per
+processi del tutto scorrelati fra loro. Così si potrebbero avere situazioni
+come quella in cui un server esce e cancella le sue code di messaggi, ed il
+relativo identificatore viene immediatamente assegnato a quelle di un altro
+server partito subito dopo, con la possibilità che i client del primo non
+facciano in tempo ad accorgersi dell'avvenuto, e finiscano con l'interagire
+con gli oggetti del secondo, con conseguenze imprevedibili.
+
+Proprio per evitare questo tipo di situazioni il sistema usa il valore di
+\var{seq} per provvedere un meccanismo che porti gli identificatori ad
+assumere tutti i valori possibili, rendendo molto più lungo il periodo in cui
+un identificatore può venire riutilizzato.
+
+Il sistema dispone sempre di un numero fisso di oggetti di IPC,\footnote{fino
+ al kernel 2.2.x questi valori, definiti dalle costanti \const{MSGMNI},
+ \const{SEMMNI} e \const{SHMMNI}, potevano essere cambiati (come tutti gli
+ altri limiti relativi al \textit{SysV IPC}) solo con una ricompilazione del
+ kernel, andando a modificarne la definizione nei relativi header file. A
+ partire dal kernel 2.4.x è possibile cambiare questi valori a sistema attivo
+ scrivendo sui file \file{shmmni}, \file{msgmni} e \file{sem} di
+ \file{/proc/sys/kernel} o con l'uso di \func{sysctl}.} e per ciascuno di
+essi viene mantenuto in \var{seq} un numero di sequenza progressivo che viene
+incrementato di uno ogni volta che l'oggetto viene cancellato. Quando
+l'oggetto viene creato usando uno spazio che era già stato utilizzato in
+precedenza per restituire l'identificatore al numero di oggetti presenti viene
+sommato il valore di \var{seq} moltiplicato per il numero massimo di oggetti
+di quel tipo,\footnote{questo vale fino ai kernel della serie 2.2.x, dalla
+ serie 2.4.x viene usato lo stesso fattore per tutti gli oggetti, esso è dato
+ dalla costante \const{IPCMNI}, definita in \file{include/linux/ipc.h}, che
+ indica il limite massimo per il numero di tutti oggetti di IPC, ed il cui
+ valore è 32768.} si evita così il riutilizzo degli stessi numeri, e si fa
+sì che l'identificatore assuma tutti i valori possibili.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+int main(int argc, char *argv[])
+{
+ ...
+ switch (type) {
+ case 'q': /* Message Queue */
+ debug("Message Queue Try\n");
+ for (i=0; i<n; i++) {
+ id = msgget(IPC_PRIVATE, IPC_CREAT|0666);
+ printf("Identifier Value %d \n", id);
+ msgctl(id, IPC_RMID, NULL);
+ }
+ break;
+ case 's': /* Semaphore */
+ debug("Semaphore\n");
+ for (i=0; i<n; i++) {
+ id = semget(IPC_PRIVATE, 1, IPC_CREAT|0666);
+ printf("Identifier Value %d \n", id);
+ semctl(id, 0, IPC_RMID);
+ }
+ break;
+ case 'm': /* Shared Memory */
+ debug("Shared Memory\n");
+ for (i=0; i<n; i++) {
+ id = shmget(IPC_PRIVATE, 1000, IPC_CREAT|0666);
+ printf("Identifier Value %d \n", id);
+ shmctl(id, IPC_RMID, NULL);
+ }
+ break;
+ default: /* should not reached */
+ return -1;
+ }
+ return 0;
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Sezione principale del programma di test per l'assegnazione degli
+ identificatori degli oggetti di IPC \file{IPCTestId.c}.}
+ \label{fig:ipc_sysv_idtest}
+\end{figure}
+
+In \figref{fig:ipc_sysv_idtest} è riportato il codice di un semplice programma
+di test che si limita a creare un oggetto (specificato a riga di comando),
+stamparne il numero di identificatore e cancellarlo per un numero specificato
+di volte. Al solito non si è riportato il codice della gestione delle opzioni
+a riga di comando, che permette di specificare quante volte effettuare il
+ciclo \var{n}, e su quale tipo di oggetto eseguirlo.
+
+La figura non riporta il codice di selezione delle opzioni, che permette di
+inizializzare i valori delle variabili \var{type} al tipo di oggetto voluto, e
+\var{n} al numero di volte che si vuole effettuare il ciclo di creazione,
+stampa, cancellazione. I valori di default sono per l'uso delle code di
+messaggi e un ciclo di 5 volte. Se si lancia il comando si otterrà qualcosa
+del tipo:
+\begin{verbatim}
+piccardi@gont sources]$ ./ipctestid
+Identifier Value 0
+Identifier Value 32768
+Identifier Value 65536
+Identifier Value 98304
+Identifier Value 131072
+\end{verbatim}%$
+il che ci mostra che abbiamo un kernel della serie 2.4.x nel quale non avevamo
+ancora usato nessuna coda di messaggi. Se ripetiamo il comando otterremo
+ancora:
+\begin{verbatim}
+[piccardi@gont sources]$ ./ipctestid
+Identifier Value 163840
+Identifier Value 196608
+Identifier Value 229376
+Identifier Value 262144
+Identifier Value 294912
+\end{verbatim}%$
+che ci mostra come il valore di \var{seq} sia in effetti una quantità
+mantenuta staticamente all'interno del sistema.
+
+
+\subsection{Code di messaggi}
+\label{sec:ipc_sysv_mq}
+
+Il primo oggetto introdotto dal \textit{SysV IPC} è quello delle code di
+messaggi. Le code di messaggi sono oggetti analoghi alle pipe o alle fifo,
+anche se la loro struttura è diversa, ed il loro scopo principale è appunto
+quello di permettere a processi diversi di scambiarsi dei dati.
+
+La funzione che permette di richiedere al sistema l'identificatore di una coda
+di messaggi esistente (o di crearne una se questa non esiste) è
+\funcd{msgget}; il suo prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{sys/ipc.h}
+ \headdecl{sys/msg.h}
+
+ \funcdecl{int msgget(key\_t key, int flag)}
+
+ Restituisce l'identificatore di una coda di messaggi.
+
+ \bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
+ in caso di errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] Il processo chiamante non ha i privilegi per accedere
+ alla coda richiesta.
+ \item[\errcode{EEXIST}] Si è richiesta la creazione di una coda che già
+ esiste, ma erano specificati sia \const{IPC\_CREAT} che \const{IPC\_EXCL}.
+ \item[\errcode{EIDRM}] La coda richiesta è marcata per essere cancellata.
+ \item[\errcode{ENOENT}] Si è cercato di ottenere l'identificatore di una coda
+ di messaggi specificando una chiave che non esiste e \const{IPC\_CREAT}
+ non era specificato.
+ \item[\errcode{ENOSPC}] Si è cercato di creare una coda di messaggi quando è
+ stato superato il limite massimo di code (\const{MSGMNI}).
+ \end{errlist}
+ ed inoltre \errval{ENOMEM}.
+}
+\end{functions}
+
+Le funzione (come le analoghe che si usano per gli altri oggetti) serve sia a
+ottenere l'identificatore di una coda di messaggi esistente, che a crearne una
+nuova. L'argomento \param{key} specifica la chiave che è associata
+all'oggetto, eccetto il caso in cui si specifichi il valore
+\const{IPC\_PRIVATE}, nel qual caso la coda è creata ex-novo e non vi è
+associata alcuna chiave, il processo (ed i suoi eventuali figli) potranno
+farvi riferimento solo attraverso l'identificatore.
+
+Se invece si specifica un valore diverso da \const{IPC\_PRIVATE}\footnote{in
+ Linux questo significa un valore diverso da zero.} l'effetto della funzione
+dipende dal valore di \param{flag}, se questo è nullo la funzione si limita ad
+effettuare una ricerca sugli oggetti esistenti, restituendo l'identificatore
+se trova una corrispondenza, o fallendo con un errore di \errcode{ENOENT} se
+non esiste o di \errcode{EACCES} se si sono specificati dei permessi non
+validi.
+
+Se invece si vuole creare una nuova coda di messaggi \param{flag} non può
+essere nullo e deve essere fornito come maschera binaria, impostando il bit
+corrispondente al valore \const{IPC\_CREAT}. In questo caso i nove bit meno
+significativi di \param{flag} saranno usati come permessi per il nuovo
+oggetto, secondo quanto illustrato in \secref{sec:ipc_sysv_access_control}.
+Se si imposta anche il bit corrispondente a \const{IPC\_EXCL} la funzione avrà
+successo solo se l'oggetto non esiste già, fallendo con un errore di
+\errcode{EEXIST} altrimenti.
+
+Si tenga conto che l'uso di \const{IPC\_PRIVATE} non impedisce ad altri
+processi di accedere alla coda (se hanno privilegi sufficienti) una volta che
+questi possano indovinare o ricavare (ad esempio per tentativi)
+l'identificatore ad essa associato. Per come sono implementati gli oggetti di
+IPC infatti non esiste una maniera che garantisca l'accesso esclusivo ad una
+coda di messaggi. Usare \const{IPC\_PRIVATE} o const{IPC\_CREAT} e
+\const{IPC\_EXCL} per \param{flag} comporta solo la creazione di una nuova
+coda.
+
+\begin{table}[htb]
+ \footnotesize
+ \centering
+ \begin{tabular}[c]{|c|r|l|l|}
+ \hline
+ \textbf{Costante} & \textbf{Valore} & \textbf{File in \texttt{proc}}
+ & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{MSGMNI}& 16& \file{msgmni} & Numero massimo di code di
+ messaggi. \\
+ \const{MSGMAX}& 8192& \file{msgmax} & Dimensione massima di un singolo
+ messaggio.\\
+ \const{MSGMNB}&16384& \file{msgmnb} & Dimensione massima del contenuto di
+ una coda.\\
+ \hline
+ \end{tabular}
+ \caption{Valori delle costanti associate ai limiti delle code di messaggi.}
+ \label{tab:ipc_msg_limits}
+\end{table}
+
+Le code di messaggi sono caratterizzate da tre limiti fondamentali, definiti
+negli header e corrispondenti alle prime tre costanti riportate in
+\tabref{tab:ipc_msg_limits}, come accennato però in Linux è possibile
+modificare questi limiti attraverso l'uso di \func{sysctl} o scrivendo nei
+file \file{msgmax}, \file{msgmnb} e \file{msgmni} di \file{/proc/sys/kernel/}.
+
+
+\begin{figure}[htb]
+ \centering \includegraphics[width=15cm]{img/mqstruct}
+ \caption{Schema della struttura di una coda messaggi.}
+ \label{fig:ipc_mq_schema}
+\end{figure}
+
+
+Una coda di messaggi è costituita da una \textit{linked list};\footnote{una
+ \textit{linked list} è una tipica struttura di dati, organizzati in una
+ lista in cui ciascun elemento contiene un puntatore al successivo. In questo
+ modo la struttura è veloce nell'estrazione ed immissione dei dati dalle
+ estremità dalla lista (basta aggiungere un elemento in testa o in coda ed
+ aggiornare un puntatore), e relativamente veloce da attraversare in ordine
+ sequenziale (seguendo i puntatori), è invece relativamente lenta
+ nell'accesso casuale e nella ricerca.} i nuovi messaggi vengono inseriti in
+coda alla lista e vengono letti dalla cima, in \figref{fig:ipc_mq_schema} si è
+riportato lo schema con cui queste strutture vengono mantenute dal
+kernel.\footnote{lo schema illustrato in \figref{fig:ipc_mq_schema} è in
+ realtà una semplificazione di quello usato effettivamente fino ai kernel
+ della serie 2.2.x, nei kernel della serie 2.4.x la gestione delle code di
+ messaggi è stata modificata ed è effettuata in maniera diversa; abbiamo
+ mantenuto lo schema precedente in quanto illustra comunque in maniera più
+ che adeguata i principi di funzionamento delle code di messaggi.}
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}
+struct msqid_ds {
+ struct ipc_perm msg_perm; /* structure for operation permission */
+ time_t msg_stime; /* time of last msgsnd command */
+ time_t msg_rtime; /* time of last msgrcv command */
+ time_t msg_ctime; /* time of last change */
+ msgqnum_t msg_qnum; /* number of messages currently on queue */
+ msglen_t msg_qbytes; /* max number of bytes allowed on queue */
+ pid_t msg_lspid; /* pid of last msgsnd() */
+ pid_t msg_lrpid; /* pid of last msgrcv() */
+ struct msg *msg_first; /* first message on queue, unused */
+ struct msg *msg_last; /* last message in queue, unused */
+ unsigned long int msg_cbytes; /* current number of bytes on queue */
+};
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \structd{msqid\_ds}, associata a ciascuna coda di
+ messaggi.}
+ \label{fig:ipc_msqid_ds}
+\end{figure}
+
+A ciascuna coda è associata una struttura \struct{msgid\_ds}, la cui
+definizione, è riportata in \secref{fig:ipc_msqid_ds}. In questa struttura il
+kernel mantiene le principali informazioni riguardo lo stato corrente della
+coda.\footnote{come accennato questo vale fino ai kernel della serie 2.2.x,
+ essa viene usata nei kernel della serie 2.4.x solo per compatibilità in
+ quanto è quella restituita dalle funzioni dell'interfaccia. Si noti come ci
+ sia una differenza con i campi mostrati nello schema di
+ \figref{fig:ipc_mq_schema} che sono presi dalla definizione di
+ \file{linux/msg.h}, e fanno riferimento alla definizione della omonima
+ struttura usata nel kernel.} In \figref{fig:ipc_msqid_ds} sono elencati i
+campi significativi definiti in \file{sys/msg.h}, a cui si sono aggiunti gli
+ultimi tre campi che sono previsti dalla implementazione originale di System
+V, ma non dallo standard Unix98.
+
+Quando si crea una nuova coda con \func{msgget} questa struttura viene
+inizializzata, in particolare il campo \var{msg\_perm} viene inizializzato
+come illustrato in \secref{sec:ipc_sysv_access_control}, per quanto riguarda
+gli altri campi invece:
+\begin{itemize}
+\item il campo \var{msg\_qnum}, che esprime il numero di messaggi presenti
+ sulla coda, viene inizializzato a 0.
+\item i campi \var{msg\_lspid} e \var{msg\_lrpid}, che esprimono
+ rispettivamente il \acr{pid} dell'ultimo processo che ha inviato o ricevuto
+ un messaggio sulla coda, sono inizializzati a 0.
+\item i campi \var{msg\_stime} e \var{msg\_rtime}, che esprimono
+ rispettivamente il tempo in cui è stato inviato o ricevuto l'ultimo
+ messaggio sulla coda, sono inizializzati a 0.
+\item il campo \var{msg\_ctime}, che esprime il tempo di creazione della coda,
+ viene inizializzato al tempo corrente.
+\item il campo \var{msg\_qbytes} che esprime la dimensione massima del
+ contenuto della coda (in byte) viene inizializzato al valore preimpostato
+ del sistema (\const{MSGMNB}).
+\item i campi \var{msg\_first} e \var{msg\_last} che esprimono l'indirizzo del
+ primo e ultimo messaggio sono inizializzati a \val{NULL} e
+ \var{msg\_cbytes}, che esprime la dimensione in byte dei messaggi presenti è
+ inizializzato a zero. Questi campi sono ad uso interno dell'implementazione
+ e non devono essere utilizzati da programmi in user space).
+\end{itemize}
+
+Una volta creata una coda di messaggi le operazioni di controllo vengono
+effettuate con la funzione \funcd{msgctl}, che (come le analoghe \func{semctl}
+e \func{shmctl}) fa le veci di quello che \func{ioctl} è per i file; il suo
+prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{sys/ipc.h}
+ \headdecl{sys/msg.h}
+
+ \funcdecl{int msgctl(int msqid, int cmd, struct msqid\_ds *buf)}
+
+ Esegue l'operazione specificata da \param{cmd} sulla coda \param{msqid}.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo o -1 in caso di
+ errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] Si è richiesto \const{IPC\_STAT} ma processo
+ chiamante non ha i privilegi di lettura sulla coda.
+ \item[\errcode{EIDRM}] La coda richiesta è stata cancellata.
+ \item[\errcode{EPERM}] Si è richiesto \const{IPC\_SET} o \const{IPC\_RMID} ma
+ il processo non ha i privilegi, o si è richiesto di aumentare il valore di
+ \var{msg\_qbytes} oltre il limite \const{MSGMNB} senza essere
+ amministratore.
+ \end{errlist}
+ ed inoltre \errval{EFAULT} ed \errval{EINVAL}.
+}
+\end{functions}
+
+La funzione permette di accedere ai valori della struttura \struct{msqid\_ds},
+mantenuta all'indirizzo \param{buf}, per la coda specificata
+dall'identificatore \param{msqid}. Il comportamento della funzione dipende dal
+valore dell'argomento \param{cmd}, che specifica il tipo di azione da
+eseguire; i valori possibili sono:
+\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
+\item[\const{IPC\_STAT}] Legge le informazioni riguardo la coda nella
+ struttura indicata da \param{buf}. Occorre avere il permesso di lettura
+ sulla coda.
+\item[\const{IPC\_RMID}] Rimuove la coda, cancellando tutti i dati, con
+ effetto immediato. Tutti i processi che cercheranno di accedere alla coda
+ riceveranno un errore di \errcode{EIDRM}, e tutti processi in attesa su
+ funzioni di di lettura o di scrittura sulla coda saranno svegliati ricevendo
+ il medesimo errore. Questo comando può essere eseguito solo da un processo
+ con user-ID effettivo corrispondente al creatore o al proprietario della
+ coda, o all'amministratore.
+\item[\const{IPC\_SET}] Permette di modificare i permessi ed il proprietario
+ della coda, ed il limite massimo sulle dimensioni del totale dei messaggi in
+ essa contenuti (\var{msg\_qbytes}). I valori devono essere passati in una
+ struttura \struct{msqid\_ds} puntata da \param{buf}. Per modificare i valori
+ di \var{msg\_perm.mode}, \var{msg\_perm.uid} e \var{msg\_perm.gid} occorre
+ essere il proprietario o il creatore della coda, oppure l'amministratore; lo
+ stesso vale per \var{msg\_qbytes}, ma l'amministratore ha la facoltà di
+ incrementarne il valore a limiti superiori a \const{MSGMNB}.
+\end{basedescript}
+
+
+Una volta che si abbia a disposizione l'identificatore, per inviare un
+messaggio su una coda si utilizza la funzione \funcd{msgsnd}; il suo prototipo
+è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{sys/ipc.h}
+ \headdecl{sys/msg.h}
+
+ \funcdecl{int msgsnd(int msqid, struct msgbuf *msgp, size\_t msgsz, int
+ msgflg)}
+
+ Invia un messaggio sulla coda \param{msqid}.
+
+ \bodydesc{La funzione restituisce 0, e -1 in caso di errore, nel qual caso
+ \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] Non si hanno i privilegi di accesso sulla coda.
+ \item[\errcode{EIDRM}] La coda è stata cancellata.
+ \item[\errcode{EAGAIN}] Il messaggio non può essere inviato perché si è
+ superato il limite \var{msg\_qbytes} sul numero massimo di byte presenti
+ sulla coda, e si è richiesto \const{IPC\_NOWAIT} in \param{flag}.
+ \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale.
+ \item[\errcode{EINVAL}] Si è specificato un \param{msgid} invalido, o un
+ valore non positivo per \param{mtype}, o un valore di \param{msgsz}
+ maggiore di \const{MSGMAX}.
+ \end{errlist}
+ ed inoltre \errval{EFAULT} ed \errval{ENOMEM}.
+}
+\end{functions}
+
+La funzione inserisce il messaggio sulla coda specificata da \param{msqid}; il
+messaggio ha lunghezza specificata da \param{msgsz} ed è passato attraverso il
+l'argomento \param{msgp}. Quest'ultimo deve venire passato sempre come
+puntatore ad una struttura \struct{msgbuf} analoga a quella riportata in
+\figref{fig:ipc_msbuf} che è quella che deve contenere effettivamente il
+messaggio. La dimensione massima per il testo di un messaggio non può
+comunque superare il limite \const{MSGMAX}.
+
+La struttura di \figref{fig:ipc_msbuf} è comunque solo un modello, tanto che
+la definizione contenuta in \file{sys/msg.h} usa esplicitamente per il secondo
+campo il valore \code{mtext[1]}, che non è di nessuna utilità ai fini pratici.
+La sola cosa che conta è che la struttura abbia come primo membro un campo
+\var{mtype} come nell'esempio; esso infatti serve ad identificare il tipo di
+messaggio e deve essere sempre specificato come intero positivo di tipo
+\ctyp{long}. Il campo \var{mtext} invece può essere di qualsiasi tipo e
+dimensione, e serve a contenere il testo del messaggio.
+
+In generale pertanto per inviare un messaggio con \func{msgsnd} si usa
+ridefinire una struttura simile a quella di \figref{fig:ipc_msbuf}, adattando
+alle proprie esigenze il campo \var{mtype}, (o ridefinendo come si vuole il
+corpo del messaggio, anche con più campi o con strutture più complesse) avendo
+però la cura di mantenere nel primo campo un valore di tipo \ctyp{long} che ne
+indica il tipo.
+
+Si tenga presente che la lunghezza che deve essere indicata in questo
+argomento è solo quella del messaggio, non quella di tutta la struttura, se
+cioè \var{message} è una propria struttura che si passa alla funzione,
+\param{msgsz} dovrà essere uguale a \code{sizeof(message)-sizeof(long)}, (se
+consideriamo il caso dell'esempio in \figref{fig:ipc_msbuf}, \param{msgsz}
+dovrà essere pari a \const{LENGTH}).
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}
+ struct msgbuf {
+ long mtype; /* message type, must be > 0 */
+ char mtext[LENGTH]; /* message data */
+ };
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Schema della struttura \structd{msgbuf}, da utilizzare come
+ argomento per inviare/ricevere messaggi.}
+ \label{fig:ipc_msbuf}
+\end{figure}
+
+Per capire meglio il funzionamento della funzione riprendiamo in
+considerazione la struttura della coda illustrata in
+\figref{fig:ipc_mq_schema}. Alla chiamata di \func{msgsnd} il nuovo messaggio
+sarà aggiunto in fondo alla lista inserendo una nuova struttura \struct{msg},
+il puntatore \var{msg\_last} di \struct{msqid\_ds} verrà aggiornato, come pure
+il puntatore al messaggio successivo per quello che era il precedente ultimo
+messaggio; il valore di \var{mtype} verrà mantenuto in \var{msg\_type} ed il
+valore di \param{msgsz} in \var{msg\_ts}; il testo del messaggio sarà copiato
+all'indirizzo specificato da \var{msg\_spot}.
+
+Il valore dell'argomento \param{flag} permette di specificare il comportamento
+della funzione. Di norma, quando si specifica un valore nullo, la funzione
+ritorna immediatamente a meno che si sia ecceduto il valore di
+\var{msg\_qbytes}, o il limite di sistema sul numero di messaggi, nel qual
+caso si blocca mandando il processo in stato di \textit{sleep}. Se si
+specifica per \param{flag} il valore \const{IPC\_NOWAIT} la funzione opera in
+modalità non bloccante, ed in questi casi ritorna immediatamente con un errore
+di \errcode{EAGAIN}.
+
+Se non si specifica \const{IPC\_NOWAIT} la funzione resterà bloccata fintanto
+che non si liberano risorse sufficienti per poter inserire nella coda il
+messaggio, nel qual caso ritornerà normalmente. La funzione può ritornare, con
+una condizione di errore anche in due altri casi: quando la coda viene rimossa
+(nel qual caso si ha un errore di \errcode{EIDRM}) o quando la funzione viene
+interrotta da un segnale (nel qual caso si ha un errore di \errcode{EINTR}).
+
+Una volta completato con successo l'invio del messaggio sulla coda, la
+funzione aggiorna i dati mantenuti in \struct{msqid\_ds}, in particolare
+vengono modificati:
+\begin{itemize*}
+\item Il valore di \var{msg\_lspid}, che viene impostato al \acr{pid} del
+ processo chiamante.
+\item Il valore di \var{msg\_qnum}, che viene incrementato di uno.
+\item Il valore \var{msg\_stime}, che viene impostato al tempo corrente.
+\end{itemize*}
+
+La funzione che viene utilizzata per estrarre un messaggio da una coda è
+\funcd{msgrcv}; il suo prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{sys/ipc.h}
+ \headdecl{sys/msg.h}
+
+ \funcdecl{ssize\_t msgrcv(int msqid, struct msgbuf *msgp, size\_t msgsz,
+ long msgtyp, int msgflg)}
+
+ Legge un messaggio dalla coda \param{msqid}.
+
+ \bodydesc{La funzione restituisce il numero di byte letti in caso di
+ successo, e -1 in caso di errore, nel qual caso \var{errno} assumerà uno
+ dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] Non si hanno i privilegi di accesso sulla coda.
+ \item[\errcode{EIDRM}] La coda è stata cancellata.
+ \item[\errcode{E2BIG}] Il testo del messaggio è più lungo di \param{msgsz} e
+ non si è specificato \const{MSG\_NOERROR} in \param{msgflg}.
+ \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale mentre
+ era in attesa di ricevere un messaggio.
+ \item[\errcode{EINVAL}] Si è specificato un \param{msgid} invalido o un
+ valore di \param{msgsz} negativo.
+ \end{errlist}
+ ed inoltre \errval{EFAULT}.
+}
+\end{functions}
+
+La funzione legge un messaggio dalla coda specificata, scrivendolo sulla
+struttura puntata da \param{msgp}, che dovrà avere un formato analogo a quello
+di \figref{fig:ipc_msbuf}. Una volta estratto, il messaggio sarà rimosso dalla
+coda. L'argomento \param{msgsz} indica la lunghezza massima del testo del
+messaggio (equivalente al valore del parametro \const{LENGTH} nell'esempio di
+\figref{fig:ipc_msbuf}).
+
+Se il testo del messaggio ha lunghezza inferiore a \param{msgsz} esso viene
+rimosso dalla coda; in caso contrario, se \param{msgflg} è impostato a
+\const{MSG\_NOERROR}, il messaggio viene troncato e la parte in eccesso viene
+perduta, altrimenti il messaggio non viene estratto e la funzione ritorna con
+un errore di \errcode{E2BIG}.
+
+L'argomento \param{msgtyp} permette di restringere la ricerca ad un
+sottoinsieme dei messaggi presenti sulla coda; la ricerca infatti è fatta con
+una scansione della struttura mostrata in \figref{fig:ipc_mq_schema},
+restituendo il primo messaggio incontrato che corrisponde ai criteri
+specificati (che quindi, visto come i messaggi vengono sempre inseriti dalla
+coda, è quello meno recente); in particolare:
+\begin{itemize}
+\item se \param{msgtyp} è 0 viene estratto il messaggio in cima alla coda, cioè
+ quello fra i presenti che è stato inserito inserito per primo.
+\item se \param{msgtyp} è positivo viene estratto il primo messaggio il cui
+ tipo (il valore del campo \var{mtype}) corrisponde al valore di
+ \param{msgtyp}.
+\item se \param{msgtyp} è negativo viene estratto il primo fra i messaggi con
+ il valore più basso del tipo, fra tutti quelli il cui tipo ha un valore
+ inferiore al valore assoluto di \param{msgtyp}.
+\end{itemize}
+
+Il valore di \param{msgflg} permette di controllare il comportamento della
+funzione, esso può essere nullo o una maschera binaria composta da uno o più
+valori. Oltre al precedente \const{MSG\_NOERROR}, sono possibili altri due
+valori: \const{MSG\_EXCEPT}, che permette, quando \param{msgtyp} è positivo,
+di leggere il primo messaggio nella coda con tipo diverso da \param{msgtyp}, e
+\const{IPC\_NOWAIT} che causa il ritorno immediato della funzione quando non
+ci sono messaggi sulla coda.
+
+Il comportamento usuale della funzione infatti, se non ci sono messaggi
+disponibili per la lettura, è di bloccare il processo in stato di
+\textit{sleep}. Nel caso però si sia specificato \const{IPC\_NOWAIT} la
+funzione ritorna immediatamente con un errore \errcode{ENOMSG}. Altrimenti la
+funzione ritorna normalmente non appena viene inserito un messaggio del tipo
+desiderato, oppure ritorna con errore qualora la coda sia rimossa (con
+\var{errno} impostata a \errcode{EIDRM}) o se il processo viene interrotto da
+un segnale (con \var{errno} impostata a \errcode{EINTR}).
+
+Una volta completata con successo l'estrazione del messaggio dalla coda, la
+funzione aggiorna i dati mantenuti in \struct{msqid\_ds}, in particolare
+vengono modificati:
+\begin{itemize*}
+\item Il valore di \var{msg\_lrpid}, che viene impostato al \acr{pid} del
+ processo chiamante.
+\item Il valore di \var{msg\_qnum}, che viene decrementato di uno.
+\item Il valore \var{msg\_rtime}, che viene impostato al tempo corrente.
+\end{itemize*}
+
+Le code di messaggi presentano il solito problema di tutti gli oggetti del
+SysV IPC; essendo questi permanenti restano nel sistema occupando risorse
+anche quando un processo è terminato, al contrario delle pipe per le quali
+tutte le risorse occupate vengono rilasciate quanto l'ultimo processo che le
+utilizzava termina. Questo comporta che in caso di errori si può saturare il
+sistema, e che devono comunque essere esplicitamente previste delle funzioni
+di rimozione in caso di interruzioni o uscite dal programma (come vedremo in
+\figref{fig:ipc_mq_fortune_server}).
+
+L'altro problema è non facendo uso di file descriptor le tecniche di
+\textit{I/O multiplexing} descritte in \secref{sec:file_multiplexing} non
+possono essere utilizzate, e non si ha a disposizione niente di analogo alle
+funzioni \func{select} e \func{poll}. Questo rende molto scomodo usare più di
+una di queste strutture alla volta; ad esempio non si può scrivere un server
+che aspetti un messaggio su più di una coda senza fare ricorso ad una tecnica
+di \textit{polling}\index{polling} che esegua un ciclo di attesa su ciascuna
+di esse.
+
+Come esempio dell'uso delle code di messaggi possiamo riscrivere il nostro
+server di \textit{fortunes} usando queste al posto delle fifo. In questo caso
+useremo una sola coda di messaggi, usando il tipo di messaggio per comunicare
+in maniera indipendente con client diversi.
+
+\begin{figure}[!bht]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+int msgid; /* Message queue identifier */
+int main(int argc, char *argv[])
+{
+/* Variables definition */
+ int i, n = 0;
+ char **fortune; /* array of fortune message string */
+ char *fortunefilename = "/usr/share/games/fortunes/linux"; /* file name */
+ struct msgbuf_read { /* message struct to read request from clients */
+ long mtype; /* message type, must be 1 */
+ long pid; /* message data, must be the pid of the client */
+ } msg_read;
+ struct msgbuf_write { /* message struct to write result to clients */
+ long mtype; /* message type, will be the pid of the client*/
+ char mtext[MSGMAX]; /* message data, will be the fortune */
+ } msg_write;
+ key_t key; /* Message queue key */
+ int size; /* message size */
+ ...
+ Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
+ Signal(SIGINT, HandSIGTERM);
+ Signal(SIGQUIT, HandSIGTERM);
+ if (n==0) usage(); /* if no pool depth exit printing usage info */
+ i = FortuneParse(fortunefilename, fortune, n); /* parse phrases */
+ /* Create the queue */
+ key = ftok("./MQFortuneServer.c", 1);
+ msgid = msgget(key, IPC_CREAT|0666);
+ if (msgid < 0) {
+ perror("Cannot create message queue");
+ exit(1);
+ }
+ /* Main body: loop over requests */
+ daemon(0, 0);
+ while (1) {
+ msgrcv(msgid, &msg_read, sizeof(int), 1, MSG_NOERROR);
+ n = random() % i; /* select random value */
+ strncpy(msg_write.mtext, fortune[n], MSGMAX);
+ size = min(strlen(fortune[n])+1, MSGMAX);
+ msg_write.mtype=msg_read.pid; /* use request pid as type */
+ msgsnd(msgid, &msg_write, size, 0);
+ }
+}
+/*
+ * Signal Handler to manage termination
+ */
+void HandSIGTERM(int signo) {
+ msgctl(msgid, IPC_RMID, NULL); /* remove message queue */
+ exit(0);
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Sezione principale del codice del server di \textit{fortunes}
+ basato sulle \textit{message queue}.}
+ \label{fig:ipc_mq_fortune_server}
+\end{figure}
+
+In \figref{fig:ipc_mq_fortune_server} si è riportato un estratto delle parti
+principali del codice del nuovo server (il codice completo è nel file
+\file{MQFortuneServer.c} nei sorgenti allegati). Il programma è basato su un
+uso accorto della caratteristica di poter associate un ``tipo'' ai messaggi
+per permettere una comunicazione indipendente fra il server ed i vari client,
+usando il \acr{pid} di questi ultimi come identificativo. Questo è possibile
+in quanto, al contrario di una fifo, la lettura di una coda di messaggi può
+non essere sequenziale, proprio grazie alla classificazione dei messaggi sulla
+base del loro tipo.
+
+Il programma, oltre alle solite variabili per il nome del file da cui leggere
+le \textit{fortunes} e per il vettore di stringhe che contiene le frasi,
+definisce due strutture appositamente per la comunicazione; con
+\var{msgbuf\_read} (\texttt{\small 8--11}) vengono passate le richieste mentre
+con \var{msgbuf\_write} (\texttt{\small 12--15}) vengono restituite le frasi.
+
+La gestione delle opzioni si è al solito omessa, essa si curerà di impostare
+in \var{n} il numero di frasi da leggere specificato a linea di comando ed in
+\var{fortunefilename} il file da cui leggerle; dopo aver installato
+(\texttt{\small 19--21}) i gestori dei segnali per trattare l'uscita dal
+server, viene prima controllato (\texttt{\small 22}) il numero di frasi
+richieste abbia senso (cioè sia maggiore di zero), le quali poi
+(\texttt{\small 23}) vengono lette nel vettore in memoria con la stessa
+funzione \code{FortuneParse} usata anche per il server basato sulle fifo.
+
+Una volta inizializzato il vettore di stringhe coi messaggi presi dal file
+delle \textit{fortune} si procede (\texttt{\small 25}) con la generazione di
+una chiave per identificare la coda di messaggi (si usa il nome del file dei
+sorgenti del server) con la quale poi si esegue (\texttt{\small 26}) la
+creazione della stessa (si noti come si sia chiamata \func{msgget} con un
+valore opportuno per l'argomento \param{flag}), avendo cura di abortire il
+programma (\texttt{\small 27--29}) in caso di errore.
+
+Finita la fase di inizializzazione il server 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]{15cm}
+ \begin{lstlisting}{}
+int main(int argc, char *argv[])
+{
+ ...
+ key = ftok("./MQFortuneServer.c", 1);
+ msgid = msgget(key, 0);
+ if (msgid < 0) {
+ perror("Cannot find message queue");
+ exit(1);
+ }
+ /* Main body: do request and write result */
+ msg_read.mtype = 1; /* type for request is always 1 */
+ msg_read.pid = getpid(); /* use pid for communications */
+ size = sizeof(msg_read.pid);
+ msgsnd(msgid, &msg_read, size, 0); /* send request message */
+ msgrcv(msgid, &msg_write, MSGMAX, msg_read.pid, MSG_NOERROR);
+ printf("%s", msg_write.mtext);
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Sezione principale del codice del client di \textit{fortunes}
+ basato sulle \textit{message queue}.}
+ \label{fig:ipc_mq_fortune_client}
+\end{figure}
+
+In \figref{fig:ipc_mq_fortune_client} si è riportato un estratto il codice del
+programma client. Al solito il codice completo è con i sorgenti allegati, nel
+file \file{MQFortuneClient.c}. Come sempre si sono rimosse le parti relative
+alla gestione delle opzioni, ed in questo caso, anche la dichiarazione delle
+variabili, che, per la parte relative alle strutture usate per la
+comunicazione tramite le code, sono le stesse viste in
+\figref{fig:ipc_mq_fortune_server}.
+
+Il client in questo caso è molto semplice; la prima parte del programma
+(\texttt{\small 4--9}) si occupa di accedere alla coda di messaggi, ed è
+identica a quanto visto per il server, solo che in questo caso \func{msgget}
+non viene chiamata con il flag di creazione in quanto la coda deve essere
+preesistente. In caso di errore (ad esempio se il server non è stato avviato)
+il programma termina immediatamente.
+
+Una volta acquisito l'identificatore della coda il client compone il
+messaggio di richiesta (\texttt{\small 12--13}) in \var{msg\_read}, usando 1
+per il tipo ed inserendo il proprio \acr{pid} come dato da passare al server.
+Calcolata (\texttt{\small 14}) la dimensione, provvede (\texttt{\small 15}) ad
+immettere la richiesta sulla coda.
+
+A questo punto non resta che (\texttt{\small 16}) rileggere dalla coda la
+risposta del server richiedendo a \func{msgrcv} di selezionare i messaggi di
+tipo corrispondente al valore del \acr{pid} inviato nella richiesta. L'ultimo
+passo (\texttt{\small 17}) prima di uscire è quello di stampare a video il
+messaggio ricevuto.
+
+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 \secref{sec:proc_race_cond}).
+
+Un semaforo è uno speciale contatore, mantenuto nel kernel, che permette, a
+seconda del suo valore, di consentire o meno la prosecuzione dell'esecuzione
+di un programma. In questo modo l'accesso ad una risorsa condivisa da più
+processi può essere controllato, associando ad essa un semaforo che consente
+di assicurare che non più di un processo alla volta possa usarla.
+
+Il concetto di semaforo è uno dei concetti base nella programmazione ed è
+assolutamente generico, così come del tutto generali sono modalità con cui lo
+si utilizza. Un processo che deve accedere ad una risorsa eseguirà un
+controllo del semaforo: se questo è positivo il suo valore sarà decrementato,
+indicando che si è consumato una unità della risorsa, ed il processo potrà
+proseguire nell'utilizzo di quest'ultima, provvedendo a rilasciarla, una volta
+completate le operazioni volute, reincrementando il semaforo.
+
+Se al momento del controllo il valore del semaforo è nullo, siamo invece in
+una situazione in cui la risorsa non è disponibile, ed il processo si
+bloccherà in stato di \textit{sleep} fin quando chi la sta utilizzando non la
+rilascerà, incrementando il valore del semaforo. Non appena il semaforo torna
+positivo, indicando che la risorsa è disponibile, il processo sarà svegliato,
+e si potrà operare come nel caso precedente (decremento del semaforo, accesso
+alla risorsa, incremento del semaforo).
+
+Per poter implementare questo tipo di logica le operazioni di controllo e
+decremento del contatore associato al semaforo devono essere atomiche,
+pertanto una realizzazione di un oggetto di questo tipo è necessariamente
+demandata al kernel. La forma più semplice di semaforo è quella del
+\textsl{semaforo binario}, o \textit{mutex}, in cui un valore diverso da zero
+(normalmente 1) indica la libertà di accesso, e un valore nullo l'occupazione
+della risorsa; in generale però si possono usare semafori con valori interi,
+utilizzando il valore del contatore come indicatore del ``numero di risorse''
+ancora disponibili.
+
+Il sistema di comunicazione inter-processo di \textit{SysV IPC} prevede anche i
+semafori, ma gli oggetti utilizzati non sono semafori singoli, ma gruppi di
+semafori detti \textsl{insiemi} (o \textit{semaphore set}); la funzione che
+permette di creare o ottenere l'identificatore di un insieme di semafori è
+\funcd{semget}, ed il suo prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{sys/ipc.h}
+ \headdecl{sys/sem.h}
+
+ \funcdecl{int semget(key\_t key, int nsems, int flag)}
+
+ Restituisce l'identificatore di un insieme di semafori.
+
+ \bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
+ in caso di errore, nel qual caso \var{errno} assumerà i valori:
+ \begin{errlist}
+ \item[\errcode{ENOSPC}] Si è cercato di creare una insieme di semafori
+ quando è stato superato o il limite per il numero totale di semafori
+ (\const{SEMMNS}) o quello per il numero totale degli insiemi
+ (\const{SEMMNI}) nel sistema.
+ \item[\errcode{EINVAL}] L'argomento \param{nsems} è minore di zero o
+ maggiore del limite sul numero di semafori per ciascun insieme
+ (\const{SEMMSL}), o se l'insieme già esiste, maggiore del numero di
+ semafori che contiene.
+ \item[\errcode{ENOMEM}] Il sistema non ha abbastanza memoria per poter
+ contenere le strutture per un nuovo insieme di semafori.
+ \end{errlist}
+ ed inoltre \errval{EACCES}, \errval{ENOENT}, \errval{EEXIST},
+ \errval{EIDRM}, con lo stesso significato che hanno per \func{msgget}.}
+\end{functions}
+
+La funzione è del tutto analoga a \func{msgget}, solo che in questo caso
+restituisce l'identificatore di un insieme di semafori, in particolare è
+identico l'uso degli argomenti \param{key} e \param{flag}, per cui non
+ripeteremo quanto detto al proposito in \secref{sec:ipc_sysv_mq}. L'argomento
+\param{nsems} permette di specificare quanti semafori deve contenere l'insieme
+quando se ne richieda la creazione, e deve essere nullo quando si effettua una
+richiesta dell'identificatore di un insieme già esistente.
+
+Purtroppo questa implementazione complica inutilmente lo schema elementare che
+abbiamo descritto, dato che non è possibile definire un singolo semaforo, ma
+se ne deve creare per forza un insieme. Ma questa in definitiva è solo una
+complicazione inutile, il problema è che i semafori del \textit{SysV IPC}
+soffrono di altri due, ben più gravi, difetti.
+
+Il primo difetto è che non esiste una funzione che permetta di creare ed
+inizializzare un semaforo in un'unica chiamata; occorre prima creare l'insieme
+dei semafori con \func{semget} e poi inizializzarlo con \func{semctl}, si
+perde così ogni possibilità di eseguire l'operazione atomicamente.
+
+Il secondo difetto deriva dalla caratteristica generale degli oggetti del
+\textit{SysV IPC} di essere risorse globali di sistema, che non vengono
+cancellate quando nessuno le usa più; ci si così a trova a dover affrontare
+esplicitamente il caso in cui un processo termina per un qualche errore,
+lasciando un semaforo occupato, che resterà tale fino al successivo riavvio
+del sistema. Come vedremo esistono delle modalità per evitare tutto ciò, ma
+diventa necessario indicare esplicitamente che si vuole il ripristino del
+semaforo all'uscita del processo.
+
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}
+struct semid_ds
+{
+ struct ipc_perm sem_perm; /* operation permission struct */
+ time_t sem_otime; /* last semop() time */
+ time_t sem_ctime; /* last time changed by semctl() */
+ unsigned long int sem_nsems; /* number of semaphores in set */
+};
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \structd{semid\_ds}, associata a ciascun insieme di
+ semafori.}
+ \label{fig:ipc_semid_ds}
+\end{figure}
+
+A ciascun insieme di semafori è associata una struttura \struct{semid\_ds},
+riportata in \figref{fig:ipc_semid_ds}.\footnote{non si sono riportati i campi
+ ad uso interno del kernel, che vedremo in \figref{fig:ipc_sem_schema}, che
+ dipendono dall'implementazione.} Come nel caso delle code di messaggi quando
+si crea un nuovo insieme di semafori con \func{semget} questa struttura viene
+inizializzata, in particolare il campo \var{sem\_perm} viene inizializzato
+come illustrato in \secref{sec:ipc_sysv_access_control} (si ricordi che in
+questo caso il permesso di scrittura è in realtà permesso di alterare il
+semaforo), per quanto riguarda gli altri campi invece:
+\begin{itemize*}
+\item il campo \var{sem\_nsems}, che esprime il numero di semafori
+ nell'insieme, viene inizializzato al valore di \param{nsems}.
+\item il campo \var{sem\_ctime}, che esprime il tempo di creazione
+ dell'insieme, viene inizializzato al tempo corrente.
+\item il campo \var{sem\_otime}, che esprime il tempo dell'ultima operazione
+ effettuata, viene inizializzato a zero.
+\end{itemize*}
+
+
+Ciascun semaforo dell'insieme è realizzato come una struttura di tipo
+\struct{sem} che ne contiene i dati essenziali, la sua definizione\footnote{si
+ è riportata la definizione originaria del kernel 1.0, che contiene la prima
+ realizzazione del \textit{SysV IPC} in Linux. In realtà questa struttura
+ ormai è ridotta ai soli due primi membri, e gli altri vengono calcolati
+ dinamicamente. La si è utilizzata a scopo di esempio, perché indica tutti i
+ valori associati ad un semaforo, restituiti dalle funzioni di controllo, e
+ citati dalle pagine di manuale.} è riportata in \figref{fig:ipc_sem}. Questa
+struttura, non è accessibile in user space, ma i valori in essa specificati
+possono essere letti in maniera indiretta, attraverso l'uso delle funzioni di
+controllo.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}
+struct sem {
+ short sempid; /* pid of last operation */
+ ushort semval; /* current value */
+ ushort semncnt; /* num procs awaiting increase in semval */
+ ushort semzcnt; /* num procs awaiting semval = 0 */
+};
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \structd{sem}, che contiene i dati di un singolo
+ semaforo.}
+ \label{fig:ipc_sem}
+\end{figure}
+
+I dati mantenuti nella struttura, ed elencati in \figref{fig:ipc_sem},
+indicano rispettivamente:
+\begin{description*}
+\item[\var{semval}] il valore numerico del semaforo.
+\item[\var{sempid}] il \acr{pid} dell'ultimo processo che ha eseguito una
+ operazione sul semaforo.
+\item[\var{semncnt}] il numero di processi in attesa che esso venga
+ incrementato.
+\item[\var{semzcnt}] il numero di processi in attesa che esso si annulli.
+\end{description*}
+
+\begin{table}[htb]
+ \footnotesize
+ \centering
+ \begin{tabular}[c]{|c|r|p{8cm}|}
+ \hline
+ \textbf{Costante} & \textbf{Valore} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{SEMMNI}& 128 & Numero massimo di insiemi di semafori. \\
+ \const{SEMMSL}& 250 & Numero massimo di semafori per insieme.\\
+ \const{SEMMNS}&\const{SEMMNI}*\const{SEMMSL}& Numero massimo di semafori
+ nel sistema .\\
+ \const{SEMVMX}& 32767 & Massimo valore per un semaforo.\\
+ \const{SEMOPM}& 32 & Massimo numero di operazioni per chiamata a
+ \func{semop}. \\
+ \const{SEMMNU}&\const{SEMMNS}& Massimo numero di strutture di ripristino.\\
+ \const{SEMUME}&\const{SEMOPM}& Massimo numero di voci di ripristino.\\
+ \const{SEMAEM}&\const{SEMVMX}& valore massimo per l'aggiustamento
+ all'uscita. \\
+ \hline
+ \end{tabular}
+ \caption{Valori delle costanti associate ai limiti degli insiemi di
+ semafori, definite in \file{linux/sem.h}.}
+ \label{tab:ipc_sem_limits}
+\end{table}
+
+Come per le code di messaggi anche per gli insiemi di semafori esistono una
+serie di limiti, i cui valori sono associati ad altrettante costanti, che si
+sono riportate in \tabref{tab:ipc_sem_limits}. Alcuni di questi limiti sono al
+solito accessibili e modificabili attraverso \func{sysctl} o scrivendo
+direttamente nel file \file{/proc/sys/kernel/sem}.
+
+La funzione che permette di effettuare le varie operazioni di controllo sui
+semafori (fra le quali, come accennato, è impropriamente compresa anche la
+loro inizializzazione) è \funcd{semctl}; il suo prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{sys/ipc.h}
+ \headdecl{sys/sem.h}
+
+ \funcdecl{int semctl(int semid, int semnum, int cmd)}
+ \funcdecl{int semctl(int semid, int semnum, int cmd, union semun arg)}
+
+ Esegue le operazioni di controllo su un semaforo o un insieme di semafori.
+
+ \bodydesc{La funzione restituisce in caso di successo un valore positivo
+ quanto usata con tre argomenti ed un valore nullo quando usata con
+ quattro. In caso di errore restituisce -1, ed \var{errno} assumerà uno dei
+ valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] Il processo non ha i privilegi per eseguire
+ l'operazione richiesta.
+ \item[\errcode{EIDRM}] L'insieme di semafori è stato cancellato.
+ \item[\errcode{EPERM}] Si è richiesto \const{IPC\_SET} o \const{IPC\_RMID}
+ ma il processo non ha privilegi sufficienti ad eseguire l'operazione.
+ \item[\errcode{ERANGE}] Si è richiesto \const{SETALL} \const{SETVAL} ma il
+ valore a cui si vuole impostare il semaforo è minore di zero o maggiore
+ di \const{SEMVMX}.
+ \end{errlist}
+ ed inoltre \errval{EFAULT} ed \errval{EINVAL}.
+}
+\end{functions}
+
+La funzione può avere tre o quattro parametri, a seconda dell'operazione
+specificata con \param{cmd}, ed opera o sull'intero insieme specificato da
+\param{semid} o sul singolo semaforo di un insieme, specificato da
+\param{semnum}.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}
+union semun {
+ int val; /* value for SETVAL */
+ struct semid_ds *buf; /* buffer for IPC_STAT, IPC_SET */
+ unsigned short *array; /* array for GETALL, SETALL */
+ /* Linux specific part: */
+ struct seminfo *__buf; /* buffer for IPC_INFO */
+};
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La definizione dei possibili valori di una \direct{union}
+ \structd{semun}, usata come quarto argomento della funzione
+ \func{semctl}.}
+ \label{fig:ipc_semun}
+\end{figure}
+
+Qualora la funzione operi con quattro argomenti \param{arg} è un argomento
+generico, che conterrà un dato diverso a seconda dell'azione richiesta; per
+unificare l'argomento esso deve essere passato come una \struct{semun}, la cui
+definizione, con i possibili valori che può assumere, è riportata in
+\figref{fig:ipc_semun}.
+
+Come già accennato sia il comportamento della funzione che il numero di
+parametri con cui deve essere invocata, dipendono dal valore dell'argomento
+\param{cmd}, che specifica l'azione da intraprendere; i valori validi (che
+cioè non causano un errore di \errcode{EINVAL}) per questo argomento sono i
+seguenti:
+\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
+\item[\const{IPC\_STAT}] Legge i dati dell'insieme di semafori, copiando il
+ contenuto della relativa struttura \struct{semid\_ds} all'indirizzo
+ specificato con \var{arg.buf}. Occorre avere il permesso di lettura.
+ L'argomento \param{semnum} viene ignorato.
+\item[\const{IPC\_RMID}] Rimuove l'insieme di semafori e le relative strutture
+ dati, con effetto immediato. Tutti i processi che erano stato di
+ \textit{sleep} vengono svegliati, ritornando con un errore di
+ \errcode{EIDRM}. L'user-ID effettivo del processo deve corrispondere o al
+ creatore o al proprietario dell'insieme, o all'amministratore. L'argomento
+ \param{semnum} viene ignorato.
+\item[\const{IPC\_SET}] Permette di modificare i permessi ed il proprietario
+ dell'insieme. I valori devono essere passati in una struttura
+ \struct{semid\_ds} puntata da \param{arg.buf} di cui saranno usati soltanto i
+ campi \var{sem\_perm.uid}, \var{sem\_perm.gid} e i nove bit meno
+ significativi di \var{sem\_perm.mode}. L'user-ID effettivo del processo deve
+ corrispondere o al creatore o al proprietario dell'insieme, o
+ all'amministratore. L'argomento \param{semnum} viene ignorato.
+\item[\const{GETALL}] Restituisce il valore corrente di ciascun semaforo
+ dell'insieme (corrispondente al campo \var{semval} di \struct{sem}) nel
+ vettore indicato da \param{arg.array}. Occorre avere il permesso di lettura.
+ L'argomento \param{semnum} viene ignorato.
+\item[\const{GETNCNT}] Restituisce come valore di ritorno della funzione il
+ numero di processi in attesa che il semaforo \param{semnum} dell'insieme
+ \param{semid} venga incrementato (corrispondente al campo \var{semncnt} di
+ \struct{sem}); va invocata con tre argomenti. Occorre avere il permesso di
+ lettura.
+\item[\const{GETPID}] Restituisce come valore di ritorno della funzione il
+ \acr{pid} dell'ultimo processo che ha compiuto una operazione sul semaforo
+ \param{semnum} dell'insieme \param{semid} (corrispondente al campo
+ \var{sempid} di \struct{sem}); va invocata con tre argomenti. Occorre avere
+ il permesso di lettura.
+\item[\const{GETVAL}] Restituisce come valore di ritorno della funzione il il
+ valore corrente del semaforo \param{semnum} dell'insieme \param{semid}
+ (corrispondente al campo \var{semval} di \struct{sem}); va invocata con tre
+ argomenti. Occorre avere il permesso di lettura.
+\item[\const{GETZCNT}] Restituisce come valore di ritorno della funzione il
+ numero di processi in attesa che il valore del semaforo \param{semnum}
+ dell'insieme \param{semid} diventi nullo (corrispondente al campo
+ \var{semncnt} di \struct{sem}); va invocata con tre argomenti. Occorre avere
+ il permesso di lettura.
+\item[\const{SETALL}] Inizializza il valore di tutti i semafori dell'insieme,
+ aggiornando il campo \var{sem\_ctime} di \struct{semid\_ds}. I valori devono
+ essere passati nel vettore indicato da \param{arg.array}. Si devono avere i
+ privilegi di scrittura sul semaforo. L'argomento \param{semnum} viene
+ ignorato.
+\item[\const{SETVAL}] Inizializza il semaforo \param{semnum} al valore passato
+ dall'argomento \param{arg.val}, aggiornando il campo \var{sem\_ctime} di
+ \struct{semid\_ds}. Si devono avere i privilegi di scrittura sul semaforo.
+\end{basedescript}
+
+Quando si imposta il valore di un semaforo (sia che lo si faccia per tutto
+l'insieme con \const{SETALL}, che per un solo semaforo con \const{SETVAL}), i
+processi in attesa su di esso reagiscono di conseguenza al cambiamento di
+valore. Inoltre la coda delle operazioni di ripristino viene cancellata per
+tutti i semafori il cui valore viene modificato.
+
+\begin{table}[htb]
+ \footnotesize
+ \centering
+ \begin{tabular}[c]{|c|l|}
+ \hline
+ \textbf{Operazione} & \textbf{Valore restituito} \\
+ \hline
+ \hline
+ \const{GETNCNT}& valore di \var{semncnt}.\\
+ \const{GETPID} & valore di \var{sempid}.\\
+ \const{GETVAL} & valore di \var{semval}.\\
+ \const{GETZCNT}& valore di \var{semzcnt}.\\
+ \hline
+ \end{tabular}
+ \caption{Valori di ritorno della funzione \func{semctl}.}
+ \label{tab:ipc_semctl_returns}
+\end{table}
+
+Il valore di ritorno della funzione in caso di successo dipende
+dall'operazione richiesta; per tutte le operazioni che richiedono quattro
+argomenti esso è sempre nullo, per le altre operazioni, elencate in
+\tabref{tab:ipc_semctl_returns} viene invece restituito il valore richiesto,
+corrispondente al campo della struttura \struct{sem} indicato nella seconda
+colonna della tabella.
+
+Le operazioni ordinarie sui semafori, come l'acquisizione o il rilascio degli
+stessi (in sostanza tutte quelle non comprese nell'uso di \func{semctl})
+vengono effettuate con la funzione \funcd{semop}, il cui prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{sys/ipc.h}
+ \headdecl{sys/sem.h}
+
+ \funcdecl{int semop(int semid, struct sembuf *sops, unsigned nsops)}
+
+ Esegue le operazioni ordinarie su un semaforo o un insieme di semafori.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+ errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] Il processo non ha i privilegi per eseguire
+ l'operazione richiesta.
+ \item[\errcode{EIDRM}] L'insieme di semafori è stato cancellato.
+ \item[\errcode{ENOMEM}] Si è richiesto un \const{SEM\_UNDO} ma il sistema
+ non ha le risorse per allocare la struttura di ripristino.
+ \item[\errcode{EAGAIN}] Un'operazione comporterebbe il blocco del processo,
+ ma si è specificato \const{IPC\_NOWAIT} in \var{sem\_flg}.
+ \item[\errcode{EINTR}] La funzione, bloccata in attesa dell'esecuzione
+ dell'operazione, viene interrotta da un segnale.
+ \item[\errcode{E2BIG}] L'argomento \param{nsops} è maggiore del numero
+ massimo di operazioni \const{SEMOPM}.
+ \item[\errcode{ERANGE}] Per alcune operazioni il valore risultante del
+ semaforo viene a superare il limite massimo \const{SEMVMX}.
+ \end{errlist}
+ ed inoltre \errval{EFAULT} ed \errval{EINVAL}.
+}
+\end{functions}
+
+La funzione permette di eseguire operazioni multiple sui singoli semafori di
+un insieme. La funzione richiede come primo argomento l'identificatore
+\param{semid} dell'insieme su cui si vuole operare. Il numero di operazioni da
+effettuare viene specificato con l'argomento \param{nsop}, mentre il loro
+contenuto viene passato con un puntatore ad un vettore di strutture
+\struct{sembuf} nell'argomento \param{sops}. Le operazioni richieste vengono
+effettivamente eseguite se e soltanto se è possibile effettuarle tutte quante.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}
+struct sembuf
+{
+ unsigned short int sem_num; /* semaphore number */
+ short int sem_op; /* semaphore operation */
+ short int sem_flg; /* operation flag */
+};
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \structd{sembuf}, usata per le operazioni sui
+ semafori.}
+ \label{fig:ipc_sembuf}
+\end{figure}
+
+Il contenuto di ciascuna operazione deve essere specificato attraverso una
+opportuna struttura \struct{sembuf} (la cui definizione è riportata in
+\figref{fig:ipc_sembuf}) che il programma chiamante deve avere cura di
+allocare in un opportuno vettore. La struttura permette di indicare il
+semaforo su cui operare, il tipo di operazione, ed un flag di controllo.
+Il campo \var{sem\_num} serve per indicare a quale semaforo dell'insieme fa
+riferimento l'operazione; si ricordi che i semafori sono numerati come in un
+vettore, per cui il primo semaforo corrisponde ad un valore nullo di
+\var{sem\_num}.
+
+Il campo \var{sem\_flg} è un flag, mantenuto come maschera binaria, per il
+quale possono essere impostati i due valori \const{IPC\_NOWAIT} e
+\const{SEM\_UNDO}. Impostando \const{IPC\_NOWAIT} si fa si che, invece di
+bloccarsi (in tutti quei casi in cui l'esecuzione di una operazione richiede
+che il processo vada in stato di \textit{sleep}), \func{semop} ritorni
+immediatamente con un errore di \errcode{EAGAIN}. Impostando \const{SEM\_UNDO}
+si richiede invece che l'operazione venga registrata in modo che il valore del
+semaforo possa essere ripristinato all'uscita del processo.
+
+Infine \var{sem\_op} è il campo che controlla l'operazione che viene eseguita
+e determina il comportamento della chiamata a \func{semop}; tre sono i casi
+possibili:
+\begin{basedescript}{\desclabelwidth{2.0cm}}
+\item[\var{sem\_op}$>0$] In questo caso il valore di \var{sem\_op} viene
+ aggiunto al valore corrente di \var{semval}. La funzione ritorna
+ immediatamente (con un errore di \errcode{ERANGE} qualora si sia superato il
+ limite \const{SEMVMX}) ed il processo non viene bloccato in nessun caso.
+ Specificando \const{SEM\_UNDO} si aggiorna il contatore per il ripristino
+ del valore del semaforo. Al processo chiamante è richiesto il privilegio di
+ alterazione (scrittura) sull'insieme di semafori.
+
+\item[\var{sem\_op}$=0$] Nel caso \var{semval} sia zero l'esecuzione procede
+ immediatamente. Se \var{semval} è diverso da zero il comportamento è
+ controllato da \var{sem\_flg}, se è stato impostato \const{IPC\_NOWAIT} la
+ funzione ritorna con un errore di \errcode{EAGAIN}, altrimenti viene
+ incrementato \var{semzcnt} di uno ed il processo resta in stato di
+ \textit{sleep} fintanto che non si ha una delle condizioni seguenti:
+ \begin{itemize*}
+ \item \var{semval} diventa zero, nel qual caso \var{semzcnt} viene
+ decrementato di uno.
+ \item l'insieme di semafori viene rimosso, nel qual caso \func{semop} ritorna
+ un errore di \errcode{EIDRM}.
+ \item il processo chiamante riceve un segnale, nel qual caso \var{semzcnt}
+ viene decrementato di uno e \func{semop} ritorna un errore di
+ \errcode{EINTR}.
+ \end{itemize*}
+ Al processo chiamante è richiesto il privilegio di lettura dell'insieme dei
+ semafori.
+
+\item[\var{sem\_op}$<0$] Nel caso in cui \var{semval} è maggiore o uguale del
+ valore assoluto di \var{sem\_op} (se cioè la somma dei due valori resta
+ positiva o nulla) i valori vengono sommati e la funzione ritorna
+ immediatamente; qualora si sia impostato \const{SEM\_UNDO} viene anche
+ aggiornato il contatore per il ripristino del valore del semaforo. In caso
+ contrario (quando cioè la somma darebbe luogo ad un valore di \var{semval}
+ negativo) se si è impostato \const{IPC\_NOWAIT} la funzione ritorna con un
+ errore di \errcode{EAGAIN}, altrimenti viene incrementato di uno
+ \var{semncnt} ed il processo resta in stato di \textit{sleep} fintanto che
+ non si ha una delle condizioni seguenti:
+ \begin{itemize*}
+ \item \var{semval} diventa maggiore o uguale del valore assoluto di
+ \var{sem\_op}, nel qual caso \var{semncnt} viene decrementato di uno, il
+ valore di \var{sem\_op} viene sommato a \var{semval}, e se era stato
+ impostato \const{SEM\_UNDO} viene aggiornato il contatore per il
+ ripristino del valore del semaforo.
+ \item l'insieme di semafori viene rimosso, nel qual caso \func{semop}
+ ritorna un errore di \errcode{EIDRM}.
+ \item il processo chiamante riceve un segnale, nel qual caso \var{semncnt}
+ viene decrementato di uno e \func{semop} ritorna un errore di
+ \errcode{EINTR}.
+ \end{itemize*}
+ Al processo chiamante è richiesto il privilegio di alterazione (scrittura)
+ sull'insieme di semafori.
+\end{basedescript}
+
+In caso di successo della funzione viene aggiornato il campo \var{sempid} per
+ogni semaforo modificato al valore del \acr{pid} del processo chiamante;
+inoltre vengono pure aggiornati al tempo corrente i campi \var{sem\_otime} e
+\var{sem\_ctime}.
+
+Dato che, come già accennato in precedenza, in caso di uscita inaspettata i
+semafori possono restare occupati, abbiamo visto come \func{semop} permetta di
+attivare un meccanismo di ripristino attraverso l'uso del flag
+\const{SEM\_UNDO}. Il meccanismo è implementato tramite una apposita struttura
+\struct{sem\_undo}, associata ad ogni processo per ciascun semaforo che esso
+ha modificato; all'uscita i semafori modificati vengono ripristinati, e le
+strutture disallocate. Per mantenere coerente il comportamento queste
+strutture non vengono ereditate attraverso una \func{fork} (altrimenti si
+avrebbe un doppio ripristino), mentre passano inalterate nell'esecuzione di
+una \func{exec} (altrimenti non si avrebbe ripristino).
+
+Tutto questo però ha un problema di fondo. Per capire di cosa si tratta
+occorre fare riferimento all'implementazione usata in Linux, che è riportata
+in maniera semplificata nello schema di \figref{fig:ipc_sem_schema}. Si è
+presa come riferimento l'architettura usata fino al kernel 2.2.x che è più
+semplice (ed illustrata in dettaglio in \cite{tlk}); nel kernel 2.4.x la
+struttura del \textit{SysV IPC} è stata modificata, ma le definizioni relative
+a queste strutture restano per compatibilità.\footnote{in particolare con le
+ vecchie versioni delle librerie del C, come le libc5.}
+
+\begin{figure}[htb]
+ \centering \includegraphics[width=15cm]{img/semtruct}
+ \caption{Schema della struttura di un insieme di semafori.}
+ \label{fig:ipc_sem_schema}
+\end{figure}
+
+Alla creazione di un nuovo insieme viene allocata una nuova strutture
+\struct{semid\_ds} ed il relativo vettore di strutture \struct{sem}. Quando si
+richiede una operazione viene anzitutto verificato che tutte le operazioni
+possono avere successo; se una di esse comporta il blocco del processo il
+kernel crea una struttura \struct{sem\_queue} che viene aggiunta in fondo alla
+coda di attesa associata a ciascun insieme di semafori\footnote{che viene
+ referenziata tramite i campi \var{sem\_pending} e \var{sem\_pending\_last}
+ di \struct{semid\_ds}.}. Nella struttura viene memorizzato il riferimento
+alle operazioni richieste (nel campo \var{sops}, che è un puntatore ad una
+struttura \struct{sembuf}) e al processo corrente (nel campo \var{sleeper}) poi
+quest'ultimo viene messo stato di attesa e viene invocato lo
+scheduler\index{scheduler} per passare all'esecuzione di un altro processo.
+
+Se invece tutte le operazioni possono avere successo queste vengono eseguite
+immediatamente, dopo di che il kernel esegue una scansione della coda di
+attesa (a partire da \var{sem\_pending}) per verificare se qualcuna delle
+operazioni sospese in precedenza può essere eseguita, nel qual caso la
+struttura \struct{sem\_queue} viene rimossa e lo stato del processo associato
+all'operazione (\var{sleeper}) viene riportato a \textit{running}; il tutto
+viene ripetuto fin quando non ci sono più operazioni eseguibili o si è
+svuotata la coda.
+
+Per gestire il meccanismo del ripristino tutte le volte che per un'operazione
+si è specificato il flag \const{SEM\_UNDO} viene mantenuta per ciascun insieme
+di semafori una apposita struttura \struct{sem\_undo} che contiene (nel vettore
+puntato dal campo \var{semadj}) un valore di aggiustamento per ogni semaforo
+cui viene sommato l'opposto del valore usato per l'operazione.
+
+Queste strutture sono mantenute in due liste,\footnote{rispettivamente
+ attraverso i due campi \var{id\_next} e \var{proc\_next}.} una associata
+all'insieme di cui fa parte il semaforo, che viene usata per invalidare le
+strutture se questo viene cancellato o per azzerarle se si è eseguita una
+operazione con \func{semctl}; l'altra associata al processo che ha eseguito
+l'operazione;\footnote{attraverso il campo \var{semundo} di
+ \struct{task\_struct}, come mostrato in \ref{fig:ipc_sem_schema}.} quando un
+processo termina, la lista ad esso associata viene scandita e le operazioni
+applicate al semaforo.
+
+Siccome un processo può accumulare delle richieste di ripristino per semafori
+differenti chiamate attraverso diverse chiamate a \func{semop}, si pone il
+problema di come eseguire il ripristino dei semafori all'uscita del processo,
+ed in particolare se questo può essere fatto atomicamente. Il punto è cosa
+succede quando una delle operazioni previste per il ripristino non può essere
+eseguita immediatamente perché ad esempio il semaforo è occupato; in tal caso
+infatti, se si pone il processo in stato di \textit{sleep} aspettando la
+disponibilità del semaforo (come faceva l'implementazione originaria) si perde
+l'atomicità dell'operazione. La scelta fatta dal kernel è pertanto quella di
+effettuare subito le operazioni che non prevedono un blocco del processo e di
+ignorare silenziosamente le altre; questo però comporta il fatto che il
+ripristino non è comunque garantito in tutte le occasioni.
+
+Come esempio di uso dell'interfaccia dei semafori vediamo come implementare
+con essa dei semplici \textit{mutex} (cioè semafori binari), tutto il codice
+in questione, contenuto nel file \file{Mutex.c} allegato ai sorgenti, è
+riportato in \figref{fig:ipc_mutex_create}. Utilizzeremo l'interfaccia per
+creare un insieme contenente un singolo semaforo, per il quale poi useremo un
+valore unitario per segnalare la disponibilità della risorsa, ed un valore
+nullo per segnalarne l'indisponibilità.
+
+\begin{figure}[!bht]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+/* Function MutexCreate: create a mutex/semaphore */
+int MutexCreate(key_t ipc_key)
+{
+ const union semun semunion={1}; /* semaphore union structure */
+ int sem_id, ret;
+ sem_id = semget(ipc_key, 1, IPC_CREAT|0666); /* get semaphore ID */
+ if (sem_id == -1) { /* if error return code */
+ return sem_id;
+ }
+ ret = semctl(sem_id, 0, SETVAL, semunion); /* init semaphore */
+ if (ret == -1) {
+ return ret;
+ }
+ return sem_id;
+}
+/* Function MutexFind: get the semaphore/mutex Id given the IPC key value */
+int MutexFind(key_t ipc_key)
+{
+ return semget(ipc_key,1,0);
+}
+/* Function MutexRead: read the current value of the mutex/semaphore */
+int MutexRead(int sem_id)
+{
+ return semctl(sem_id, 0, GETVAL);
+}
+/* Define sembuf structures to lock and unlock the semaphore */
+struct sembuf sem_lock={ /* to lock semaphore */
+ 0, /* semaphore number (only one so 0) */
+ -1, /* operation (-1 to use resource) */
+ SEM_UNDO}; /* flag (set for undo at exit) */
+struct sembuf sem_ulock={ /* to unlock semaphore */
+ 0, /* semaphore number (only one so 0) */
+ 1, /* operation (1 to release resource) */
+ SEM_UNDO}; /* flag (in this case 0) */
+/* Function MutexLock: to lock a mutex/semaphore */
+int MutexLock(int sem_id)
+{
+ return semop(sem_id, &sem_lock, 1);
+}
+/* Function MutexUnlock: to unlock a mutex/semaphore */
+int MutexUnlock(int sem_id)
+{
+ return semop(sem_id, &sem_ulock, 1);
+}
+/* Function MutexRemove: remove a mutex/semaphore */
+int MutexRemove(int sem_id)
+{
+ return semctl(sem_id, 0, IPC_RMID);
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Il codice delle funzioni che permettono di creare o recuperare
+ l'identificatore di un semaforo da utilizzare come \textit{mutex}.}
+ \label{fig:ipc_mutex_create}
+\end{figure}
+
+La prima funzione (\texttt{\small 2--15}) è \func{MutexCreate} che data una
+chiave crea il semaforo usato per il mutex e lo inizializza, restituendone
+l'identificatore. Il primo passo (\texttt{\small 6}) è chiamare \func{semget}
+con \const{IPC\_CREATE} per creare il semaforo qualora non esista,
+assegnandogli i privilegi di lettura e scrittura per tutti. In caso di errore
+(\texttt{\small 7--9}) si ritorna subito il risultato di \func{semget},
+altrimenti (\texttt{\small 10}) si inizializza il semaforo chiamando
+\func{semctl} con il comando \const{SETVAL}, utilizzando l'unione
+\struct{semunion} dichiarata ed avvalorata in precedenza (\texttt{\small 4})
+ad 1 per significare che risorsa è libera. In caso di errore (\texttt{\small
+ 11--13}) si restituisce il valore di ritorno di \func{semctl}, altrimenti
+(\texttt{\small 14}) si ritorna l'identificatore del semaforo.
+
+La seconda funzione (\texttt{\small 17--20}) è \func{MutexFind}, che, data una
+chiave, restituisce l'identificatore del semaforo ad essa associato. La
+comprensione del suo funzionamento è immediata in quanto essa è soltanto un
+\textit{wrapper}\footnote{si chiama così una funzione usata per fare da
+ \textsl{involucro} alla chiamata di un altra, usata in genere per
+ semplificare un'interfaccia (come in questo caso) o per utilizzare con la
+ stessa funzione diversi substrati (librerie, ecc.) che possono fornire le
+ stesse funzionalità.} di una chiamata a \func{semget} per cercare
+l'identificatore associato alla chiave, il valore di ritorno di quest'ultima
+viene passato all'indietro al chiamante.
+
+La terza funzione (\texttt{\small 22--25}) è \func{MutexRead} che, dato un
+identificatore, restituisce il valore del semaforo associato al mutex. Anche
+in questo caso la funzione è un \textit{wrapper} per una chiamata a
+\func{semctl} con il comando \const{GETVAL}, che permette di restituire il
+valore del semaforo.
+
+La quarta e la quinta funzione (\texttt{\small 36--44}) sono \func{MutexLock},
+e \func{MutexUnlock}, che permettono rispettivamente di bloccare e sbloccare
+il mutex. Entrambe fanno da wrapper per \func{semop}, utilizzando le due
+strutture \var{sem\_lock} e \var{sem\_unlock} definite in precedenza
+(\texttt{\small 27--34}). Si noti come per queste ultime si sia fatto uso
+dell'opzione \const{SEM\_UNDO} per evitare che il semaforo resti bloccato in
+caso di terminazione imprevista del processo.
+
+L'ultima funzione (\texttt{\small 46--49}) della serie, è \func{MutexRemove},
+che rimuove il mutex. Anche in questo caso si ha un wrapper per una chiamata a
+\func{semctl} con il comando \const{IPC\_RMID}, che permette di cancellare il
+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 \secref{sec:ipc_lock_file} come sia possibile ottenere
+un'interfaccia analoga a quella appena illustrata, senza incorrere in questi
+problemi, usando il file locking\index{file!locking}.
+
+
+\subsection{Memoria condivisa}
+\label{sec:ipc_sysv_shm}
+
+Il terzo oggetto introdotto dal \textit{SysV IPC} è quello dei segmenti di
+memoria condivisa. La funzione che permette di ottenerne uno è \funcd{shmget},
+ed il suo prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{sys/ipc.h}
+ \headdecl{sys/shm.h}
+
+ \funcdecl{int shmget(key\_t key, int size, int flag)}
+
+ Restituisce l'identificatore di una memoria condivisa.
+
+ \bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
+ in caso di errore, nel qual caso \var{errno} assumerà i valori:
+ \begin{errlist}
+ \item[\errcode{ENOSPC}] Si è superato il limite (\const{SHMMNI}) sul numero
+ di segmenti di memoria nel sistema, o cercato di allocare un segmento le
+ cui dimensioni fanno superare il limite di sistema (\const{SHMALL}) per
+ la memoria ad essi riservata.
+ \item[\errcode{EINVAL}] Si è richiesta una dimensione per un nuovo segmento
+ maggiore di \const{SHMMAX} o minore di \const{SHMMIN}, o se il segmento
+ già esiste \param{size} è maggiore delle sue dimensioni.
+ \item[\errcode{ENOMEM}] Il sistema non ha abbastanza memoria per poter
+ contenere le strutture per un nuovo segmento di memoria condivisa.
+ \end{errlist}
+ ed inoltre \errval{EACCES}, \errval{ENOENT}, \errval{EEXIST},
+ \errval{EIDRM}, con lo stesso significato che hanno per \func{msgget}.}
+\end{functions}
+
+La funzione, come \func{semget}, è del tutto analoga a \func{msgget}, ed
+identico è l'uso degli argomenti \param{key} e \param{flag} per cui non
+ripeteremo quanto detto al proposito in \secref{sec:ipc_sysv_mq}. L'argomento
+\param{size} specifica invece la dimensione, in byte, del segmento, che viene
+comunque arrotondata al multiplo superiore di \const{PAGE\_SIZE}.
+
+La memoria condivisa è la forma più veloce di comunicazione fra due processi,
+in quanto permette agli stessi di vedere nel loro spazio di indirizzi una
+stessa sezione di memoria. Pertanto non è necessaria nessuna operazione di
+copia per trasmettere i dati da un processo all'altro, in quanto ciascuno può
+accedervi direttamente con le normali operazioni di lettura e scrittura dei
+dati in memoria.
+
+Ovviamente tutto questo ha un prezzo, ed il problema fondamentale della
+memoria condivisa è la sincronizzazione degli accessi. È evidente infatti che
+se un processo deve scambiare dei dati con un altro, si deve essere sicuri che
+quest'ultimo non acceda al segmento di memoria condivisa prima che il primo
+non abbia completato le operazioni di scrittura, inoltre nel corso di una
+lettura si deve essere sicuri che i dati restano coerenti e non vengono
+sovrascritti da un accesso in scrittura sullo stesso segmento da parte di un
+altro processo. Per questo in genere la memoria condivisa viene sempre
+utilizzata in abbinamento ad un meccanismo di sincronizzazione, il che, di
+norma, significa insieme a dei semafori.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}
+struct shmid_ds {
+ struct ipc_perm shm_perm; /* operation perms */
+ int shm_segsz; /* size of segment (bytes) */
+ time_t shm_atime; /* last attach time */
+ time_t shm_dtime; /* last detach time */
+ time_t shm_ctime; /* last change time */
+ unsigned short shm_cpid; /* pid of creator */
+ unsigned short shm_lpid; /* pid of last operator */
+ short shm_nattch; /* no. of current attaches */
+};
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \structd{shmid\_ds}, associata a ciascun segmento di
+ memoria condivisa.}
+ \label{fig:ipc_shmid_ds}
+\end{figure}
+
+A ciascun segmento di memoria condivisa è associata una struttura
+\struct{shmid\_ds}, riportata in \figref{fig:ipc_shmid_ds}. Come nel caso
+delle code di messaggi quando si crea un nuovo segmento di memoria condivisa
+con \func{shmget} questa struttura viene inizializzata, in particolare il
+campo \var{shm\_perm} viene inizializzato come illustrato in
+\secref{sec:ipc_sysv_access_control}, e valgono le considerazioni ivi fatte
+relativamente ai permessi di accesso; per quanto riguarda gli altri campi
+invece:
+\begin{itemize*}
+\item il campo \var{shm\_segsz}, che esprime la dimensione del segmento, viene
+ inizializzato al valore di \param{size}.
+\item il campo \var{shm\_ctime}, che esprime il tempo di creazione del
+ segmento, viene inizializzato al tempo corrente.
+\item i campi \var{shm\_atime} e \var{shm\_dtime}, che esprimono
+ rispettivamente il tempo dell'ultima volta che il segmento è stato
+ agganciato o sganciato da un processo, vengono inizializzati a zero.
+\item il campo \var{shm\_lpid}, che esprime il \acr{pid} del processo che ha
+ eseguito l'ultima operazione, viene inizializzato a zero.
+\item il campo \var{shm\_cpid}, che esprime il \acr{pid} del processo che ha
+ creato il segmento, viene inizializzato al \acr{pid} del processo chiamante.
+\item il campo \var{shm\_nattac}, che esprime il numero di processi agganciati
+ al segmento viene inizializzato a zero.
+\end{itemize*}
+
+Come per le code di messaggi e gli insiemi di semafori, anche per i segmenti
+di memoria condivisa esistono una serie di limiti imposti dal sistema. Alcuni
+di questi limiti sono al solito accessibili e modificabili attraverso
+\func{sysctl} o scrivendo direttamente nei rispettivi file di
+\file{/proc/sys/kernel/}.
+
+In \tabref{tab:ipc_shm_limits} si sono riportate le
+costanti simboliche associate a ciascuno di essi, il loro significato, i
+valori preimpostati, e, quando presente, il file in \file{/proc/sys/kernel/}
+che permettono di cambiarne il valore.
+
+
+\begin{table}[htb]
+ \footnotesize
+ \centering
+ \begin{tabular}[c]{|c|r|c|p{7cm}|}
+ \hline
+ \textbf{Costante} & \textbf{Valore} & \textbf{File in \texttt{proc}}
+ & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{SHMALL}& 0x200000&\file{shmall}& Numero massimo di pagine che
+ possono essere usate per i segmenti di
+ memoria condivisa. \\
+ \const{SHMMAX}&0x2000000&\file{shmmax}& Dimensione massima di un segmento
+ di memoria condivisa.\\
+ \const{SHMMNI}& 4096&\file{msgmni}& Numero massimo di segmenti di
+ memoria condivisa presenti nel
+ kernel.\\
+ \const{SHMMIN}& 1& --- & Dimensione minima di un segmento di
+ memoria condivisa. \\
+ \const{SHMLBA}&\const{PAGE\_SIZE}&--- & Limite inferiore per le dimensioni
+ minime di un segmento (deve essere
+ allineato alle dimensioni di una
+ pagina di memoria). \\
+ \const{SHMSEG}& --- & --- & Numero massimo di segmenti di
+ memoria condivisa
+ per ciascun processo.\\
+
+
+ \hline
+ \end{tabular}
+ \caption{Valori delle costanti associate ai limiti dei segmenti di memoria
+ condivisa, insieme al relativo file in \file{/proc/sys/kernel/} ed al
+ valore preimpostato presente nel sistema.}
+ \label{tab:ipc_shm_limits}
+\end{table}
+
+Al solito la funzione che permette di effettuare le operazioni di controllo su
+un segmento di memoria condivisa è \funcd{shmctl}; il suo prototipo è:
+\begin{functions}
+ \headdecl{sys/ipc.h}
+ \headdecl{sys/shm.h}
+
+ \funcdecl{int shmctl(int shmid, int cmd, struct shmid\_ds *buf)}
+
+ Esegue le operazioni di controllo su un segmento di memoria condivisa.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+ errore, nel qual caso \var{errno} assumerà i valori:
+ \begin{errlist}
+ \item[\errcode{EACCES}] Si è richiesto \const{IPC\_STAT} ma i permessi non
+ consentono l'accesso in lettura al segmento.
+ \item[\errcode{EINVAL}] O \param{shmid} 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{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
+ \secref{sec:proc_mem_lock}.} sul segmento di memoria condivisa. Solo
+ l'amministratore può utilizzare questo comando.
+\item[\const{SHM\_UNLOCK}] Disabilita il \textit{memory locking} sul segmento
+ di memoria condivisa. Solo l'amministratore può utilizzare questo comando.
+\end{basedescript}
+i primi tre comandi sono gli stessi già visti anche per le code 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
+\figref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si
+ricordi quanto illustrato al proposito in \secref{sec:proc_mem_layout}). In
+particolare l'indirizzo finale del segmento dati (quello impostato da
+\func{brk}, vedi \secref{sec:proc_mem_sbrk}) non viene influenzato. Si tenga
+presente infine che la funzione ha successo anche se il segmento è stato
+marcato per la cancellazione.
+
+\begin{figure}[htb]
+ \centering
+ \includegraphics[height=10cm]{img/sh_memory_layout}
+ \caption{Disposizione dei segmenti di memoria di un processo quando si è
+ agganciato un segmento di memoria condivisa.}
+ \label{fig:ipc_shmem_layout}
+\end{figure}
+
+L'argomento \param{shmaddr} specifica a quale indirizzo\footnote{Lo standard
+ SVID prevede che l'argomento \param{shmaddr} sia di tipo \ctyp{char *}, così
+ come il valore di ritorno della funzione. In Linux è stato così con le
+ \acr{libc4} e le \acr{libc5}, con il passaggio alle \acr{glibc} il tipo di
+ \param{shmaddr} è divenuto un \ctyp{const void *} e quello del valore di
+ ritorno un \ctyp{void *}.} deve essere associato il segmento, se il valore
+specificato è \val{NULL} è il sistema a scegliere opportunamente un'area di
+memoria libera (questo è il modo più portabile e sicuro di usare la funzione).
+Altrimenti il kernel aggancia il segmento all'indirizzo specificato da
+\param{shmaddr}; questo però può avvenire solo se l'indirizzo coincide con il
+limite di una pagina, cioè se è un multiplo esatto del parametro di sistema
+\const{SHMLBA}, che in Linux è sempre uguale \const{PAGE\_SIZE}.
+
+Si tenga presente però che quando si usa \val{NULL} come valore di
+\param{shmaddr}, l'indirizzo restituito da \func{shmat} può cambiare da
+processo a processo; pertanto se nell'area di memoria condivisa si salvano
+anche degli indirizzi, si deve avere cura di usare valori relativi (in genere
+riferiti all'indirizzo di partenza del segmento).
+
+L'argomento \param{shmflg} permette di cambiare il comportamento della
+funzione; esso va specificato come maschera binaria, i bit utilizzati sono
+solo due e sono identificati dalle costanti \const{SHM\_RND} e
+\const{SHM\_RDONLY}, che vanno combinate con un OR aritmetico. Specificando
+\const{SHM\_RND} si evita che \func{shmat} ritorni un errore quando
+\param{shmaddr} non è allineato ai confini di una pagina. Si può quindi usare
+un valore qualunque per \param{shmaddr}, e il segmento verrà comunque
+agganciato, ma al più vicino multiplo di \const{SHMLBA} (il nome della
+costante sta infatti per \textit{rounded}, e serve per specificare un
+indirizzo come arrotondamento, in Linux è equivalente a \const{PAGE\_SIZE}).
+
+L'uso di \const{SHM\_RDONLY} permette di agganciare il segmento in sola
+lettura (si ricordi che anche le pagine di memoria hanno dei permessi), in tal
+caso un tentativo di scrivere sul segmento comporterà una violazione di
+accesso con l'emissione di un segnale di \const{SIGSEGV}. Il comportamento
+usuale di \func{shmat} è quello di agganciare il segmento con l'accesso in
+lettura e scrittura (ed il processo deve aver questi permessi in
+\var{shm\_perm}), non è prevista la possibilità di agganciare un segmento in
+sola scrittura.
+
+In caso di successo la funzione aggiorna anche i seguenti campi di
+\struct{shmid\_ds}:
+\begin{itemize*}
+\item il tempo \var{shm\_atime} dell'ultima operazione di aggancio viene
+ impostato al tempo corrente.
+\item il \acr{pid} \var{shm\_lpid} dell'ultimo processo che ha operato sul
+ segmento viene impostato a quello del processo corrente.
+\item il numero \var{shm\_nattch} di processi agganciati al segmento viene
+ aumentato di uno.
+\end{itemize*}
+
+Come accennato in \secref{sec:proc_fork} un segmento di memoria condivisa
+agganciato ad un processo viene ereditato da un figlio attraverso una
+\func{fork}, dato che quest'ultimo riceve una copia dello spazio degli
+indirizzi del padre. Invece, dato che attraverso una \func{exec} viene
+eseguito un diverso programma con uno spazio di indirizzi completamente
+diverso, tutti i segmenti agganciati al processo originario vengono
+automaticamente sganciati. Lo stesso avviene all'uscita del processo
+attraverso una \func{exit}.
+
+Una volta che un segmento di memoria condivisa non serve più, si può
+sganciarlo esplicitamente dal processo usando l'altra funzione
+dell'interfaccia, \funcd{shmdt}, il cui prototipo è:
+\begin{functions}
+ \headdecl{sys/types.h}
+ \headdecl{sys/shm.h}
+
+ \funcdecl{int shmdt(const void *shmaddr)}
+ Sgancia dal processo un segmento di memoria condivisa.
+
+ \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
+ errore, la funzione fallisce solo quando non c'è un segmento agganciato
+ all'indirizzo \func{shmaddr}, con \var{errno} che assume il valore
+ \errval{EINVAL}.}
+\end{functions}
+
+La funzione sgancia dallo spazio degli indirizzi del processo un segmento di
+memoria condivisa; questo viene identificato con l'indirizzo \param{shmaddr}
+restituito dalla precedente chiamata a \func{shmat} con il quale era stato
+agganciato al processo.
+
+In caso di successo la funzione aggiorna anche i seguenti campi di
+\struct{shmid\_ds}:
+\begin{itemize*}
+\item il tempo \var{shm\_dtime} dell'ultima operazione di sganciamento viene
+ impostato al tempo corrente.
+\item il \acr{pid} \var{shm\_lpid} dell'ultimo processo che ha operato sul
+ segmento viene impostato a quello del processo corrente.
+\item il numero \var{shm\_nattch} di processi agganciati al segmento viene
+ decrementato di uno.
+\end{itemize*}
+inoltre la regione di indirizzi usata per il segmento di memoria condivisa
+viene tolta dallo spazio di indirizzi del processo.
+
+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
+\figref{fig:ipc_sysv_shm_func}.
+
+\begin{figure}[!bht]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+/* Function ShmCreate Create a SysV shared memory segment */
+void * ShmCreate(key_t ipc_key, int shm_size, int perm, int fill)
+{
+ void * shm_ptr;
+ int shm_id; /* ID of the IPC shared memory segment */
+ shm_id = shmget(ipc_key, shm_size, IPC_CREAT|perm); /* get shm ID */
+ if (shm_id < 0) {
+ return NULL;
+ }
+ shm_ptr = shmat(shm_id, NULL, 0); /* map it into memory */
+ if (shm_ptr < 0) {
+ return NULL;
+ }
+ memset((void *)shm_ptr, fill, shm_size); /* fill segment */
+ return shm_ptr;
+}
+/* Function ShmFind: Find a SysV shared memory segment */
+void * ShmFind(key_t ipc_key, int shm_size)
+{
+ void * shm_ptr;
+ int shm_id; /* ID of the SysV shared memory segment */
+ shm_id = shmget(ipc_key, shm_size, 0); /* find shared memory ID */
+ if (shm_id < 0) {
+ return NULL;
+ }
+ shm_ptr = shmat(shm_id, NULL, 0); /* map it into memory */
+ if (shm_ptr < 0) {
+ return NULL;
+ }
+ return shm_ptr;
+}
+/* Function ShmRemove: Schedule removal for a SysV shared memory segment */
+int ShmRemove(key_t ipc_key, void * shm_ptr)
+{
+ int shm_id; /* ID of the SysV shared memory segment */
+ /* first detach segment */
+ if (shmdt(shm_ptr) < 0) {
+ return -1;
+ }
+ /* schedule segment removal */
+ shm_id = shmget(ipc_key, 0, 0); /* find shared memory ID */
+ if (shm_id < 0) {
+ if (errno == EIDRM) return 0;
+ return -1;
+ }
+ if (shmctl(shm_id, IPC_RMID, NULL) < 0) { /* ask for removal */
+ if (errno == EIDRM) return 0;
+ return -1;
+ }
+ return 0;
+}
+ \end{lstlisting}
+ \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}
+
+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 \secref{sec:ipc_sysv_mq} per la
+ comunicazione non sequenziale si possono usare le code di messaggi,
+ attraverso l'uso del campo \var{mtype}, ma solo se quest'ultima può essere
+ effettuata in forma di messaggio.} o quando non può avvenire secondo una
+modalità predefinita.
+
+Un esempio classico di uso della memoria condivisa è quello del
+``\textit{monitor}'', in cui viene per scambiare informazioni fra un processo
+server, che vi scrive dei dati di interesse generale che ha ottenuto, e i
+processi client interessati agli stessi dati che così possono leggerli in
+maniera completamente asincrona. Con questo schema di funzionamento da una
+parte si evita che ciascun processo client debba compiere l'operazione,
+potenzialmente onerosa, di ricavare e trattare i dati, e dall'altra si evita
+al processo server di dover gestire l'invio a tutti i client di tutti i dati
+(non potendo il server sapere quali di essi servono effettivamente al singolo
+client).
+
+Nel nostro caso implementeremo un ``\textsl{monitor}'' di una directory: un
+processo si incaricherà di tenere sotto controllo alcuni parametri relativi ad
+una directory (il numero dei file contenuti, la dimensione totale, quante
+directory, link simbolici, file normali, ecc.) che saranno salvati in un
+segmento di memoria condivisa cui altri processi potranno accedere per
+ricavare la parte di informazione che interessa.
+
+In \figref{fig:ipc_dirmonitor_main} si è riportata la sezione principale del
+corpo del programma server, insieme alle definizioni delle altre funzioni
+usate nel programma e delle variabili globali, omettendo tutto quello che
+riguarda la gestione delle opzioni e la stampa delle istruzioni di uso a
+video; al solito il codice completo si trova con i sorgenti allegati nel file
+\file{DirMonitor.c}.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+/* global variables for shared memory segment */
+struct DirProp {
+ int tot_size;
+ int tot_files;
+ int tot_regular;
+ int tot_fifo;
+ int tot_link;
+ int tot_dir;
+ int tot_block;
+ int tot_char;
+ int tot_sock;
+} *shmptr;
+key_t key;
+int mutex;
+/* main body */
+int main(int argc, char *argv[])
+{
+ int i, pause = 10;
+ ...
+ if ((argc - optind) != 1) { /* There must be remaing parameters */
+ printf("Wrong number of arguments %d\n", argc - optind);
+ usage();
+ }
+ if (chdir(argv[1])) { /* chdir to be sure dir exist */
+ perror("Cannot find directory to monitor");
+ }
+ Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
+ Signal(SIGINT, HandSIGTERM);
+ Signal(SIGQUIT, HandSIGTERM);
+ key = ftok("~/gapil/sources/DirMonitor.c", 1); /* define a key */
+ shmptr = ShmCreate(key, 4096, 0666, 0); /* get a shared memory segment */
+ if (!shmptr) {
+ perror("Cannot create shared memory");
+ exit(1);
+ }
+ if ((mutex = MutexCreate(key)) == -1) { /* get a Mutex */
+ perror("Cannot create mutex");
+ exit(1);
+ }
+ /* main loop, monitor directory properties each 10 sec */
+ daemon(1, 0); /* demonize process, staying in monitored dir */
+ while (1) {
+ MutexLock(mutex); /* lock shared memory */
+ memset(shmptr, 0, sizeof(struct DirProp)); /* erase previous data */
+ DirScan(argv[1], ComputeValues); /* execute scan */
+ MutexUnlock(mutex); /* unlock shared memory */
+ sleep(pause); /* sleep until next watch */
+ }
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Codice della funzione principale del programma \file{DirMonitor.c}.}
+ \label{fig:ipc_dirmonitor_main}
+\end{figure}
+
+Il programma usa delle variabili globali (\texttt{\small 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 \secref{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 \secref{sec:ipc_sysv_sem}, anche un mutex, che
+utilizzeremo per regolare l'accesso alla memoria condivisa.
+
+Completata l'inizializzazione e la creazione degli oggetti di
+intercomunicazione il programma entra nel ciclo principale (\texttt{\small
+ 40--49}) dove vengono eseguite indefinitamente le attività di monitoraggio.
+Il primo passo (\texttt{\small 41}) è eseguire \func{daemon} per proseguire
+con l'esecuzione in background come si conviene ad un programma demone; si
+noti che si è mantenuta, usando un valore non nullo del primo argomento, la
+directory di lavoro corrente. Una volta che il programma è andato in
+background l'esecuzione prosegue (\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}.
+
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+/* Routine to compute directory properties inside DirScan */
+int ComputeValues(struct dirent * direntry)
+{
+ struct stat data;
+ stat(direntry->d_name, &data); /* get stat data */
+ shmptr->tot_size += data.st_size;
+ shmptr->tot_files++;
+ if (S_ISREG(data.st_mode)) shmptr->tot_regular++;
+ if (S_ISFIFO(data.st_mode)) shmptr->tot_fifo++;
+ if (S_ISLNK(data.st_mode)) shmptr->tot_link++;
+ if (S_ISDIR(data.st_mode)) shmptr->tot_dir++;
+ if (S_ISBLK(data.st_mode)) shmptr->tot_block++;
+ if (S_ISCHR(data.st_mode)) shmptr->tot_char++;
+ if (S_ISSOCK(data.st_mode)) shmptr->tot_sock++;
+ return 0;
+}
+/* Signal Handler to manage termination */
+void HandSIGTERM(int signo) {
+ MutexLock(mutex);
+ ShmRemove(key, shmptr);
+ MutexRemove(mutex);
+ exit(0);
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Codice delle funzione ausiliarie usate da \file{DirMonitor.c}.}
+ \label{fig:ipc_dirmonitor_sub}
+\end{figure}
+
+Si noti come per il calcolo dei valori da mantenere nella memoria condivisa si
+sia usata ancora una volta la funzione \func{DirScan}, già utilizzata (e
+descritta in dettaglio) in \secref{sec:file_dir_read}, che ci permette di
+effettuare la scansione delle voci della directory, chiamando per ciascuna di
+esse la funzione \func{ComputeValues}, che esegue tutti i calcoli necessari.
+
+Il codice di quest'ultima è riportato in \figref{fig:ipc_dirmonitor_sub}. Come
+si vede la funzione (\texttt{\small 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
+\tabref{tab:file_type_macro}, si contano (\texttt{\small 8--14}) quanti ce ne
+sono per ciascun tipo.
+
+In \figref{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]{15cm}
+ \begin{lstlisting}{}
+int main(int argc, char *argv[])
+{
+ key_t key;
+ ...
+ /* create needed IPC objects */
+ key = ftok("~/gapil/sources/DirMonitor.c", 1); /* define a key */
+ if (!(shmptr = ShmFind(key, 4096))) { /* get a shared memory segment */
+ perror("Cannot find shared memory");
+ exit(1);
+ }
+ if ((mutex = MutexFind(key)) == -1) { /* get the Mutex */
+ perror("Cannot find mutex");
+ exit(1);
+ }
+ /* main loop */
+ MutexLock(mutex); /* lock shared memory */
+ printf("Ci sono %d file dati\n", shmptr->tot_regular);
+ printf("Ci sono %d directory\n", shmptr->tot_dir);
+ printf("Ci sono %d link\n", shmptr->tot_link);
+ printf("Ci sono %d fifo\n", shmptr->tot_fifo);
+ printf("Ci sono %d socket\n", shmptr->tot_sock);
+ printf("Ci sono %d device a caratteri\n", shmptr->tot_char);
+ printf("Ci sono %d device a blocchi\n", shmptr->tot_block);
+ printf("Totale %d file, per %d byte\n",
+ shmptr->tot_files, shmptr->tot_size);
+ MutexUnlock(mutex); /* unlock shared memory */
+}
+ \end{lstlisting}
+ \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 \figref{fig:ipc_dirmonitor_client}. Al solito si è
+omessa la sezione di gestione delle opzioni e la funzione che stampa a video
+le istruzioni; il codice completo è nei sorgenti allegati, nel file
+\file{ReadMonitor.c}.
+
+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
+%% \figref{fig:ipc_shm_struct}.
+
+%% \begin{figure}[htb]
+%% \centering
+%% \includegraphics[width=10cm]{img/shmstruct}
+%% \caption{Schema dell'implementazione dei segmenti di memoria condivisa in
+%% Linux.}
+%% \label{fig:ipc_shm_struct}
+%% \end{figure}
+
+
+
+
+\section{Tecniche alternative}
+\label{sec:ipc_alternatives}
+
+Come abbiamo detto in \secref{sec:ipc_sysv_generic}, e ripreso nella
+descrizione dei singoli oggetti che ne fan parte, il \textit{SysV IPC}
+presenta numerosi problemi; in \cite{APUE}\footnote{in particolare nel
+ capitolo 14.} Stevens ne effettua una accurata analisi (alcuni dei concetti
+sono già stati accennati in precedenza) ed elenca alcune possibili tecniche
+alternative, che vogliamo riprendere in questa sezione.
+
+
+\subsection{Alternative alle code di messaggi}
+\label{sec:ipc_mq_alternative}
+
+Le code di messaggi sono probabilmente il meno usato degli oggetti del
+\textit{SysV IPC}; esse infatti nacquero principalmente come meccanismo di
+comunicazione bidirezionale quando ancora le pipe erano unidirezionali; con la
+disponibilità di \func{socketpair} (vedi \secref{sec:ipc_socketpair}) o
+utilizzando una coppia di pipe, si può ottenere questo risultato senza
+incorrere nelle complicazioni introdotte dal \textit{SysV IPC}.
+
+In realtà, grazie alla presenza del campo \var{mtype}, le code di messaggi
+hanno delle caratteristiche ulteriori, consentendo una classificazione dei
+messaggi ed un accesso non rigidamente sequenziale; due caratteristiche che
+sono impossibili da ottenere con le pipe e i socket\index{socket} di
+\func{socketpair}. A queste esigenze però si può comunque ovviare in maniera
+diversa con un uso combinato della memoria condivisa e dei meccanismi di
+sincronizzazione, per cui alla fine l'uso delle code di messaggi classiche è
+relativamente poco diffuso.
+
+\subsection{I \textsl{file di lock}}
+\label{sec:ipc_file_lock}
+
+\index{file!di lock|(}
+Come illustrato in \secref{sec:ipc_sysv_sem} i semafori del \textit{SysV IPC}
+presentano una interfaccia inutilmente complessa e con alcuni difetti
+strutturali, per questo quando si ha una semplice esigenza di sincronizzazione
+per la quale basterebbe un semaforo binario (quello che abbiamo definito come
+\textit{mutex}), per indicare la disponibilità o meno di una risorsa, senza la
+necessità di un contatore come i semafori, si possono utilizzare metodi
+alternativi.
+
+La prima possibilità, utilizzata fin dalle origini di Unix, è quella di usare
+dei \textsl{file di lock} (per i quali esiste anche una opportuna directory,
+\file{/var/lock}, nel filesystem standard). Per questo si usa la
+caratteristica della funzione \func{open} (illustrata in
+\secref{sec:file_open}) che prevede\footnote{questo è quanto dettato dallo
+ standard POSIX.1, ciò non toglie che in alcune implementazioni questa
+ tecnica possa non funzionare; in particolare per Linux, nel caso di NFS, si
+ è comunque soggetti alla possibilità di una race
+ condition\index{race condition}.} che essa ritorni un errore quando usata
+con i flag di \const{O\_CREAT} e \const{O\_EXCL}. In tal modo la creazione di
+un \textsl{file di lock} può essere eseguita atomicamente, il processo che
+crea il file con successo si può considerare come titolare del lock (e della
+risorsa ad esso associata) mentre il rilascio si può eseguire con una chiamata
+ad \func{unlink}.
+
+Un esempio dell'uso di questa funzione è mostrato dalle funzioni
+\func{LockFile} ed \func{UnlockFile} riportate in \figref{fig:ipc_file_lock}
+(sono contenute in \file{LockFile.c}, un'altro dei sorgenti allegati alla
+guida) che permettono rispettivamente di creare e rimuovere un \textsl{file di
+ lock}. Come si può notare entrambe le funzioni sono elementari; la prima
+(\texttt{\small 4--10}) si limita ad aprire il file di lock (\texttt{\small
+ 9}) nella modalità descritta, mentre la seconda (\texttt{\small 11--17}) lo
+cancella con \func{unlink}.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h> /* unix standard functions */
+/*
+ * Function LockFile:
+ */
+int LockFile(const char* path_name)
+{
+ return open(path_name, O_EXCL|O_CREAT);
+}
+/*
+ * Function UnlockFile:
+ */
+int UnlockFile(const char* path_name)
+{
+ return unlink(path_name);
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Il codice delle funzioni \func{LockFile} e \func{UnlockFile} che
+ permettono di creare e rimuovere un \textsl{file di lock}.}
+ \label{fig:ipc_file_lock}
+\end{figure}
+
+Uno dei limiti di questa tecnica è che, come abbiamo già accennato in
+\secref{sec:file_open}, questo comportamento di \func{open} può non funzionare
+(la funzione viene eseguita, ma non è garantita l'atomicità dell'operazione)
+se il filesystem su cui si va ad operare è su NFS; in tal caso si può adottare
+una tecnica alternativa che prevede l'uso della \func{link} per creare come
+\textsl{file di lock} un hard link ad un file esistente; se il link esiste già
+e la funzione fallisce, significa che la risorsa è bloccata e potrà essere
+sbloccata solo con un \func{unlink}, altrimenti il link è creato ed il lock
+acquisito; il controllo e l'eventuale acquisizione sono atomici; la soluzione
+funziona anche su NFS, ma ha un'altro difetto è che è quello di poterla usare
+solo se si opera all'interno di uno stesso filesystem.
+
+Un generale comunque l'uso di un \textsl{file di lock} presenta parecchi
+problemi, che non lo rendono una alternativa praticabile per la
+sincronizzazione: anzitutto in caso di terminazione imprevista del processo,
+si lascia allocata la risorsa (il \textsl{file di lock}) e questa deve essere
+sempre cancellata esplicitamente. Inoltre il controllo della disponibilità
+può essere eseguito solo con una tecnica di \textit{polling}\index{polling},
+ed è quindi molto inefficiente.
+
+La tecnica dei file di lock ha comunque una sua utilità, e può essere usata
+con successo quando l'esigenza è solo quella di segnalare l'occupazione di una
+risorsa, senza necessità di attendere che questa si liberi; ad esempio la si
+usa spesso per evitare interferenze sull'uso delle porte seriali da parte di
+più programmi: qualora si trovi un file di lock il programma che cerca di
+accedere alla seriale si limita a segnalare che la risorsa non è
+disponibile.\index{file!di lock|)}
+
+
+\subsection{La sincronizzazione con il \textit{file locking}}
+\label{sec:ipc_lock_file}
+
+Dato che i file di lock\index{file!di lock} presentano gli inconvenienti
+illustrati in precedenza, la tecnica alternativa di sincronizzazione più
+comune è quella di fare ricorso al \textit{file locking}\index{file!locking}
+(trattato in \secref{sec:file_locking}) usando \func{fcntl} su un file creato
+per l'occasione per ottenere un write lock. In questo modo potremo usare il
+lock come un \textit{mutex}: per bloccare la risorsa basterà acquisire il
+lock, per sbloccarla basterà rilasciare il lock. Una richiesta fatta con un
+write lock metterà automaticamente il processo in stato di attesa, senza
+necessità di ricorrere al \textit{polling}\index{polling} per determinare la
+disponibilità della risorsa, e al rilascio della stessa da parte del processo
+che la occupava si otterrà il nuovo lock atomicamente.
+
+Questo approccio presenta il notevole vantaggio che alla terminazione di un
+processo tutti i lock acquisiti vengono rilasciati automaticamente (alla
+chiusura dei relativi file) e non ci si deve preoccupare di niente; inoltre
+non consuma risorse permanentemente allocate nel sistema. Lo svantaggio è che,
+dovendo fare ricorso a delle operazioni sul filesystem, esso è in genere
+leggermente più lento.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+/* Function CreateMutex: Create a mutex using file locking. */
+int CreateMutex(const char *path_name)
+{
+ return open(path_name, O_EXCL|O_CREAT);
+}
+/* Function UnlockMutex: unlock a file. */
+int FindMutex(const char *path_name)
+{
+ return open(path_name, O_RDWR);
+}
+/* Function LockMutex: lock mutex using file locking. */
+int LockMutex(int fd)
+{
+ struct flock lock; /* file lock structure */
+ /* set flock structure */
+ lock.l_type = F_WRLCK; /* set type: read or write */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = 0; /* set the start of the locked region */
+ lock.l_len = 0; /* set the length of the locked region */
+ /* do locking */
+ return fcntl(fd, F_SETLKW, &lock);
+}
+/* Function UnlockMutex: unlock a file. */
+int UnlockMutex(int fd)
+{
+ struct flock lock; /* file lock structure */
+ /* set flock structure */
+ lock.l_type = F_UNLCK; /* set type: unlock */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = 0; /* set the start of the locked region */
+ lock.l_len = 0; /* set the length of the locked region */
+ /* do locking */
+ return fcntl(fd, F_SETLK, &lock);
+}
+/* Function RemoveMutex: remove a mutex (unlinking the lock file). */
+int RemoveMutex(const char *path_name)
+{
+ return unlink(path_name);
+}
+/* Function ReadMutex: read a mutex status. */
+int ReadMutex(int fd)
+{
+ int res;
+ struct flock lock; /* file lock structure */
+ /* set flock structure */
+ lock.l_type = F_WRLCK; /* set type: unlock */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = 0; /* set the start of the locked region */
+ lock.l_len = 0; /* set the length of the locked region */
+ /* do locking */
+ if ( (res = fcntl(fd, F_GETLK, &lock)) ) {
+ return res;
+ }
+ return lock.l_type;
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Il codice delle funzioni che permettono per la gestione dei
+ \textit{mutex} con il file locking\index{file!locking}.}
+ \label{fig:ipc_flock_mutex}
+\end{figure}
+
+Il codice delle varie funzioni usate per implementare un mutex utilizzando il
+file locking\index{file!locking} è riportato in \figref{fig:ipc_flock_mutex};
+si è mantenuta volutamente una struttura analoga alle precedenti funzioni che
+usano i semafori, anche se le due interfacce non possono essere completamente
+equivalenti, specie per quanto riguarda la rimozione del mutex.
+
+La prima funzione (\texttt{\small 1--5}) è \func{CreateMutex}, e serve a
+creare il mutex; la funzione è estremamente semplice, 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 \secref{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
+\secref{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 \secref{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
+\secref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete.
+
+
+
+\section{La comunicazione fra processi di POSIX}
+\label{sec:ipc_posix}
+
+Per superare i numerosi problemi del \textit{SysV IPC}, evidenziati per i suoi
+aspetti generali in coda a \secref{sec:ipc_sysv_generic} e per i singoli
+oggetti nei paragrafi successivi, lo standard POSIX.1b ha introdotto dei nuovi
+meccanismi di comunicazione, che vanno sotto il nome di POSIX IPC, definendo
+una interfaccia completamente nuova, che tratteremo in questa sezione.
+
+
+\subsection{Considerazioni generali}
+\label{sec:ipc_posix_generic}
+
+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{Posix IPC names}, che sono sostanzialmente
+equivalenti ai nomi dei file. Tutte le funzioni che creano un oggetto di IPC
+Posix prendono come primo argomento una stringa che indica uno di questi nomi;
+lo standard è molto generico riguardo l'implementazione, ed i nomi stessi
+possono avere o meno una corrispondenza sul filesystem; tutto quello che è
+richiesto è che:
+\begin{itemize}
+\item i nomi devono essere conformi alle regole che caratterizzano i
+ \textit{pathname}, in particolare non essere più lunghi di \const{PATH\_MAX}
+ byte e terminati da un carattere nullo.
+\item se il nome inizia per una \texttt{/} chiamate differenti allo stesso
+ nome fanno riferimento allo stesso oggetto, altrimenti l'interpretazione del
+ nome dipende dall'implementazione.
+\item l'interpretazione di ulteriori \texttt{/} presenti nel nome dipende
+ dall'implementazione.
+\end{itemize}
+
+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 \secref{sec:ipc_posix_shm} e \secref{sec:ipc_posix_mq})
+ed i nomi specificati nelle relative funzioni sono considerati come un
+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 \secref{sec:file_access_control}), invece di
+quella particolare (si ricordi quanto visto in
+\secref{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/\~{}wrona/posix\_ipc}.}.
+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.}
+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
+\tabref{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
+\figref{fig:ipc_mq_attr}.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}[labelstep=0]{}
+struct mq_attr {
+ long mq_flags; /* message queue flags */
+ long mq_maxmsg; /* maximum number of messages */
+ long mq_msgsize; /* maximum message size */
+ long mq_curmsgs; /* number of messages currently queued */
+};
+ \end{lstlisting}
+ \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 \figref{fig:file_sigevent}) introdotta dallo
+standard POSIX.1b per gestire la notifica di eventi; per altri dettagli si può
+vedere quanto detto in \secref{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
+\figref{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 \secref{sec:sig_real_time} a proposito dei segnali
+ real-time.} posto che questo sia installato nella forma estesa vista in
+\secref{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
+\figref{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 \secref{sec:sig_sigaction} e \secref{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 \secref{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 \secref{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
+\tabref{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 \secref{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
+\secref{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]{15cm}
+ \begin{lstlisting}{}
+/* Function CreateShm: Create a shared memory segment mapping it */
+void * CreateShm(char * shm_name, off_t shm_size, mode_t perm, int fill)
+{
+ void * shm_ptr;
+ int fd;
+ int flag;
+ /* first open the object, creating it if not existent */
+ flag = O_CREAT|O_EXCL|O_RDWR;
+ fd = shm_open(shm_name, flag, perm); /* get object file descriptor */
+ if (fd < 0) {
+ return NULL;
+ }
+ /* set the object size */
+ if (ftruncate(fd, shm_size)) {
+ return NULL;
+ }
+ /* map it in the process address space */
+ shm_ptr = mmap(NULL, shm_size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
+ if (shm_ptr == MAP_FAILED) {
+ return NULL;
+ }
+ memset((void *) shm_ptr, fill, shm_size); /* fill segment */
+ return shm_ptr;
+}
+/* Function FindShm: Find a POSIX shared memory segment */
+void * FindShm(char * shm_name, off_t shm_size)
+{
+ void * shm_ptr;
+ int fd; /* ID of the IPC shared memory segment */
+ /* find shared memory ID */
+ if ((fd = shm_open(shm_name, O_RDWR|O_EXCL, 0)) < 0) {
+ return NULL;
+ }
+ /* take the pointer to it */
+ shm_ptr = mmap(NULL, shm_size, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
+ if (shm_ptr == MAP_FAILED) {
+ return NULL;
+ }
+ return shm_ptr;
+}
+/* Function RemoveShm: Remove a POSIX shared memory segment */
+int RemoveShm(char * shm_name)
+{
+ return shm_unlink(shm_name);
+}
+ \end{lstlisting}
+ \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
+\secref{fig:ipc_sysv_shm_func} per la memoria condivisa in stile SysV. Il
+codice, riportato in \figref{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.