X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=5f3b5af947d766bd91e0bf8f15394248bbf19387;hp=ba47d11cd3007013384d2da885d37c6d54038121;hb=3fce8d71dc08554143eaf3613f27289337950ef2;hpb=fbedaeae01259c00f725deed1ae724a013ab531d diff --git a/ipc.tex b/ipc.tex index ba47d11..5f3b5af 100644 --- 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,6 +4192,79 @@ differenza fra le due funzioni 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 questo problema. + +Una caratteristica specifica delle code di messaggi POSIX è infatti 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. Inoltre il campo \var{sigev\_value} (la cui definizione è +riportata in \figref{fig:sig_sigval}) permette di restituire al gestore del +segnale un valore numerico o un indirizzo. + +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 (e quindi anche all'uscita +del processo) ogni eventuale registrazione di notifica presente viene +cancellata. + +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. + +L'invio del segnale avvalora i campi seguenti campi di \struct{siginfo\_t} (la +cui definizione è in \figref{fig:sig_siginfo_t}): \var{si\_pid} con il +\acr{pid} del processo che ha emesso il segnale, \var{si\_uid} con l'userid +effettivo, \var{si\_code} con \const{SI\_MESGQ}, e \var{si\_errno} a 0. Questo +ci dice che, se si effettua la ricezione 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 (si ricordi +quanto già detto al proposito in \secref{sec:sig_sigaction} e +\secref{sec:sig_real_time}). + \subsection{Semafori}