Finita parte sulle code di messaggi POSIX, iniziato a scrivere qualcosa sui
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index e1863eebaca9fd8d9a66ea967ede33b61285be6b..9676970e57dcf5372c91c85d63d8ff00e8ada585 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -3764,8 +3764,8 @@ il \textit{memory mapping} anonimo.\footnote{nei sistemi derivati da SysV una
   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 il monitor visto in \secref{sec:ipc_sysv_shm}
-in modo che possa restituire i suoi risultati anche via rete.
+più avanti, quando realizzeremo una nuova versione del monitor visto in
+\secref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete.
 
 
 
@@ -3779,29 +3779,511 @@ meccanismi di comunicazione, che vanno sotto il nome di POSIX IPC, definendo
 una interfaccia completamente nuova, che tratteremo in questa sezione.
 
 
-
 \subsection{Considerazioni generali}
 \label{sec:ipc_posix_generic}
 
-Il Linux non tutti gli oggetti del POSIX IPC sono supportati nel kernel
-ufficiale; solo la memoria condivisa è presente, ma solo a partire dal kernel
-2.4.x, per gli altri oggetti esistono patch e librerie non ufficiali.
-Nonostante questo è importante esaminare questa interfaccia per la sua netta
-superiorità nei confronti di quella del \textit{SysV IPC}.
+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 per
+quanto riguarda la memoria condivisa, tutto viene creato nella directory
+\file{/dev/shm}, ed i nomi sono presi come pathname assoluto (comprendente
+eventuali sottodirectory) rispetto a questa radice (per maggiori dettagli si
+veda quanto illustrato in \secref{sec:ipc_posix_shm}). Lo stesso accade per
+l'implementazione sperimentale delle code di messaggi, che però fa riferimento
+alla directory \file{/dev/mqueue}.
+
+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 è vero nel caso di Linux, che usa
+  una implementazione che lo consente, non è detto che altrettanto valga per
+  altri kernel. In particolare per la memoria condivisa, come si può
+  facilmente evincere con uno \cmd{strace}, le system call utilizzate sono le
+  stesse, in quanto essa è realizzata con file in uno speciale 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;\footnote{esiste però una proposta di implementazione di Krzysztof
-  Benedyczak, a partire dal kernel 2.5.50.}  inoltre esse possono essere
-implementate, usando la memoria condivisa ed i mutex, con funzioni di
-libreria. In generale, come le corrispettive del SysV IPC, sono poco usate,
-dato che i socket\index{socket}, nei casi in cui sono sufficienti, sono più
-comodi, e negli altri casi la comunicazione può essere gestita direttamente
-con mutex e memoria condivisa. Per questo ci limiteremo ad una descrizione
-essenziale.
+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}.}
 
 
 
@@ -3810,16 +4292,59 @@ essenziale.
 
 Dei semafori POSIX esistono sostanzialmente due implementazioni; una è fatta a
 livello di libreria ed è fornita dalla libreria dei thread; questa però li
-implementa solo a livello di thread e non di processi. Esiste un'altra
-versione, realizzata da Konstantin Knizhnik, che reimplementa l'interfaccia
-POSIX usando i semafori di SysV IPC. 
+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. 
+kernel ufficiale. Per poterla utilizzare occorre abilitare 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 (viene usato anche per la SysV shared memory). In più i suoi
+  contenuti, essendo trattati direttamente dalla memoria
+  virtuale\index{memoria virtuale} e possono essere salvati sullo swap
+  automaticamente.} abilitando l'opzione \texttt{CONFIG\_TMPFS} in fase di
+compilazione del kernel, e montando il filesystem aggiungendo una riga tipo:
+\begin{verbatim}
+tmpfs   /dev/shm        tmpfs   defaults        0      0
+\end{verbatim}
+ad \file{/etc/fstab}, oppure dove si preferisce con un comando del
+tipo:\footnote{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}.}
+\begin{verbatim}
+mount -t tmpfs -o size=10G,nr_inodes=10k,mode=700 tmpfs /mytmpfs
+\end{verbatim}
+
+
+ la memoria
+condivisa è trattata come un filesystem separato, con tutte le caratteristiche
+di un qualunque filesystem,
 
 
 %%% Local Variables: