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 inviare, si procederà (\texttt{\small
- 42--46}) all'apertura della \textit{fifo} per la risposta, che poi
-\texttt{\small 47--48}) vi sarà scritta. Infine (\texttt{\small 49}) si chiude
-la \textit{fifo} di risposta che non serve più.
+ 42--46}) all'apertura della \textit{fifo} per la risposta, che poi
+(\texttt{\small 47--48}) vi sarà scritta. Infine (\texttt{\small 49}) si
+chiude la \textit{fifo} di risposta che non serve più.
Il codice del client è invece riportato in fig.~\ref{fig:ipc_fifo_client},
anche in questo caso si è omessa la gestione delle opzioni e la funzione che
\var{msg\_qbytes} oltre il limite \const{MSGMNB} senza essere
amministratore.
\end{errlist}
- ed inoltre \errval{EFAULT} ed \errval{EINVAL} nel loro significato
+ ed inoltre \errval{EFAULT} ed \errval{EINVAL} nel loro significato
generico.}
\end{funcproto}
successivo potrebbe ricevere un messaggio non indirizzato a lui.
-
\subsection{I semafori}
\label{sec:ipc_sysv_sem}
effettuata, viene inizializzato a zero.
\end{itemize*}
-
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{.80\textwidth}
\param{semid} o sul singolo semaforo di un insieme, specificato da
\param{semnum}.
-
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{.80\textwidth}
+ \begin{minipage}[c]{0.80\textwidth}
\includestruct{listati/semun.h}
\end{minipage}
\normalsize
Infine \var{sem\_op} è il campo che controlla qual'è l'operazione che viene
eseguita e determina in generale il comportamento della chiamata a
\func{semop}. I casi possibili per il valore di questo campo sono tre:
-\begin{basedescript}{\desclabelwidth{2.0cm}}
+\begin{basedescript}{\desclabelwidth{1.8cm}}
\item[\var{sem\_op} $>0$] In questo caso il valore viene aggiunto al valore
corrente di \var{semval} per il semaforo indicato. Questa operazione non
causa mai un blocco del processo, ed eventualmente \func{semop} ritorna
versioni delle librerie del C, come le \acr{libc5}).
\begin{figure}[!htb]
- \centering \includegraphics[width=13cm]{img/semtruct}
+ \centering \includegraphics[width=12cm]{img/semtruct}
\caption{Schema della struttura di un insieme di semafori.}
\label{fig:ipc_sem_schema}
\end{figure}
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{\textwidth}
+ \begin{minipage}[c]{0.80\textwidth}
\includestruct{listati/shmid_ds.h}
\end{minipage}
\normalsize
sez.~\ref{sec:ipc_sysv_access_control}, e valgono le considerazioni ivi fatte
relativamente ai permessi di accesso; per quanto riguarda gli altri campi
invece:
-\begin{itemize}
+\begin{itemize*}
\item il campo \var{shm\_segsz}, che esprime la dimensione del segmento, viene
inizializzato al valore di \param{size}.
\item il campo \var{shm\_ctime}, che esprime il tempo di creazione del
creato il segmento, viene inizializzato al \ids{PID} del processo chiamante.
\item il campo \var{shm\_nattac}, che esprime il numero di processi agganciati
al segmento viene inizializzato a zero.
-\end{itemize}
+\end{itemize*}
Come per le code di messaggi e gli insiemi di semafori, anche per i segmenti
di memoria condivisa esistono una serie di limiti imposti dal sistema. Alcuni
per \param{shmaddr} o il valore \val{NULL} indicando \const{SHM\_REMAP}.
\end{errlist}
ed inoltre \errval{ENOMEM} nel suo significato generico.
-
}
\end{funcproto}
In caso di successo la funzione \func{shmat} aggiorna anche i seguenti campi
della struttura \struct{shmid\_ds}:
-\begin{itemize}
+\begin{itemize*}
\item il tempo \var{shm\_atime} dell'ultima operazione di aggancio viene
impostato al tempo corrente.
\item il \ids{PID} \var{shm\_lpid} dell'ultimo processo che ha operato sul
segmento viene impostato a quello del processo corrente.
\item il numero \var{shm\_nattch} di processi agganciati al segmento viene
aumentato di uno.
-\end{itemize}
+\end{itemize*}
Come accennato in sez.~\ref{sec:proc_fork} un segmento di memoria condivisa
agganciato ad un processo viene ereditato da un figlio attraverso una
il flag \const{MAP\_SHARED}, le modifiche effettuate al contenuto del file
vengono viste da tutti i processi che lo hanno mappato. Utilizzare questa
tecnica per creare una memoria condivisa fra processi diversi è estremamente
-inefficiente, in quanto occorre passare attraverso il disco. Però abbiamo
-visto anche che se si esegue la mappatura con il flag \const{MAP\_ANONYMOUS}
-la regione mappata non viene associata a nessun file, anche se quanto scritto
-rimane in memoria e può essere riletto; allora, dato che un processo figlio
-mantiene nel suo spazio degli indirizzi anche le regioni mappate, esso sarà
-anche in grado di accedere a quanto in esse è contenuto.
+inefficiente, in quanto occorre passare attraverso il disco.
+
+Però abbiamo visto anche che se si esegue la mappatura con il flag
+\const{MAP\_ANONYMOUS} la regione mappata non viene associata a nessun file,
+anche se quanto scritto rimane in memoria e può essere riletto; allora, dato
+che un processo figlio mantiene nel suo spazio degli indirizzi anche le
+regioni mappate, esso sarà anche in grado di accedere a quanto in esse è
+contenuto.
In questo modo diventa possibile creare una memoria condivisa fra processi
diversi, purché questi abbiano almeno un progenitore comune che ha effettuato
lo standard è molto generico riguardo l'implementazione, ed i nomi stessi
possono avere o meno una corrispondenza sul filesystem; tutto quello che è
richiesto è che:
-\begin{itemize*}
+\begin{itemize}
\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.
nome dipende dall'implementazione.
\item l'interpretazione di ulteriori \texttt{/} presenti nel nome dipende
dall'implementazione.
-\end{itemize*}
+\end{itemize}
Data la assoluta genericità delle specifiche, il comportamento delle funzioni
è subordinato in maniera quasi completa alla relativa implementazione, 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, sia per quanto riguarda la memoria
-condivisa ed i semafori, che per quanto riguarda le code di messaggi, tutto
-viene creato usando come radici delle opportune directory (rispettivamente
-\file{/dev/shm} e \file{/dev/mqueue}, per i dettagli si faccia riferimento a
+standardizzabili.
+
+Nel caso di Linux, sia per quanto riguarda la memoria condivisa ed i semafori,
+che per quanto riguarda le code di messaggi, tutto viene creato usando come
+radici delle opportune directory (rispettivamente \file{/dev/shm} e
+\file{/dev/mqueue}, per i dettagli si faccia riferimento a
sez.~\ref{sec:ipc_posix_shm}, sez.~\ref{sec:ipc_posix_sem} e
sez.~\ref{sec:ipc_posix_mq}) ed i nomi specificati nelle relative funzioni
sono considerati come un \itindsub{pathname}{assoluto} \textit{pathname}
corrispondenza all'inclusione del supporto nel kernel ufficiale anche
\file{libmqueue} è stata inserita nella \acr{glibc}, a partire dalla
versione 2.3.4 delle medesime.} che contiene le funzioni dell'interfaccia
-POSIX.\footnote{in realtà l'implementazione è realizzata tramite delle
- opportune chiamate ad \func{ioctl} sui file del filesystem speciale su cui
- vengono mantenuti questi oggetti di IPC.}
+POSIX (in realtà l'implementazione è realizzata tramite delle opportune
+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 \conffile{/etc/fstab} una riga come:
-\begin{verbatim}
+\begin{Example}
mqueue /dev/mqueue mqueue defaults 0 0
-\end{verbatim}
+\end{Example}
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
La funzione che permette di aprire (e crearla se non esiste ancora) una coda
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)}
-
- \funcdecl{mqd\_t mq\_open(const char *name, int oflag, unsigned long mode,
+
+\begin{funcproto}{
+\fhead{mqueue.h}
+\fdecl{mqd\_t mq\_open(const char *name, int oflag)}
+\fdecl{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 per un errore; nel quel caso \var{errno} assumerà i
- valori:
- \begin{errlist}
+
+\fdesc{Apre una coda di messaggi POSIX impostandone le caratteristiche.}
+}
+
+{La funzione ritorna il descrittore associato alla coda in caso di successo e
+ $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori:
+ \begin{errlist}
\item[\errcode{EACCES}] 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
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}, \errval{EINTR} ed \errval{ENFILE}.
-}
-\end{functions}
+ \end{errlist}
+ ed inoltre \errval{ENOMEM}, \errval{ENOSPC}, \errval{EFAULT},
+ \errval{EMFILE}, \errval{EINTR} ed \errval{ENFILE} nel loro significato
+ generico.
+}
+\end{funcproto}
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{nel caso di Linux si tratta in effetti proprio di un
- normale file descriptor; pertanto, anche se questo comportamento non è
- portabile, lo si può tenere sotto osservazione con le funzioni dell'I/O
- multiplexing (vedi sez.~\ref{sec:file_multiplexing}) come possibile
- alternativa all'uso dell'interfaccia di notifica di \func{mq\_notify} (che
- vedremo a breve).} Se la coda esiste già il descrittore farà riferimento
-allo stesso oggetto, consentendo così la comunicazione fra due processi
-diversi.
+\type{mqd\_t}. Nel caso di Linux si tratta in effetti proprio di un normale
+file descriptor; pertanto, anche se questo comportamento non è portabile, lo
+si può tenere sotto osservazione con le funzioni dell'I/O multiplexing (vedi
+sez.~\ref{sec:file_multiplexing}) come possibile alternativa all'uso
+dell'interfaccia di notifica di \func{mq\_notify} (che vedremo a breve). 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
\begin{figure}[!htb]
\footnotesize \centering
- \begin{minipage}[c]{\textwidth}
+ \begin{minipage}[c]{0.90\textwidth}
\includestruct{listati/mq_attr.h}
\end{minipage}
\normalsize
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 per un errore;
- nel quel caso \var{errno} assumerà i valori \errval{EBADF} o
- \errval{EINTR}.}
-\end{prototype}
+\begin{funcproto}{
+\fhead{mqueue.h}
+\fdecl{int mq\_close(mqd\_t mqdes)}
+
+\fdesc{Chiude una coda di messaggi.}
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà uno dei valori \errval{EBADF} o \errval{EINTR} nel
+ loro significato generico.
+}
+\end{funcproto}
-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
+La funzione è analoga a \func{close} (e 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}
+\begin{funcproto}{
+\fhead{mqueue.h}
+\fdecl{int mq\_unlink(const char *name)}
+
+\fdesc{Rimuove una coda di messaggi.}
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+ caso \var{errno} assumerà gli stessi valori riportati da \func{unlink}.
+}
+\end{funcproto}
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 rimuove la coda \param{name}, così
-che una successiva chiamata a \func{mq\_open} fallisce o crea una coda
-diversa.
+\func{unlink} per i file, (e di nuovo l'implementazione di Linux usa
+direttamente \func{unlink}) la funzione rimuove 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
Come accennato 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,
+
+\begin{funcproto}{
+\fhead{mqueue.h}
+\fdecl{int mq\_getattr(mqd\_t mqdes, struct mq\_attr *mqstat)}
+\fdesc{Legge gli attributi di una coda di messaggi POSIX.}
+\fdecl{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}
+\fdesc{Modifica gli attributi di una coda di messaggi POSIX.}
+}
+
+{Entrambe le funzioni ritornano $0$ in caso di successo e $-1$ per un errore,
+ nel qual caso \var{errno} assumerà i valori \errval{EBADF}
+ o \errval{EINVAL} nel loro significato generico.
+}
+\end{funcproto}
La funzione \func{mq\_getattr} legge i valori correnti degli attributi della
coda nella struttura puntata da \param{mqstat}; di questi l'unico relativo
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$ per un
- errore; nel quel caso \var{errno} assumerà i valori:
- \begin{errlist}
+\begin{funcproto}{
+\fhead{mqueue.h}
+\fdecl{int mq\_send(mqd\_t mqdes, const char *msg\_ptr, size\_t msg\_len,
+ unsigned int msg\_prio)}
+\fdesc{Esegue l'inserimento di un messaggio su una coda.}
+\fdecl{int mq\_timedsend(mqd\_t mqdes, const char *msg\_ptr, size\_t
+ msg\_len, unsigned msg\_prio, const struct timespec *abs\_timeout)}
+\fdesc{Esegue l'inserimento di un messaggio su una coda entro un tempo
+ specificato}
+}
+
+{Entrambe le funzioni ritornano $0$ in caso di successo e $-1$ per un errore,
+ nel qual caso \var{errno} assumerà uno dei 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}
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}, \errval{ENOMEM} ed \errval{EINTR}.}
-\end{functions}
+ \end{errlist}
+ ed inoltre \errval{EBADF}, \errval{ENOMEM} ed \errval{EINTR} nel loro
+ significato generico.
+}
+\end{funcproto}
Entrambe le funzioni richiedono un puntatore al testo del messaggio
nell'argomento \param{msg\_ptr} e la relativa lunghezza in \param{msg\_len}.