Messa pure mq_notify
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index 029284fb19b426022a8a2c6e5ae18b5c72e971cf..de0823f17fe51dc909b681e6eeec760bed399641 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -3879,9 +3879,8 @@ filesystem.
 
 
 La funzione che permette di aprire (e crearla se non esiste ancora) una coda
-di messaggi POSIX è \func{mq\_open}, ed il suo prototipo è:
+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)}
@@ -3908,7 +3907,7 @@ di messaggi POSIX 
     \end{errlist}
     ed inoltre \errval{ENOMEM}, \errval{ENOSPC}, \errval{EFAULT},
     \errval{EMFILE} ed \errval{ENFILE}.}
-\end{prototype}
+\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
@@ -3939,23 +3938,24 @@ seguenti:
 \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
-  \errval{EAGAIN}.
+  \errcode{EAGAIN}.
 \end{basedescript}
 
 I primi tre bit specificano la modalità di apertura della coda, e sono fra
-loro esclusivi; qualunque sia la modalità in cui si è aperta una coda, questa
-potrà essere riaperta più volte in una modalità diversa, e vi si potrà
-accedere attraverso descrittori diversi, esattamente come si può fare per i
-file normali.
+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 si deve specificare \const{O\_CREAT} per creare una
-nuova, in tal caso come accennato occorre anche specificare i permessi di
+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 della coda tramite l'argomento
-\param{attr} che è il puntatore ad una struttura \struct{mq\_attr}, la cui
-definizione è riportata in \figref{fig:ipc_mq_attr}.
+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
@@ -3975,14 +3975,261 @@ struct mq_attr {
   \label{fig:ipc_mq_attr}
 \end{figure}
 
-Quando si crea la coda possono essere specificati solo i campi
-\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 \errval{EINVAL}.  Qualora si specifichi per
-\param{attr} un puntatore nullo gli attributi della coda saranno impostati ai
-valori predefiniti.
+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}    
+    \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 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.
+
+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}.
+
+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}.
+
+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 è:
+\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}, il meccanismo è disponibile per un solo processo
+alla volta per ogni 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.
+
+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.
+
+
 
 
 \subsection{Semafori}