Ancora message queues
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index 78d612f91270dfb2a6e799ec7fd49f9d6df66c44..029284fb19b426022a8a2c6e5ae18b5c72e971cf 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -3785,13 +3785,9 @@ una interfaccia completamente nuova, che tratteremo in questa sezione.
 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, e sono utilizzabili
-solo all'interno dei thread generati dallo stesso processo,\footnote{sono cioè
-  oggetti che non possono, al contrario dei semafori del SysV IPC, essere
-  utilizzati per sincronizzare processi diversi.} le code di messaggi non
-hanno alcun tipo di supporto ufficiale.  Esistono tuttavia dei patch e delle
-librerie aggiuntive che supportano alcune di queste interfacce, anche se
-sperimentali e di uso limitato.
+\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
@@ -3799,34 +3795,194 @@ degli identificatori e delle chiavi visti nel SysV IPC, per passare ai
 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. 
-
-
- le caratteristiche di questi nomi,
-per i quali richiede che:
+possono avere o meno una corrispondenza sul filesystem; tutto quello che è
+richiesto è che:
 \begin{itemize}
-\item debbano essere conformi alle regole che caratterizzano i
+\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{/} 
+\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, in assenza di una implementazione
-uffiale, ne tralasciamo la descrizione.
+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.
+
+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 è \func{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{prototype}
 
+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
+  \errval{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.
+
+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
+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}.
+
+\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}
+
+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.
 
 
 \subsection{Semafori}
@@ -3834,9 +3990,14 @@ uffiale, ne tralasciamo la descrizione.
 
 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.
 
 
 
@@ -3845,7 +4006,34 @@ POSIX usando i semafori di SysV IPC.
 \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: