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 de0823f17fe51dc909b681e6eeec760bed399641..9676970e57dcf5372c91c85d63d8ff00e8ada585 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -3847,12 +3847,14 @@ processo che esegue la creazione).
 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 \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.
+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
@@ -4010,7 +4012,7 @@ 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)}
+{int mq\_unlink(const char *name)}
 
 Rimuove una coda di messaggi.
   
@@ -4132,11 +4134,12 @@ 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\_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)}
+    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}.
   
@@ -4153,25 +4156,34 @@ prototipi sono:
     \item[\errcode{ETIMEDOUT}] La ricezione del messaggio non è stata
       effettuata entro il tempo stabilito.
     \end{errlist}    
-    \errval{EBADF}, \errval{EINTR}, \errval{ENOMEM}, o \errval{EINVAL}.}
+    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
+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 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 chiamare sempre \func{mq\_getaddr} prima
-di eseguire una ricezione, per allocare per i messaggi dei buffer di
-dimensione opportuna.
+ritorno.
 
-Se si specifica un valore non nullo per l'argomento \param{msg\_prio} il
-valore della priorità del messaggio viene memorizzato all'indirizzo da esso
-puntato. Si noti che con le code di messaggi POSIX non si ha la possibilità di
-selezionare quale messaggio estrarre in base alla priorità, a differenza di
-quanto avveniva con le code di messaggi di SysV che permettono la selezione in
-base al valore del campo \var{mtype}.
+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
@@ -4180,9 +4192,18 @@ differenza fra le due funzioni 
 passato il tempo massimo \param{abs\_timeout} ritorna comunque con un errore
 di \errcode{ETIMEDOUT}.
 
-Un'altra 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 è:
+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)}
 
@@ -4200,35 +4221,69 @@ Attiva il meccanismo di notifica per la coda \param{mqdes}.
 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}, il meccanismo è disponibile per un solo processo
-alla volta per ogni coda.
+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 struttura \struct{sigevent}
-(la cui definizione è in \figref{fig:file_sigevent}) che abbiamo già
-incontrato in \secref{sec:file_asyncronous_io}.  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.
+\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.
-
-La notifica avviene all'arrivo di un messaggio in una coda vuota (e non se ci
-sono messaggi sulla coda), in tal caso il segnale specificato da
-\code{notification->sigev\_signo} viene inviato al processo che si era
-registrato, e la coda diventa disponibile per una ulteriore registrazione. Si
-tenga presente però che la presenza di un processo bloccato in una chiamata a
-\func{mq\_receive} ha la precedenza sulla notifica; in tal caso infatti un
-enventuale messaggio viene immediatamente inviato a quest'ultimo, e per il
-meccanismo di notifica funziona tutto come se la coda fosse restata vuota.
-
+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}.}
 
 
 
@@ -4246,6 +4301,15 @@ 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.
+