Avanti sulle message queues
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index fcf702ab2fe399f8dcd48667b01e863edd9a0256..b5e7981f69c17cfbb835dccc66e431d374ec811c 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -50,7 +50,7 @@ Crea una coppia di file descriptor associati ad una \textit{pipe}.
     \macro{ENFILE} e \macro{EFAULT}.}
 \end{prototype}
 
-La funzione restituisce la coppia di file descriptor nell'array
+La funzione restituisce la coppia di file descriptor nel vettore
 \param{filedes}; il primo è aperto in lettura ed il secondo in scrittura. Come
 accennato concetto di funzionamento di una pipe è semplice: quello che si
 scrive nel file descriptor aperto in scrittura viene ripresentato tale e quale
@@ -376,7 +376,7 @@ originarie del codice a barre e produce un JPEG di dimensioni corrette.
 Questo approccio però non funziona, per via di una delle caratteristiche
 principali delle pipe. Per poter effettuare la conversione di un PDF infatti è
 necessario, per la struttura del formato, potersi spostare (con \func{lseek})
-all'interno del file da convertire; se si eseguela conversione con \cmd{gs} su
+all'interno del file da convertire; se si esegue la conversione con \cmd{gs} su
 un file regolare non ci sono problemi, una pipe però è rigidamente
 sequenziale, e l'uso di \func{lseek} su di essa fallisce sempre con un errore
 di \macro{ESPIPE}, rendendo impossibile la conversione.  Questo ci dice che in
@@ -517,7 +517,7 @@ apertura (bloccante e non bloccante); questo pu
 comunque una fifo in scrittura anche se non ci sono ancora processi il
 lettura; è possibile anche usare la fifo all'interno di un solo processo, nel
 qual caso però occorre stare molto attenti alla possibili
-deadlock.\footnote{se si cerca di leggere da una fifo che non contiene dati si
+situazioni di stallo.\footnote{se si cerca di leggere da una fifo che non contiene dati si
   avrà un deadlock immediato, dato che il processo si blocca e non potrà
   quindi mai eseguire le funzioni di scrittura.}
 
@@ -694,7 +694,7 @@ Per questo motivo, dopo aver eseguito l'apertura in lettura (\texttt{\small
   lettura in attesa di una richiesta.} si esegue una seconda apertura in
 scrittura (\texttt{\small 29--32}), scartando il relativo file descriptor che
 non sarà mai usato, ma lasciando la fifo comunque aperta anche in scrittura,
-cosicchè le successive possano bloccarsi.
+cosicché le successive possano bloccarsi.
 
 A questo punto si può entrare nel ciclo principale del programma che fornisce
 le risposte ai client (\texttt{\small 34--50}), che viene eseguito
@@ -707,7 +707,7 @@ Per cui prima (\texttt{\small 35--39}) si esegue la lettura dalla stringa di
 richiesta dalla fifo nota (che a questo punto si bloccherà tutte le volte che
 non ci sono richieste). Dopo di che, una volta terminata la stringa
 (\texttt{\small 40}) e selezionato (\texttt{\small 41}) un numero casuale per
-ricavare la frase da invaire, si procederà (\texttt{\small 42--46})
+ricavare la frase da inviare, si procederà (\texttt{\small 42--46})
 all'apertura della fifo per la risposta, che \texttt{\small 47--48}) poi vi
 sarà scritta. Infine (\texttt{\small 49}) si chiude la fifo di risposta che
 non serve più. 
@@ -772,8 +772,8 @@ del processo per essere sicuri di avere un nome univoco; dopo di che
 (\texttt{\small 13-18}) si procede alla creazione del relativo file, uscendo
 in caso di errore (a meno che il file non sia già presente sul filesystem).
 
-A questo punto il client può effettuare l'interrogazione del server, pe questo
-prima si apre la fifo nota (\texttt{\small 19--23}), e poi ci si scrive
+A questo punto il client può effettuare l'interrogazione del server, per
+questo prima si apre la fifo nota (\texttt{\small 19--23}), e poi ci si scrive
 (\texttt{\small 24}) la stringa composta in precedenza, che contiene il nome
 della fifo da utilizzare per la risposta. Infine si richiude la fifo del
 server che a questo punto non serve più (\texttt{\small 25}).
@@ -845,7 +845,7 @@ utilizzando, con tutte le conseguenze (negative) del caso.
 Gli oggetti usati nel System V IPC vengono creati direttamente dal kernel, e
 sono accessibili solo specificando il relativo \textsl{identificatore}. Questo
 è un numero progressivo (un po' come il \acr{pid} dei processi) che il kernel
-assegna a ciascuno di essi quanto vengono creati (sul prodedimento di
+assegna a ciascuno di essi quanto vengono creati (sul procedimento di
 assegnazione torneremo in \secref{sec:ipc_sysv_id_use}). L'identificatore
 viene restituito dalle funzioni che creano l'oggetto, ed è quindi locale al
 processo che le ha eseguite. Dato che l'identificatore viene assegnato
@@ -886,13 +886,13 @@ associato ad un oggetto ed accedervi. Il problema che sorge a questo punto 
 come devono fare per accordarsi sull'uso di una stessa chiave. Se i processi
 sono \textsl{parenti} la soluzione è relativamente semplice, in tal caso
 infatti si può usare il valore speciale \texttt{IPC\_PRIVATE} per creare un
-nuovo oggetto nel processo padre, l'idenficatore così ottenuto sarà
+nuovo oggetto nel processo padre, l'identificatore così ottenuto sarà
 disponibile in tutti i figli, e potrà essere passato come parametro attraverso
 una \func{exec}.
 
 Però quando i processi non sono \textsl{parenti} (come capita tutte le volte
 che si ha a che fare con un sistema client-server) tutto questo non è
-possibile; si potebbe comunque salvare l'identificatore su un file noto, ma
+possibile; si potrebbe comunque salvare l'identificatore su un file noto, ma
 questo ovviamente comporta lo svantaggio di doverselo andare a rileggere.  Una
 alternativa più efficace è quella che i programmi usino un valore comune per
 la chiave (che ad esempio può essere dichiarato in un header comune), ma c'è
@@ -927,15 +927,15 @@ Il problema 
 sia univoco, infatti esso è costruito combinando il byte di \param{proj\_id)}
 con i 16 bit meno significativi dell'inode del file \param{pathname} (che
 vengono ottenuti attraverso \func{stat}, da cui derivano i possibili errori),
-e gli 8 bit meno significativi del numero del device su cui è il file. Diventa
-perciò relativamente facile ottenere delle collisioni, specie se i file sono
-su dispositivi con lo stesso \textit{minor number}, come \file{/dev/hda1} e
-\file{/dev/sda1}.
+e gli 8 bit meno significativi del numero del dispositivo su cui è il file.
+Diventa perciò relativamente facile ottenere delle collisioni, specie se i
+file sono su dispositivi con lo stesso \textit{minor number}, come
+\file{/dev/hda1} e \file{/dev/sda1}.
 
 In genere quello che si fa è utilizzare un file comune usato dai programmi che
 devono comunicare (ad esempio un haeder comune, o uno dei programmi che devono
-usare l'oggetto in questione), utilizzando il numero di progetto per ottere le
-chiavi che interessano. In ogni caso occorre sempre controllare, prima di
+usare l'oggetto in questione), utilizzando il numero di progetto per ottenere
+le chiavi che interessano. In ogni caso occorre sempre controllare, prima di
 creare un oggetto, che la chiave non sia già stata utilizzata. Se questo va
 bene in fase di creazione, le cose possono complicarsi per i programmi che
 devono solo accedere, in quanto, a parte gli eventuali controlli sugli altri
@@ -997,7 +997,7 @@ Il secondo livello di controllo 
 direttamente (in lettura o scrittura) all'oggetto. In tal caso lo schema dei
 controlli è simile a quello dei file, ed avviene secondo questa sequenza:
 \begin{itemize}
-\item se il processo ha i privilegi di amministatore l'accesso è sempre
+\item se il processo ha i privilegi di amministratore l'accesso è sempre
   consentito. 
 \item se l'userid effettivo del processo corrisponde o al valore del campo
   \var{cuid} o a quello del campo \var{uid} ed il permesso per il proprietario
@@ -1028,10 +1028,10 @@ identificatori degli oggetti del sistema di IPC.
 
 Quando il sistema si avvia, alla creazione di ogni nuovo oggetto di IPC viene
 assegnato un numero progressivo, pari al numero di oggetti di quel tipo
-esistenti. Se il comportamente fosse sempre questo sarebbe identico a quello
+esistenti. Se il comportamento fosse sempre questo sarebbe identico a quello
 usato nell'assegnazione dei file descriptor nei processi, ed i valori degli
 identificatori tenderebbero ad essere riutilizzati spesso e restare di piccole
-dimensioni (inferiori al numero massimo di oggetti diponibili).
+dimensioni (inferiori al numero massimo di oggetti disponibili).
 
 Questo va benissimo nel caso dei file descriptor, che sono locali ad un
 processo, ma qui il comportamento varrebbe per tutto il sistema, e per
@@ -1168,7 +1168,7 @@ una 
     in caso di errore, nel qual caso \var{errno} viene settato ad uno dei
     valori: 
   \begin{errlist}
-  \item[\macro{EACCES}] Il processo chiamante non ha i provilegi per accedere
+  \item[\macro{EACCES}] Il processo chiamante non ha i privilegi per accedere
   alla coda richiesta.  
   \item[\macro{EEXIST}] Si è richiesta la creazione di una coda che già
   esiste, ma erano specificati sia \macro{IPC\_CREAT} che \macro{IPC\_EXCL}. 
@@ -1207,30 +1207,157 @@ Se si imposta anche il bit corrispondente a \macro{IPC\_EXCL} la funzione avr
 successo solo se l'oggetto non esiste già, fallendo con un errore di
 \macro{EEXIST} altrimenti.
 
-Una coda di messaggi è costituita da una \textit{linked list}\footnote{una
+Si tenga conto che l'uso di \macro{IPC\_PRIVATE} non impedisce ad altri
+processi di accedere alla coda (se hanno privilegi sufficienti) una volta che
+questi possano indovinare o ricavare (ad esempio per tentativi)
+l'identificatore ad essa associato. Per come sono implementati gli oggetti di
+IPC infatti non esiste una maniera che  garantisca l'accesso esclusivo ad una
+coda di messaggi.  Usare \macro{IPC\_PRIVATE} o macro{IPC\_CREAT} e
+\macro{IPC\_EXCL} per \param{flag} comporta solo la creazione di una nuova
+coda.
+
+\begin{table}[htb]
+  \footnotesize
+  \centering
+  \begin{tabular}[c]{|c|r|l|l|}
+    \hline
+    \textbf{Costante} & \textbf{Valore} & \textbf{File in \texttt{proc}}
+    & \textbf{Significato} \\
+    \hline
+    \hline
+    \macro{MSGMNI}&   16& \file{msgmni} & Numero massimo di code di
+                                          messaggi. \\
+    \macro{MSGMAX}& 8192& \file{msgmax} & Dimensione massima di un singolo
+                                          messaggio.\\
+    \macro{MSGMNB}&16384& \file{msgmnb} & Dimensione massima di una coda di 
+                                          messaggi.\\
+    \hline
+  \end{tabular}
+  \caption{Valori delle costanti associati ai limiti delle code di messaggi.}
+  \label{tab:ipc_msg_limits}
+\end{table}
+
+Le code di messaggi sono caratterizzate da tre limiti fondamentali, definiti
+negli header e corrispondenti alle prime tre costanti riportate in
+\tabref{tab:ipc_msg_limits}, come accennato però in Linux è possibile
+modificare questi limiti attraverso l'uso di \func{syscntl} o scrivendo nei
+file \file{msgmax}, \file{msgmnb} e \file{msgmni} di \file{/proc/sys/kernel/}.
+
+
+\begin{figure}[htb]
+  \centering \includegraphics[width=15cm]{img/mqstruct}
+  \caption{Schema della struttura di una coda messaggi.}
+  \label{fig:ipc_mq_schema}
+\end{figure}
+
+
+Una coda di messaggi è costituita da una \textit{linked list};\footnote{una
   \textit{linked list} è una tipica struttura di dati, organizzati in una
   lista in cui ciascun elemento contiene un puntatore al successivo. In questo
   modo la struttura è veloce nell'estrazione ed immissione dei dati dalle
   estremità dalla lista (basta aggiungere un elemento in testa o in coda ed
   aggiornare un puntatore), e relativamente veloce da attraversare in ordine
   sequenziale (seguendo i puntatori), è invece relativamente lenta
-  nell'accesso casuale e nella ricerca.} in cui nuovi messaggi vengono
-inseriti in coda per poi essere letti dalla cima, con una struttura del tipo
-di quella illustrata in 
+  nell'accesso casuale e nella ricerca.}  i nuovi messaggi vengono inseriti in
+coda alla lista e vengono letti dalla cima, in \figref{fig:ipc_mq_schema} si è
+riportato lo schema con cui queste strutture vengono mantenute dal
+kernel.\footnote{lo schema illustrato in figura è in realtà una semplificazione
+  di quanto usato fino ai kernel della serie 2.2.x, nei kernel della serie
+  2.4.x la gestione è effettuata in maniera diversa; ma esso illustra comunque
+  in maniera adeguata i principi di funzionamento delle code di messaggi.}
 
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \begin{lstlisting}[labelstep=0]{}
+struct msqid_ds {
+    struct ipc_perm msg_perm;     /* structure for operation permission */
+    time_t msg_stime;             /* time of last msgsnd command */
+    time_t msg_rtime;             /* time of last msgrcv command */
+    time_t msg_ctime;             /* time of last change */
+    unsigned long int msg_cbytes; /* current number of bytes on queue */
+    msgqnum_t msg_qnum;           /* number of messages currently on queue */
+    msglen_t msg_qbytes;          /* max number of bytes allowed on queue */
+    pid_t msg_lspid;              /* pid of last msgsnd() */
+    pid_t msg_lrpid;              /* pid of last msgrcv() */
+    struct msg *msg_first;        /* first message on queue, unused  */
+    struct msg *msg_last;         /* last message in queue, unused */
+};
+    \end{lstlisting}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \var{msgid\_ds}, associata a ciascuna coda di
+    messaggi. Si sono riportati i campi significativi definiti in
+    \file{sys/msg.h}, aggiungendo anche due campi interni, non visibili in
+    user space.}
+  \label{fig:ipc_msgid_sd}
+\end{figure}
 
-Si tenga conto che l'uso di \macro{IPC\_PRIVATE} non impedisce ad altri
-processi di accedere alla coda (se hanno privilegi sufficienti) una volta che
-questi possano indovinare o ricavare l'identificatore ad essa associato. Per
-la loro implementazione non esiste cioè una maniera che garantisca l'accesso
-esclusivo ad una coda di messaggi. Usare \macro{IPC\_PRIVATE} o
-macro{IPC\_CREAT} e \macro{IPC\_EXCL} per \param{flag} comporta solo la
-creazione di una nuova coda. 
-
-Le code di messaggi sono caratterizzate da tre limiti 
+A ciascuna coda è associata una struttura \var{msgid\_ds}, la cui definizione
+è riportata in \secref{fig:ipc_msgid_sd}, il significato dei vari campi è
+riportato nella figura. In questa struttura il kernel\footnote{come accennato
+  questo vale fino ai kernel della serie 2.2.x, essa viene usata nei kernel
+  della serie 2.4.x solo per compatibilità in quanto è quella restituita dalle
+  funzioni dell'interfaccia.}  mantiene le principali informazioni riguardo lo
+stato corrente della coda. Quando si crea una nuova coda con \func{msgget}
+questa struttura viene inizializzata, in particolare il campo \var{msg\_perm}
+viene inizializzato come illustrato in \secref{sec:ipc_sysv_access_control},
+per quanto riguarda gli altri campi invece:
+\begin{itemize}
+\item i campi \var{msg\_qnum}, \var{msg\_lspid}, \var{msg\_lrpid},
+  \var{msg\_stime}, \var{msg\_rtime} sono inizializzati a 0
+\item il campo \var{msg\_ctime} viene settato al tempo corrente
+\item il campo \var{msg\_qbytes} al limite di sistema.
+\item i campi \var{msg\_first} e  \var{msg\_last} (che non vengono visti in
+  user space) sono inizializzati a \macro{NULL} essendo la coda vuota.
+\end{itemize}
 
-Una volta creata una coda di messaggi se ne può controllare 
+Una volta creata una coda di messaggi le operazioni di controllo vengono
+effettuate con la funzione \func{msgctl}, che (come le analoghe \func{semctl}
+e \func{shmctl}) fa le veci di quello che \func{ioctl} è per i file; il suo
+prototipo è:
+\begin{functions}
+  \headdecl{sys/types.h} 
+  \headdecl{sys/ipc.h} 
+  \headdecl{sys/msg.h} 
+  
+  \funcdecl{int msgctl(int msqid, int cmd, struct msqid\_ds *buf)}
+  
+  Esegue l'operazione specificata da \param{cmd} sulla coda \param{msqid}.
+  
+  \bodydesc{La funzione restituisce 0 in caso di successo o -1 in caso di
+    errore, nel qual caso \var{errno} viene settato a:
+  \begin{errlist}
+  \item[\macro{EACCES}] Si è richiesto \macro{IPC\_STAT} ma processo chiamante
+    non ha i privilegi di lettura sulla coda.
+  \item[\macro{EIDRM}] La coda richiesta è marcata per essere cancellata.
+  \item[\macro{EPERM}] Si è richiesto \macro{IPC\_SET} o \macro{IPC\_RMID} ma
+    il processo non ha i privilegi, o si è richiesto di aumentare il valore di
+    \var{msg\_qbytes} oltre il limite \macro{MSGMNB} senza essere
+    amministratore.
+  \end{errlist}
+  ed inoltre \macro{EFAULT} ed \macro{EINVAL}.
+}
+\end{functions}
 
+La funzione permette di accedere ai valori della struttura \var{msqid\_ds},
+mantenuta all'indirizzo \param{buf}, per la coda specificata
+dall'identificatore \param{msqid}. Il comportamento della funzione dipende dal
+valore dell'argomento \param{cmd}, che specifica il tipo di azione da
+eseguire; i valori possibili sono:
+\begin{basedescript}{\desclabelwidth{3cm}\desclabelstyle{\nextlinelabel}}
+\item[\macro{IPC\_STAT}] Legge le informazioni riguardo la coda nella
+  struttura indicata da \param{buf}. Occorre avere il permesso di lettura
+  sulla coda.
+\item[\macro{IPC\_RMID}] Rimuove la coda, cancellando tutti i dati, con
+  effetto immediato. Tutti i processi che cercheranno di accedere alla coda
+  riceveranno un errore di \macro{EIDRM}, e tutti processi in attesa su
+  funzioni di di lettura o di scrittura sulla coda saranno svegliati ricevendo
+  il medesimo errore. Questo comando può essere eseguito solo da un processo
+  con userid effettivo corrispondente al creatore a o al proprietario della
+  coda, o all'amministratore.
+\item[\macro{IPC\_SET}]
+\end{basedescript}
 
 
 \subsection{Semafori}
@@ -1257,7 +1384,7 @@ risorse condivise. La funzione che permette di ottenere un insieme di semafori
 La funzione è del tutto analoga a \func{msgget} ed identico è l'uso degli
 argomenti \param{key} e \param{flag}, per cui non ripeteremo quanto detto al
 proposito in \secref{sec:ipc_sysv_mq}. L'argomento \param{nsems} permette di
-specificare quanti semfori deve contenere l'insieme qualora se ne richieda la
+specificare quanti semafori deve contenere l'insieme qualora se ne richieda la
 creazione, e deve essere nullo quando si effettua una richiesta
 dell'identificatore di un insieme già esistente.