From 6686b8c78363c1e91e069b0ff9932929b7948136 Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Wed, 1 May 2013 17:13:25 +0000 Subject: [PATCH] Ancora IPC, code di messaggi SysV --- ipc.tex | 708 +++++++++++++++++++++++--------------------- session.tex | 14 +- socket.tex | 28 +- sources/IPCTestId.c | 2 +- 4 files changed, 405 insertions(+), 347 deletions(-) diff --git a/ipc.tex b/ipc.tex index 41c64c4..87c35f8 100644 --- a/ipc.tex +++ b/ipc.tex @@ -437,7 +437,7 @@ di dimensioni corrette attraverso vari programmi di manipolazione In questo caso però occorre eseguire in sequenza ben quattro comandi diversi, inviando l'uscita di ciascuno all'ingresso del successivo, per poi ottenere il risultato finale sullo \textit{standard output}: un caso classico di -utilizzazione delle pipe, in cui l'uso di \func{popen} e \func{pclose} +utilizzazione delle \textit{pipe}, in cui l'uso di \func{popen} e \func{pclose} permette di semplificare notevolmente la stesura del codice. Nel nostro caso, dato che ciascun processo deve scrivere la sua uscita sullo @@ -792,68 +792,69 @@ Linux ext2fs has been stable for a long time, now it's time to break it e ripetendo varie volte il comando otterremo, in ordine casuale, le dieci frasi tenute in memoria dal server. -Infine per chiudere il server basterà inviare un segnale di terminazione con -\code{killall fortuned} e potremo verificare che il gestore del segnale ha -anche correttamente cancellato la \textit{fifo} di ascolto da \file{/tmp}. +Infine per chiudere il server basterà inviargli un segnale di terminazione (ad +esempio con \cmd{killall fortuned}) e potremo verificare che il gestore del +segnale ha anche correttamente cancellato la \textit{fifo} di ascolto da +\file{/tmp}. Benché il nostro sistema client-server funzioni, la sua struttura è piuttosto complessa e continua ad avere vari inconvenienti\footnote{lo stesso Stevens, che esamina questa architettura in \cite{APUE}, nota come sia impossibile per il server sapere se un client è andato in crash, con la possibilità di - far restare le fifo temporanee sul filesystem, di come sia necessario - intercettare \signal{SIGPIPE} dato che un client può terminare dopo aver - fatto una richiesta, ma prima che la risposta sia inviata (cosa che nel - nostro esempio non è stata fatta).}; in generale infatti l'interfaccia delle -fifo non è adatta a risolvere questo tipo di problemi, che possono essere -affrontati in maniera più semplice ed efficace o usando i socket (che -tratteremo in dettaglio a partire da cap.~\ref{cha:socket_intro}) o ricorrendo -a meccanismi di comunicazione diversi, come quelli che esamineremo in seguito. + far restare le \textit{fifo} temporanee sul filesystem, di come sia + necessario intercettare \signal{SIGPIPE} dato che un client può terminare + dopo aver fatto una richiesta, ma prima che la risposta sia inviata (cosa + che nel nostro esempio non è stata fatta).}; in generale infatti +l'interfaccia delle \textit{fifo} non è adatta a risolvere questo tipo di +problemi, che possono essere affrontati in maniera più semplice ed efficace o +usando i socket (che tratteremo in dettaglio a partire da +cap.~\ref{cha:socket_intro}) o ricorrendo a meccanismi di comunicazione +diversi, come quelli che esamineremo in seguito. \subsection{La funzione \func{socketpair}} \label{sec:ipc_socketpair} -Un meccanismo di comunicazione molto simile alle pipe, ma che non presenta il -problema della unidirezionalità del flusso dei dati, è quello dei cosiddetti -\textsl{socket locali} (o \textit{Unix domain socket}). Tratteremo l'argomento -dei socket in cap.~\ref{cha:socket_intro},\footnote{si tratta comunque di - oggetti di comunicazione che, come le pipe, sono utilizzati attraverso dei - file descriptor.} nell'ambito dell'interfaccia generale che essi forniscono -per la programmazione di rete; e vedremo anche -(in~sez.~\ref{sec:sock_sa_local}) come si possono definire dei -\index{file!speciali} file speciali (di tipo socket, analoghi a quello -associati alle fifo) cui si accede però attraverso quella medesima -interfaccia; vale però la pena esaminare qui una modalità di uso dei socket -locali\footnote{la funzione \func{socketpair} è stata introdotta in BSD4.4, ma - è supportata in genere da qualunque sistema che fornisca l'interfaccia dei - socket.} che li rende sostanzialmente identici ad una pipe bidirezionale. - -La funzione \funcd{socketpair} infatti consente di creare una coppia di file -descriptor connessi fra di loro (tramite un socket, appunto), senza dover -ricorrere ad un \index{file!speciali} file speciale sul filesystem, i -descrittori sono del tutto analoghi a quelli che si avrebbero con una chiamata -a \func{pipe}, con la sola differenza è che in questo caso il flusso dei dati -può essere effettuato in entrambe le direzioni. Il prototipo della funzione è: -\begin{functions} - \headdecl{sys/types.h} - \headdecl{sys/socket.h} - - \funcdecl{int socketpair(int domain, int type, int protocol, int sv[2])} - - Crea una coppia di socket connessi fra loro. - - \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di - errore, nel qual caso \var{errno} assumerà uno dei valori: +Un meccanismo di comunicazione molto simile alle \textit{pipe}, ma che non +presenta il problema della unidirezionalità del flusso dei dati, è quello dei +cosiddetti \textsl{socket locali} (o \textit{Unix domain socket}). Tratteremo +in generale i socket in cap.~\ref{cha:socket_intro}, nell'ambito +dell'interfaccia che essi forniscono per la programmazione di rete, e vedremo +anche (in~sez.~\ref{sec:sock_sa_local}) come si possono utilizzare i +\index{file!speciali} file speciali di tipo socket, analoghi a quelli +associati alle \textit{fifo} (si rammenti sez.~\ref{sec:file_file_types}) cui +si accede però attraverso quella medesima interfaccia; vale però la pena +esaminare qui una modalità di uso dei socket locali che li rende +sostanzialmente identici ad una \textit{pipe} bidirezionale. + +La funzione di sistema \funcd{socketpair}, introdotta da BSD ma supportata in +genere da qualunque sistema che fornisca l'interfaccia dei socket ed inclusa +in POSIX.1-2001, consente infatti di creare una coppia di file descriptor +connessi fra loro (tramite un socket, appunto) senza dover ricorrere ad un +\index{file!speciali} file speciale sul filesystem. I descrittori sono del +tutto analoghi a quelli che si avrebbero con una chiamata a \func{pipe}, con +la sola differenza è che in questo caso il flusso dei dati può essere +effettuato in entrambe le direzioni. Il prototipo della funzione è: + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/socket.h} +\fdecl{int socketpair(int domain, int type, int protocol, int sv[2])} +\fdesc{Crea una coppia di socket connessi fra loro.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EAFNOSUPPORT}] i socket locali non sono supportati. - \item[\errcode{EPROTONOSUPPORT}] il protocollo specificato non è supportato. \item[\errcode{EOPNOTSUPP}] il protocollo specificato non supporta la creazione di coppie di socket. + \item[\errcode{EPROTONOSUPPORT}] il protocollo specificato non è supportato. \end{errlist} - ed inoltre \errval{EMFILE}, \errval{EFAULT}. -} -\end{functions} + ed inoltre \errval{EFAULT}, \errval{EMFILE} e \errval{ENFILE} nel loro + significato generico.} +\end{funcproto} La funzione restituisce in \param{sv} la coppia di descrittori connessi fra di loro: quello che si scrive su uno di essi sarà ripresentato in input @@ -862,7 +863,13 @@ sull'altro e viceversa. Gli argomenti \param{domain}, \param{type} e sez.~\ref{sec:sock_creation}) che è quella che fornisce il substrato per connettere i due descrittori, ma in questo caso i soli valori validi che possono essere specificati sono rispettivamente \const{AF\_UNIX}, -\const{SOCK\_STREAM} e \val{0}. +\const{SOCK\_STREAM} e \val{0}. + +A partire dal kernel 2.6.27 la funzione supporta anche l'uso dei flag +\const{SOCK\_NONBLOCK} e \const{SOCK\_CLOEXEC} (trattati in +sez.~\ref{sec:sock_type}) nell'indicazione del tipo di socket, con effetto +identico agli analoghi \const{O\_CLOEXEC} e \const{O\_NONBLOCK} di una +\func{open} (vedi tab.~\ref{tab:open_operation_flag}). L'utilità di chiamare questa funzione per evitare due chiamate a \func{pipe} può sembrare limitata; in realtà l'utilizzo di questa funzione (e dei socket @@ -876,49 +883,51 @@ questa funzionalità in sez.~\ref{sec:sock_fd_passing}). \section{L'intercomunicazione fra processi di System V} \label{sec:ipc_sysv} -Benché le pipe e le fifo siano ancora ampiamente usate, esse scontano il -limite fondamentale che il meccanismo di comunicazione che forniscono è -rigidamente sequenziale: una situazione in cui un processo scrive qualcosa che -molti altri devono poter leggere non può essere implementata con una pipe. +Benché le \textit{pipe} e le \textit{fifo} siano ancora ampiamente usate, esse +scontano il limite fondamentale che il meccanismo di comunicazione che +forniscono è rigidamente sequenziale: una situazione in cui un processo scrive +qualcosa che molti altri devono poter leggere non può essere implementata con +una \textit{pipe}. Per questo nello sviluppo di System V vennero introdotti una serie di nuovi oggetti per la comunicazione fra processi ed una nuova interfaccia di -programmazione, che fossero in grado di garantire una maggiore flessibilità. -In questa sezione esamineremo come Linux supporta quello che viene chiamato il -\textsl{Sistema di comunicazione fra processi} di System V, cui da qui in -avanti faremo riferimento come \textit{SysV IPC} (dove IPC è la sigla di -\textit{Inter-Process Comunication}). +programmazione, poi inclusa anche in POSIX.1-2001, che fossero in grado di +garantire una maggiore flessibilità. In questa sezione esamineremo come Linux +supporta quello che viene chiamato il \textsl{Sistema di comunicazione fra + processi} di System V, cui da qui in avanti faremo riferimento come +\textit{SysV-IPC} (dove IPC è la sigla di \textit{Inter-Process + Comunication}). \subsection{Considerazioni generali} \label{sec:ipc_sysv_generic} -La principale caratteristica del \textit{SysV IPC} è quella di essere basato +La principale caratteristica del \textit{SysV-IPC} è quella di essere basato su oggetti permanenti che risiedono nel kernel. Questi, a differenza di quanto avviene per i file descriptor, non mantengono un contatore dei riferimenti, e -non vengono cancellati dal sistema una volta che non sono più in uso. - -Questo comporta due problemi: il primo è che, al contrario di quanto avviene -per pipe e fifo, la memoria allocata per questi oggetti non viene rilasciata -automaticamente quando non c'è più nessuno che li utilizzi, ed essi devono -essere cancellati esplicitamente, se non si vuole che restino attivi fino al -riavvio del sistema. Il secondo problema è che, dato che non c'è, come per i -file, un contatore del numero di riferimenti che ne indichi l'essere in uso, -essi possono essere cancellati anche se ci sono dei processi che li stanno -utilizzando, con tutte le conseguenze (negative) del caso. - -Un'ulteriore caratteristica negativa è che gli oggetti usati nel \textit{SysV - IPC} vengono creati direttamente dal kernel, e sono accessibili solo -specificando il relativo \textsl{identificatore}. Questo è un numero +non vengono cancellati dal sistema una volta che non sono più in uso. Questo +comporta due problemi: il primo è che, al contrario di quanto avviene per +\textit{pipe} e \textit{fifo}, la memoria allocata per questi oggetti non +viene rilasciata automaticamente quando non c'è più nessuno che li utilizzi ed +essi devono essere cancellati esplicitamente, se non si vuole che restino +attivi fino al riavvio del sistema. Il secondo problema è, dato che non c'è +come per i file un contatore del numero di riferimenti che ne indichi l'essere +in uso, che essi possono essere cancellati anche se ci sono dei processi che +li stanno utilizzando, con tutte le conseguenze (ovviamente assai sgradevoli) +del caso. + +Un'ulteriore caratteristica negativa è che gli oggetti usati nel +\textit{SysV-IPC} vengono creati direttamente dal kernel, e sono accessibili +solo specificando il relativo \textsl{identificatore}. Questo è un numero progressivo (un po' come il \ids{PID} dei processi) che il kernel assegna a ciascuno di essi quanto vengono creati (sul procedimento di assegnazione -torneremo in sez.~\ref{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 dinamicamente dal kernel -non è possibile prevedere quale sarà, né utilizzare un qualche valore statico, -si pone perciò il problema di come processi diversi possono accedere allo -stesso oggetto. +torneremo in sez.~\ref{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 dinamicamente +dal kernel non è possibile prevedere quale sarà, né utilizzare un qualche +valore statico, si pone perciò il problema di come processi diversi possono +accedere allo stesso oggetto. Per risolvere il problema nella struttura \struct{ipc\_perm} che il kernel associa a ciascun oggetto, viene mantenuto anche un campo apposito che @@ -927,13 +936,13 @@ primitivo \type{key\_t}, da specificare in fase di creazione dell'oggetto, e tramite la quale è possibile ricavare l'identificatore.\footnote{in sostanza si sposta il problema dell'accesso dalla classificazione in base all'identificatore alla classificazione in base alla chiave, una delle tante - complicazioni inutili presenti nel \textit{SysV IPC}.} Oltre la chiave, la + complicazioni inutili presenti nel \textit{SysV-IPC}.} Oltre la chiave, la struttura, la cui definizione è riportata in fig.~\ref{fig:ipc_ipc_perm}, mantiene varie proprietà ed informazioni associate all'oggetto. \begin{figure}[!htb] \footnotesize \centering - \begin{minipage}[c]{\textwidth} + \begin{minipage}[c]{0.80\textwidth} \includestruct{listati/ipc_perm.h} \end{minipage} \normalsize @@ -962,27 +971,27 @@ qualcun altro. Dato che non esiste una convenzione su come assegnare queste chiavi in maniera univoca l'interfaccia mette a disposizione una funzione apposita, \funcd{ftok}, che permette di ottenere una chiave specificando il nome di un file ed un numero di versione; il suo prototipo è: -\begin{functions} - \headdecl{sys/types.h} - \headdecl{sys/ipc.h} - - \funcdecl{key\_t ftok(const char *pathname, int proj\_id)} - - Restituisce una chiave per identificare un oggetto del \textit{SysV IPC}. - - \bodydesc{La funzione restituisce la chiave in caso di successo e -1 - altrimenti, nel qual caso \var{errno} sarà uno dei possibili codici di - errore di \func{stat}.} -\end{functions} + +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/ipc.h} +\fdecl{key\_t ftok(const char *pathname, int proj\_id)} +\fdesc{Restituisce una chiave per identificare un oggetto del \textit{SysV + IPC}.}} + +{La funzione ritorna la chiave in caso di successo e $-1$ per un errore, nel + qual caso \var{errno} assumerà uno dei possibili codici di errore di + \func{stat}.} +\end{funcproto} La funzione determina un valore della chiave sulla base di \param{pathname}, che deve specificare il \textit{pathname} di un file effettivamente esistente e di un numero di progetto \param{proj\_id)}, che di norma viene specificato come carattere, dato che ne vengono utilizzati solo gli 8 bit meno -significativi.\footnote{nelle libc4 e libc5, come avviene in SunOS, - l'argomento \param{proj\_id} è dichiarato tipo \ctyp{char}, la \acr{glibc} - usa il prototipo specificato da XPG4, ma vengono lo stesso utilizzati gli 8 - bit meno significativi.} +significativi. Nelle \acr{libc4} e \acr{libc5}, come avviene in SunOS, +l'argomento \param{proj\_id} è dichiarato tipo \ctyp{char}, la \acr{glibc} usa +il prototipo specificato da XPG4, ma vengono lo stesso utilizzati gli 8 bit +meno significativi. Il problema è che anche così non c'è la sicurezza che il valore della chiave sia univoco, infatti esso è costruito combinando il byte di \param{proj\_id)} @@ -1007,22 +1016,25 @@ creato da chi ci si aspetta. Questo è, insieme al fatto che gli oggetti sono permanenti e non mantengono un contatore di riferimenti per la cancellazione automatica, il principale -problema del \textit{SysV IPC}. Non esiste infatti una modalità chiara per +problema del \textit{SysV-IPC}. Non esiste infatti una modalità chiara per identificare un oggetto, come sarebbe stato se lo si fosse associato ad in -file, e tutta l'interfaccia è inutilmente complessa. Per questo ne è stata -effettuata una revisione completa nello standard POSIX.1b, che tratteremo in -sez.~\ref{sec:ipc_posix}. +file, e tutta l'interfaccia è inutilmente complessa. Per questo se ne +sconsiglia assolutamente l'uso nei nuovi programmi, considerato che è ormai +disponibile una revisione completa dei meccamismi di IPC fatta secondo quanto +indicato dallo standard POSIX.1b, che presenta una realizzazione più sicura ed +una interfaccia più semplice, che tratteremo in sez.~\ref{sec:ipc_posix}. \subsection{Il controllo di accesso} \label{sec:ipc_sysv_access_control} -Oltre alle chiavi, abbiamo visto che ad ogni oggetto sono associate in -\struct{ipc\_perm} ulteriori informazioni, come gli identificatori del creatore -(nei campi \var{cuid} e \var{cgid}) e del proprietario (nei campi \var{uid} e -\var{gid}) dello stesso, e un insieme di permessi (nel campo \var{mode}). In -questo modo è possibile definire un controllo di accesso sugli oggetti di IPC, -simile a quello che si ha per i file (vedi sez.~\ref{sec:file_perm_overview}). +Oltre alle chiavi, abbiamo visto in fig.~\ref{fig:ipc_ipc_perm} che ad ogni +oggetto sono associate in \struct{ipc\_perm} ulteriori informazioni, come gli +identificatori del creatore (nei campi \var{cuid} e \var{cgid}) e del +proprietario (nei campi \var{uid} e \var{gid}) dello stesso, e un insieme di +permessi (nel campo \var{mode}). In questo modo è possibile definire un +controllo di accesso sugli oggetti di IPC, simile a quello che si ha per i +file (vedi sez.~\ref{sec:file_perm_overview}). Benché questo controllo di accesso sia molto simile a quello dei file, restano delle importanti differenze. La prima è che il permesso di esecuzione non @@ -1030,14 +1042,17 @@ esiste (e se specificato viene ignorato), per cui si può parlare solo di permessi di lettura e scrittura (nel caso dei semafori poi quest'ultimo è più propriamente un permesso di modifica). I valori di \var{mode} sono gli stessi ed hanno lo stesso significato di quelli riportati in -tab.~\ref{tab:file_mode_flags}\footnote{se però si vogliono usare le costanti - simboliche ivi definite occorrerà includere il file \headfile{sys/stat.h}, - alcuni sistemi definiscono le costanti \const{MSG\_R} (\texttt{0400}) e - \const{MSG\_W} (\texttt{0200}) per indicare i permessi base di lettura e - scrittura per il proprietario, da utilizzare, con gli opportuni shift, pure - per il gruppo e gli altri, in Linux, visto la loro scarsa utilità, queste - costanti non sono definite.} e come per i file definiscono gli accessi per -il proprietario, il suo gruppo e tutti gli altri. +tab.~\ref{tab:file_mode_flags} e come per i file definiscono gli accessi per +il proprietario, il suo gruppo e tutti gli altri. + +Se però si vogliono usare le costanti simboliche di +tab.~\ref{tab:file_mode_flags} occorrerà includere anche il file +\headfile{sys/stat.h}; alcuni sistemi definiscono le costanti \const{MSG\_R} +(il valore ottale \texttt{0400}) e \const{MSG\_W} (il valore ottale +\texttt{0200}) per indicare i permessi base di lettura e scrittura per il +proprietario, da utilizzare, con gli opportuni shift, pure per il gruppo e gli +altri. In Linux, visto la loro scarsa utilità, queste costanti non sono +definite. Quando l'oggetto viene creato i campi \var{cuid} e \var{uid} di \struct{ipc\_perm} ed i campi \var{cgid} e \var{gid} vengono impostati @@ -1059,8 +1074,9 @@ Il secondo livello di controllo è quello delle varie funzioni che accedono 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 amministratore l'accesso è sempre - consentito. +\item se il processo ha i privilegi di amministratore (più precisamente la + capacità \itindex{capability} \const{CAP\_IPC\_OWNER}) l'accesso è sempre + consentito. \item se l'\ids{UID} effettivo del processo corrisponde o al valore del campo \var{cuid} o a quello del campo \var{uid} ed il permesso per il proprietario in \var{mode} è appropriato\footnote{per appropriato si intende che è @@ -1109,28 +1125,16 @@ Proprio per evitare questo tipo di situazioni il sistema usa il valore di assumere tutti i valori possibili, rendendo molto più lungo il periodo in cui un identificatore può venire riutilizzato. -Il sistema dispone sempre di un numero fisso di oggetti di IPC,\footnote{fino - al kernel 2.2.x questi valori, definiti dalle costanti \const{MSGMNI}, - \const{SEMMNI} e \const{SHMMNI}, potevano essere cambiati (come tutti gli - altri limiti relativi al \textit{SysV IPC}) solo con una ricompilazione del - kernel, andando a modificarne la definizione nei relativi header file. A - partire dal kernel 2.4.x è possibile cambiare questi valori a sistema attivo - scrivendo sui file \sysctlrelfile{kernel}{shmmni}, - \sysctlrelfile{kernel}{msgmni} e \sysctlrelfile{kernel}{sem} - di \file{/proc/sys/kernel} o con l'uso di \func{sysctl}.} e per ciascuno di -essi viene mantenuto in \var{seq} un numero di sequenza progressivo che viene -incrementato di uno ogni volta che l'oggetto viene cancellato. Quando -l'oggetto viene creato usando uno spazio che era già stato utilizzato in -precedenza per restituire l'identificatore al numero di oggetti presenti viene -sommato il valore di \var{seq} moltiplicato per il numero massimo di oggetti -di quel tipo,\footnote{questo vale fino ai kernel della serie 2.2.x, dalla - serie 2.4.x viene usato lo stesso fattore per tutti gli oggetti, esso è dato - dalla costante \const{IPCMNI}, definita in \file{include/linux/ipc.h}, che - indica il limite massimo per il numero di tutti oggetti di IPC, ed il cui - valore è 32768.} si evita così il riutilizzo degli stessi numeri, e si fa -sì che l'identificatore assuma tutti i valori possibili. +Il sistema dispone sempre di un numero fisso di oggetti di IPC, fino al kernel +2.2.x questi erano definiti dalle costanti \const{MSGMNI}, \const{SEMMNI} e +\const{SHMMNI}, e potevano essere cambiati (come tutti gli altri limiti +relativi al \textit{SysV-IPC}) solo con una ricompilazione del kernel. A +partire dal kernel 2.4.x è possibile cambiare questi valori a sistema attivo +scrivendo sui file \sysctlrelfile{kernel}{shmmni}, +\sysctlrelfile{kernel}{msgmni} e \sysctlrelfile{kernel}{sem} di +\file{/proc/sys/kernel} o con l'uso di \func{sysctl}. -\begin{figure}[!htbp] +\begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{\codesamplewidth} \includecodesample{listati/IPCTestId.c} @@ -1141,93 +1145,124 @@ sì che l'identificatore assuma tutti i valori possibili. \label{fig:ipc_sysv_idtest} \end{figure} +Per ciascun tipo di oggetto di IPC viene mantenuto in \var{seq} un numero di +sequenza progressivo che viene incrementato di uno ogni volta che l'oggetto +viene cancellato. Quando l'oggetto viene creato usando uno spazio che era già +stato utilizzato in precedenza, per restituire il nuovo identificatore al +numero di oggetti presenti viene sommato il valore corrente del campo +\var{seq}, moltiplicato per il numero massimo di oggetti di quel tipo. + +Questo in realtà è quanto avveniva fino ai kernel della serie 2.2, dalla serie +2.4 viene usato lo stesso fattore di moltiplicazione per qualunque tipo di +oggetto, utilizzando il valore dalla costante \const{IPCMNI} (definita in +\file{include/linux/ipc.h}), che indica il limite massimo complessivo per il +numero di tutti gli oggetti presenti nel \textit{SysV-IPC}, ed il cui default +è 32768. Si evita così il riutilizzo degli stessi numeri, e si fa sì che +l'identificatore assuma tutti i valori possibili. + In fig.~\ref{fig:ipc_sysv_idtest} è riportato il codice di un semplice -programma di test che si limita a creare un oggetto (specificato a riga di -comando), stamparne il numero di identificatore e cancellarlo per un numero -specificato di volte. Al solito non si è riportato il codice della gestione -delle opzioni a riga di comando, che permette di specificare quante volte -effettuare il ciclo \var{n}, e su quale tipo di oggetto eseguirlo. - -La figura non riporta il codice di selezione delle opzioni, che permette di -inizializzare i valori delle variabili \var{type} al tipo di oggetto voluto, e -\var{n} al numero di volte che si vuole effettuare il ciclo di creazione, -stampa, cancellazione. I valori di default sono per l'uso delle code di -messaggi e un ciclo di 5 volte. Se si lancia il comando si otterrà qualcosa -del tipo: -\begin{Verbatim} -piccardi@gont sources]$ ./ipctestid +programma di test che si limita a creare un oggetto di ICP (specificato con +una opzione a riga di comando), stamparne il numero di identificatore, e +cancellarlo, il tutto un numero di volte specificato tramite una seconda +opzione. La figura non riporta il codice di selezione delle opzioni, che +permette di inizializzare i valori delle variabili \var{type} al tipo di +oggetto voluto, e \var{n} al numero di volte che si vuole effettuare il ciclo +di creazione, stampa, cancellazione. + +I valori di default sono per l'uso delle code di messaggi e per 5 ripetizioni +del ciclo. Per questo motivo se non si utilizzano opzioni verrà eseguito per +cinque volte il ciclo (\texttt{\small 7-11}), in cui si crea una coda di +messaggi (\texttt{\small 8}), se ne stampa l'identificativo (\texttt{\small + 9}) e la si rimuove (\texttt{\small 10}). Non stiamo ad approfondire adesso +il significato delle funzioni utilizzate, che verranno esaminate nelle +prossime sezioni. + +Quello che ci interessa infatti è verificare l'allocazione degli +identificativi associati agli oggetti; lanciando il comando si otterrà +pertanto qualcosa del tipo: +\begin{Console} +piccardi@gont sources]$ \textbf{./ipctestid} Identifier Value 0 Identifier Value 32768 Identifier Value 65536 Identifier Value 98304 -Identifier Value 131072 -\end{Verbatim} +Identifier Value 131072 +\end{Console} %$ -il che ci mostra che abbiamo un kernel della serie 2.4.x nel quale non avevamo -ancora usato nessuna coda di messaggi. Se ripetiamo il comando otterremo -ancora: -\begin{Verbatim} -[piccardi@gont sources]$ ./ipctestid -Identifier Value 163840 +il che ci mostra che stiamo lavorando con un kernel posteriore alla serie 2.2 +nel quale non avevamo ancora usato nessuna coda di messaggi (il valore nullo +del primo identificativo indica che il campo \var{seq} era zero). Ripetendo il +comando, e quindi eseguendolo in un processo diverso, in cui non può esistere +nessuna traccia di quanto avvenuto in precedenza, otterremo come nuovo +risultato: +\begin{Console} +[piccardi@gont sources]$ \textbf{./ipctestid} +Identifier Value 163840 Identifier Value 196608 Identifier Value 229376 Identifier Value 262144 Identifier Value 294912 -\end{Verbatim} +\end{Console} %$ -che ci mostra come il valore di \var{seq} sia in effetti una quantità -mantenuta staticamente all'interno del sistema. +in cui la sequenza numerica prosegue, cosa che ci mostra come il valore di +\var{seq} continui ad essere incrementato e costituisca in effetti una +quantità mantenuta all'interno del sistema ed indipendente dai processi. \subsection{Code di messaggi} \label{sec:ipc_sysv_mq} -Il primo oggetto introdotto dal \textit{SysV IPC} è quello delle code di -messaggi. Le code di messaggi sono oggetti analoghi alle pipe o alle fifo, -anche se la loro struttura è diversa, ed il loro scopo principale è appunto -quello di permettere a processi diversi di scambiarsi dei dati. +Il primo oggetto introdotto dal \textit{SysV-IPC} è quello delle code di +messaggi. Le code di messaggi sono oggetti analoghi alle \textit{pipe} o alle +\textit{fifo} ed il loro scopo principale è quello di fornire a processi +diversi un meccanismo con cui scambiarsi dei dati in forma di messaggio. Dato +che le \textit{pipe} e le \textit{fifo} costituiscono una ottima alternativa, +ed in genere sono molto più semplici da usare, le code di messaggi sono il +meno utilizzato degli oggetti introdotti dal \textit{SysV-IPC}. + +La funzione di sistema che permette di ottenere l'identificativo di una coda +di messaggi esistente per potervi accedere, oppure di creare una nuova coda +qualora quella indicata non esista ancora, è \funcd{msgget}, e il suo +prototipo è: -La funzione che permette di richiedere al sistema l'identificatore di una coda -di messaggi esistente (o di crearne una se questa non esiste) è -\funcd{msgget}; il suo prototipo è: -\begin{functions} - \headdecl{sys/types.h} - \headdecl{sys/ipc.h} - \headdecl{sys/msg.h} - - \funcdecl{int msgget(key\_t key, int flag)} - - Restituisce l'identificatore di una coda di messaggi. - - \bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1 - in caso di errore, nel qual caso \var{errno} assumerà uno dei valori: +\begin{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/ipc.h} +\fhead{sys/msg.h} +\fdecl{int msgget(key\_t key, int flag)} +\fdesc{Ottiene o crea una coda di messaggi.} +} + +{La funzione ritorna l'identificatore (un intero positivo) 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 chiamante non ha i privilegi per accedere - alla coda richiesta. + \item[\errcode{EACCES}] il processo chiamante non ha i privilegi per + accedere alla coda richiesta. \item[\errcode{EEXIST}] si è richiesta la creazione di una coda che già - esiste, ma erano specificati sia \const{IPC\_CREAT} che \const{IPC\_EXCL}. - \item[\errcode{EIDRM}] la coda richiesta è marcata per essere cancellata. + esiste, ma erano specificati sia \const{IPC\_CREAT} che \const{IPC\_EXCL}. + \item[\errcode{EIDRM}] la coda richiesta è marcata per essere cancellata + (solo fino al kernel 2.3.20). \item[\errcode{ENOENT}] si è cercato di ottenere l'identificatore di una coda di messaggi specificando una chiave che non esiste e \const{IPC\_CREAT} non era specificato. \item[\errcode{ENOSPC}] si è cercato di creare una coda di messaggi quando è stato superato il limite massimo di code (\const{MSGMNI}). - \end{errlist} - ed inoltre \errval{ENOMEM}. -} -\end{functions} + \end{errlist} + ed inoltre \errval{ENOMEM} nel suo significato generico.} +\end{funcproto} Le funzione (come le analoghe che si usano per gli altri oggetti) serve sia a ottenere l'identificatore di una coda di messaggi esistente, che a crearne una nuova. L'argomento \param{key} specifica la chiave che è associata all'oggetto, eccetto il caso in cui si specifichi il valore \const{IPC\_PRIVATE}, nel qual caso la coda è creata ex-novo e non vi è -associata alcuna chiave, il processo (ed i suoi eventuali figli) potranno -farvi riferimento solo attraverso l'identificatore. +associata alcuna chiave (per questo viene detta \textsl{privata}), ed il +processo e i suoi eventuali figli potranno farvi riferimento solo attraverso +l'identificatore. -Se invece si specifica un valore diverso da \const{IPC\_PRIVATE}\footnote{in - Linux questo significa un valore diverso da zero.} l'effetto della funzione -dipende dal valore di \param{flag}, se questo è nullo la funzione si limita ad +Se invece si specifica un valore diverso da \const{IPC\_PRIVATE} (in Linux +questo significa un valore diverso da zero) l'effetto della funzione dipende +dal valore di \param{flag}, se questo è nullo la funzione si limita ad effettuare una ricerca sugli oggetti esistenti, restituendo l'identificatore se trova una corrispondenza, o fallendo con un errore di \errcode{ENOENT} se non esiste o di \errcode{EACCES} se si sono specificati dei permessi non @@ -1243,20 +1278,20 @@ successo solo se l'oggetto non esiste già, fallendo con un errore di \errcode{EEXIST} altrimenti. Si tenga conto che l'uso di \const{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) +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 \const{IPC\_PRIVATE} o const{IPC\_CREAT} e -\const{IPC\_EXCL} per \param{flag} comporta solo la creazione di una nuova -coda. +IPC infatti non esiste alcun modo in cui si possa garantire l'accesso +esclusivo ad una coda di messaggi. Usare \const{IPC\_PRIVATE} o +\const{IPC\_CREAT} e \const{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{Costante} & \textbf{Valore} & \textbf{File in \file{/proc}} & \textbf{Significato} \\ \hline \hline @@ -1272,38 +1307,51 @@ coda. \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 -tab.~\ref{tab:ipc_msg_limits}, come accennato però in Linux è possibile -modificare questi limiti attraverso l'uso di \func{sysctl} o scrivendo nei -file \sysctlrelfile{kernel}{msgmax}, -\sysctlrelfile{kernel}{msgmnb} e -\sysctlrelfile{kernel}{msgmni} di \file{/proc/sys/kernel/}. - -\begin{figure}[!htb] - \centering \includegraphics[width=13cm]{img/mqstruct} - \caption{Schema della struttura di una coda messaggi.} - \label{fig:ipc_mq_schema} -\end{figure} - +Le code di messaggi sono caratterizzate da tre limiti fondamentali, un tempo +definiti staticamente e corrispondenti alle prime tre costanti riportate in +tab.~\ref{tab:ipc_msg_limits}. Come accennato però con tutte le versioni più +recenti del kernel con Linux è possibile modificare questi limiti attraverso +l'uso di \func{sysctl} o scrivendo nei file \sysctlrelfile{kernel}{msgmax}, +\sysctlrelfile{kernel}{msgmnb} e \sysctlrelfile{kernel}{msgmni} di +\file{/proc/sys/kernel/}. Una coda di messaggi è costituita da una \itindex{linked~list} \textit{linked - list};\footnote{una \itindex{linked~list} \textit{linked list} è una tipica + list}.\footnote{una \itindex{linked~list} \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.} i nuovi messaggi vengono inseriti in coda alla lista e vengono -letti dalla cima, in fig.~\ref{fig:ipc_mq_schema} si è riportato lo schema con -cui queste strutture vengono mantenute dal kernel.\footnote{lo schema - illustrato in fig.~\ref{fig:ipc_mq_schema} è in realtà una semplificazione - di quello usato effettivamente fino ai kernel della serie 2.2.x, nei kernel - della serie 2.4.x la gestione delle code di messaggi è stata modificata ed è - effettuata in maniera diversa; abbiamo mantenuto lo schema precedente in - quanto illustra comunque in maniera più che adeguata i principi di - funzionamento delle code di messaggi.} + ricerca.} I nuovi messaggi vengono inseriti in coda alla lista e vengono +letti dalla cima, in fig.~\ref{fig:ipc_mq_schema} si è riportato uno schema +semplificato con cui queste strutture vengono mantenute dal +kernel.\footnote{lo schema illustrato è in realtà una semplificazione di + quello usato fino ai kernel della serie 2.2, a partire della serie 2.4 la + gestione delle code di messaggi è effettuata in maniera diversa, ma abbiamo + mantenuto lo schema precedente dato che illustra in maniera più che adeguata + i principi di funzionamento delle code di messaggi.} + +\begin{figure}[!htb] + \centering \includegraphics[width=13cm]{img/mqstruct} + \caption{Schema della struttura di una coda messaggi.} + \label{fig:ipc_mq_schema} +\end{figure} + + +A ciascuna coda è associata una struttura \struct{msqid\_ds} la cui +definizione è riportata in fig.~\ref{fig:ipc_msqid_ds}. In questa struttura il +kernel mantiene le principali informazioni riguardo lo stato corrente della +coda.\footnote{come accennato questo vale fino ai kernel della serie 2.2, essa + viene usata nei kernel della serie 2.4 solo per compatibilità in quanto è + quella restituita dalle funzioni dell'interfaccia; si noti come ci sia una + differenza con i campi mostrati nello schema di fig.~\ref{fig:ipc_mq_schema} + che sono presi dalla definizione di \file{include/linux/msg.h}, e fanno + riferimento alla definizione della omonima struttura usata nel kernel.} In +fig.~\ref{fig:ipc_msqid_ds} sono elencati i campi significativi definiti in +\headfile{sys/msg.h}, a cui si sono aggiunti gli ultimi tre campi che sono +previsti dalla implementazione originale di System V, ma non dallo standard +Unix98. \begin{figure}[!htb] \footnotesize \centering @@ -1316,20 +1364,6 @@ cui queste strutture vengono mantenute dal kernel.\footnote{lo schema \label{fig:ipc_msqid_ds} \end{figure} -A ciascuna coda è associata una struttura \struct{msqid\_ds}, la cui -definizione, è riportata in fig.~\ref{fig:ipc_msqid_ds}. In questa struttura -il kernel mantiene le principali informazioni riguardo lo stato corrente della -coda.\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. Si noti come ci - sia una differenza con i campi mostrati nello schema di - fig.~\ref{fig:ipc_mq_schema} che sono presi dalla definizione di - \file{include/linux/msg.h}, e fanno riferimento alla definizione della - omonima struttura usata nel kernel.} In fig.~\ref{fig:ipc_msqid_ds} sono -elencati i campi significativi definiti in \headfile{sys/msg.h}, a cui si sono -aggiunti gli ultimi tre campi che sono previsti dalla implementazione -originale di System V, ma non dallo standard Unix98. - 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 sez.~\ref{sec:ipc_sysv_access_control}, per quanto riguarda @@ -1356,20 +1390,20 @@ gli altri campi invece: \end{itemize*} Una volta creata una coda di messaggi le operazioni di controllo vengono -effettuate con la funzione \funcd{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} assumerà uno dei valori: +effettuate con la funzione di sistema \funcd{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{funcproto}{ +\fhead{sys/types.h} +\fhead{sys/ipc.h} +\fhead{sys/msg.h} +\fdecl{int msgctl(int msqid, int cmd, struct msqid\_ds *buf)} +\fdesc{Esegue una operazione su una coda.} +} + +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: \begin{errlist} \item[\errcode{EACCES}] si è richiesto \const{IPC\_STAT} ma processo chiamante non ha i privilegi di lettura sulla coda. @@ -1379,9 +1413,10 @@ prototipo è: \var{msg\_qbytes} oltre il limite \const{MSGMNB} senza essere amministratore. \end{errlist} - ed inoltre \errval{EFAULT} ed \errval{EINVAL}. -} -\end{functions} + ed inoltre \errval{EFAULT} ed \errval{EINVAL} nel loro significato + generico.} +\end{funcproto} + La funzione permette di accedere ai valori della struttura \struct{msqid\_ds}, mantenuta all'indirizzo \param{buf}, per la coda specificata @@ -1603,13 +1638,13 @@ vengono modificati: \end{itemize*} Le code di messaggi presentano il solito problema di tutti gli oggetti del -SysV IPC; essendo questi permanenti restano nel sistema occupando risorse -anche quando un processo è terminato, al contrario delle pipe per le quali -tutte le risorse occupate vengono rilasciate quanto l'ultimo processo che le -utilizzava termina. Questo comporta che in caso di errori si può saturare il -sistema, e che devono comunque essere esplicitamente previste delle funzioni -di rimozione in caso di interruzioni o uscite dal programma (come vedremo in -fig.~\ref{fig:ipc_mq_fortune_server}). +SysV-IPC; essendo questi permanenti restano nel sistema occupando risorse +anche quando un processo è terminato, al contrario delle \textit{pipe} per le +quali tutte le risorse occupate vengono rilasciate quanto l'ultimo processo +che le utilizzava termina. Questo comporta che in caso di errori si può +saturare il sistema, e che devono comunque essere esplicitamente previste +delle funzioni di rimozione in caso di interruzioni o uscite dal programma +(come vedremo in fig.~\ref{fig:ipc_mq_fortune_server}). L'altro problema è non facendo uso di file descriptor le tecniche di \textit{I/O multiplexing} descritte in sez.~\ref{sec:file_multiplexing} non @@ -1621,9 +1656,9 @@ di \itindex{polling} \textit{polling} che esegua un ciclo di attesa su ciascuna di esse. Come esempio dell'uso delle code di messaggi possiamo riscrivere il nostro -server di \textit{fortunes} usando queste al posto delle fifo. In questo caso -useremo una sola coda di messaggi, usando il tipo di messaggio per comunicare -in maniera indipendente con client diversi. +server di \textit{fortunes} usando queste al posto delle \textit{fifo}. In +questo caso useremo una sola coda di messaggi, usando il tipo di messaggio per +comunicare in maniera indipendente con client diversi. \begin{figure}[!htbp] \footnotesize \centering @@ -1642,9 +1677,9 @@ principali del codice del nuovo server (il codice completo è nel file uso accorto della caratteristica di poter associate un ``tipo'' ai messaggi per permettere una comunicazione indipendente fra il server ed i vari client, usando il \ids{PID} di questi ultimi come identificativo. Questo è possibile -in quanto, al contrario di una fifo, la lettura di una coda di messaggi può -non essere sequenziale, proprio grazie alla classificazione dei messaggi sulla -base del loro tipo. +in quanto, al contrario di una \textit{fifo}, la lettura di una coda di +messaggi può non essere sequenziale, proprio grazie alla classificazione dei +messaggi sulla base del loro tipo. Il programma, oltre alle solite variabili per il nome del file da cui leggere le \textit{fortunes} e per il vettore di stringhe che contiene le frasi, @@ -1659,7 +1694,8 @@ in \var{n} il numero di frasi da leggere specificato a linea di comando ed in server, viene prima controllato (\texttt{\small 22}) il numero di frasi richieste abbia senso (cioè sia maggiore di zero), le quali poi (\texttt{\small 23}) vengono lette nel vettore in memoria con la stessa -funzione \code{FortuneParse} usata anche per il server basato sulle fifo. +funzione \code{FortuneParse} usata anche per il server basato sulle +\textit{fifo}. Una volta inizializzato il vettore di stringhe coi messaggi presi dal file delle \textit{fortune} si procede (\texttt{\small 25}) con la generazione di @@ -1775,15 +1811,15 @@ il server inviando il segnale di terminazione con il comando \code{killall mqfortuned} verificando che effettivamente la coda di messaggi viene rimossa. Benché funzionante questa architettura risente dello stesso inconveniente -visto anche nel caso del precedente server basato sulle fifo; se il client -viene interrotto dopo l'invio del messaggio di richiesta e prima della lettura -della risposta, quest'ultima resta nella coda (così come per le fifo si aveva -il problema delle fifo che restavano nel filesystem). In questo caso però il -problemi sono maggiori, sia perché è molto più facile esaurire la memoria -dedicata ad una coda di messaggi che gli \itindex{inode} inode di un filesystem, -sia perché, con il riutilizzo dei \ids{PID} da parte dei processi, un client -eseguito in un momento successivo potrebbe ricevere un messaggio non -indirizzato a lui. +visto anche nel caso del precedente server basato sulle \textit{fifo}; se il +client viene interrotto dopo l'invio del messaggio di richiesta e prima della +lettura della risposta, quest'ultima resta nella coda (così come per le +\textit{fifo} si aveva il problema delle \textit{fifo} che restavano nel +filesystem). In questo caso però il problemi sono maggiori, sia perché è molto +più facile esaurire la memoria dedicata ad una coda di messaggi che gli +\itindex{inode} inode di un filesystem, sia perché, con il riutilizzo dei +\ids{PID} da parte dei processi, un client eseguito in un momento successivo +potrebbe ricevere un messaggio non indirizzato a lui. @@ -1791,10 +1827,11 @@ indirizzato a lui. \label{sec:ipc_sysv_sem} I semafori non sono meccanismi di intercomunicazione diretta come quelli -(pipe, fifo e code di messaggi) visti finora, e non consentono di scambiare -dati fra processi, ma servono piuttosto come meccanismi di sincronizzazione o -di protezione per le \index{sezione~critica} \textsl{sezioni critiche} del -codice (si ricordi quanto detto in sez.~\ref{sec:proc_race_cond}). +(\textit{pipe}, \textit{fifo} e code di messaggi) visti finora, e non +consentono di scambiare dati fra processi, ma servono piuttosto come +meccanismi di sincronizzazione o di protezione per le \index{sezione~critica} +\textsl{sezioni critiche} del codice (si ricordi quanto detto in +sez.~\ref{sec:proc_race_cond}). Un semaforo è uno speciale contatore, mantenuto nel kernel, che permette, a seconda del suo valore, di consentire o meno la prosecuzione dell'esecuzione @@ -1828,7 +1865,7 @@ della risorsa. In generale però si possono usare semafori con valori interi, utilizzando il valore del contatore come indicatore del ``numero di risorse'' ancora disponibili. -Il sistema di comunicazione inter-processo di \textit{SysV IPC} prevede anche i +Il sistema di comunicazione inter-processo di \textit{SysV-IPC} prevede anche i semafori, ma gli oggetti utilizzati non sono semafori singoli, ma gruppi di semafori detti \textsl{insiemi} (o \textit{semaphore set}); la funzione che permette di creare o ottenere l'identificatore di un insieme di semafori è @@ -1871,7 +1908,7 @@ richiesta dell'identificatore di un insieme già esistente. Purtroppo questa implementazione complica inutilmente lo schema elementare che abbiamo descritto, dato che non è possibile definire un singolo semaforo, ma se ne deve creare per forza un insieme. Ma questa in definitiva è solo una -complicazione inutile, il problema è che i semafori del \textit{SysV IPC} +complicazione inutile, il problema è che i semafori del \textit{SysV-IPC} soffrono di altri due, ben più gravi, difetti. Il primo difetto è che non esiste una funzione che permetta di creare ed @@ -1880,7 +1917,7 @@ dei semafori con \func{semget} e poi inizializzarlo con \func{semctl}, si perde così ogni possibilità di eseguire l'operazione atomicamente. Il secondo difetto deriva dalla caratteristica generale degli oggetti del -\textit{SysV IPC} di essere risorse globali di sistema, che non vengono +\textit{SysV-IPC} di essere risorse globali di sistema, che non vengono cancellate quando nessuno le usa più; ci si così a trova a dover affrontare esplicitamente il caso in cui un processo termina per un qualche errore, lasciando un semaforo occupato, che resterà tale fino al successivo riavvio @@ -1921,7 +1958,7 @@ quanto riguarda gli altri campi invece: Ciascun semaforo dell'insieme è realizzato come una struttura di tipo \struct{sem} che ne contiene i dati essenziali, la sua definizione\footnote{si è riportata la definizione originaria del kernel 1.0, che contiene la prima - realizzazione del \textit{SysV IPC} in Linux. In realtà questa struttura + realizzazione del \textit{SysV-IPC} in Linux. In realtà questa struttura ormai è ridotta ai soli due primi membri, e gli altri vengono calcolati dinamicamente. La si è utilizzata a scopo di esempio, perché indica tutti i valori associati ad un semaforo, restituiti dalle funzioni di controllo, e @@ -2277,7 +2314,7 @@ occorre fare riferimento all'implementazione usata in Linux, che è riportata in maniera semplificata nello schema di fig.~\ref{fig:ipc_sem_schema}. Si è presa come riferimento l'architettura usata fino al kernel 2.2.x che è più semplice (ed illustrata in dettaglio in \cite{tlk}); nel kernel 2.4.x la -struttura del \textit{SysV IPC} è stata modificata, ma le definizioni relative +struttura del \textit{SysV-IPC} è stata modificata, ma le definizioni relative a queste strutture restano per compatibilità.\footnote{in particolare con le vecchie versioni delle librerie del C, come le libc5.} @@ -2425,7 +2462,7 @@ problemi, usando il \itindex{file~locking} \textit{file locking}. \subsection{Memoria condivisa} \label{sec:ipc_sysv_shm} -Il terzo oggetto introdotto dal \textit{SysV IPC} è quello dei segmenti di +Il terzo oggetto introdotto dal \textit{SysV-IPC} è quello dei segmenti di memoria condivisa. La funzione che permette di ottenerne uno è \funcd{shmget}, ed il suo prototipo è: \begin{functions} @@ -2822,10 +2859,10 @@ Benché la memoria condivisa costituisca il meccanismo di intercomunicazione fra processi più veloce, essa non è sempre il più appropriato, dato che, come abbiamo visto, si avrà comunque la necessità di una sincronizzazione degli accessi. Per questo motivo, quando la comunicazione fra processi è -sequenziale, altri meccanismi come le pipe, le fifo o i socket, che non -necessitano di sincronizzazione esplicita, sono da preferire. Essa diventa -l'unico meccanismo possibile quando la comunicazione non è -sequenziale\footnote{come accennato in sez.~\ref{sec:ipc_sysv_mq} per la +sequenziale, altri meccanismi come le \textit{pipe}, le \textit{fifo} o i +socket, che non necessitano di sincronizzazione esplicita, sono da +preferire. Essa diventa l'unico meccanismo possibile quando la comunicazione +non è sequenziale\footnote{come accennato in sez.~\ref{sec:ipc_sysv_mq} per la comunicazione non sequenziale si possono usare le code di messaggi, attraverso l'uso del campo \var{mtype}, ma solo se quest'ultima può essere effettuata in forma di messaggio.} o quando non può avvenire secondo una @@ -3103,7 +3140,7 @@ key msqid owner perms used-bytes messages \label{sec:ipc_alternatives} Come abbiamo detto in sez.~\ref{sec:ipc_sysv_generic}, e ripreso nella -descrizione dei singoli oggetti che ne fan parte, il \textit{SysV IPC} +descrizione dei singoli oggetti che ne fan parte, il \textit{SysV-IPC} presenta numerosi problemi; in \cite{APUE}\footnote{in particolare nel capitolo 14.} Stevens ne effettua una accurata analisi (alcuni dei concetti sono già stati accennati in precedenza) ed elenca alcune possibili tecniche @@ -3114,20 +3151,21 @@ alternative, che vogliamo riprendere in questa sezione. \label{sec:ipc_mq_alternative} Le code di messaggi sono probabilmente il meno usato degli oggetti del -\textit{SysV IPC}; esse infatti nacquero principalmente come meccanismo di -comunicazione bidirezionale quando ancora le pipe erano unidirezionali; con la -disponibilità di \func{socketpair} (vedi sez.~\ref{sec:ipc_socketpair}) o -utilizzando una coppia di pipe, si può ottenere questo risultato senza -incorrere nelle complicazioni introdotte dal \textit{SysV IPC}. +\textit{SysV-IPC}; esse infatti nacquero principalmente come meccanismo di +comunicazione bidirezionale quando ancora le \textit{pipe} erano +unidirezionali; con la disponibilità di \func{socketpair} (vedi +sez.~\ref{sec:ipc_socketpair}) o utilizzando una coppia di \textit{pipe}, si +può ottenere questo risultato senza incorrere nelle complicazioni introdotte +dal \textit{SysV-IPC}. In realtà, grazie alla presenza del campo \var{mtype}, le code di messaggi hanno delle caratteristiche ulteriori, consentendo una classificazione dei messaggi ed un accesso non rigidamente sequenziale; due caratteristiche che -sono impossibili da ottenere con le pipe e i socket di \func{socketpair}. A -queste esigenze però si può comunque ovviare in maniera diversa con un uso -combinato della memoria condivisa e dei meccanismi di sincronizzazione, per -cui alla fine l'uso delle code di messaggi classiche è relativamente poco -diffuso. +sono impossibili da ottenere con le \textit{pipe} e i socket di +\func{socketpair}. A queste esigenze però si può comunque ovviare in maniera +diversa con un uso combinato della memoria condivisa e dei meccanismi di +sincronizzazione, per cui alla fine l'uso delle code di messaggi classiche è +relativamente poco diffuso. % TODO: trattare qui, se non ssis trova posto migliore, copy_from_process e % copy_to_process, introdotte con il kernel 3.2. Vedi @@ -3140,7 +3178,7 @@ diffuso. \index{file!di lock|(} -Come illustrato in sez.~\ref{sec:ipc_sysv_sem} i semafori del \textit{SysV IPC} +Come illustrato in sez.~\ref{sec:ipc_sysv_sem} i semafori del \textit{SysV-IPC} presentano una interfaccia inutilmente complessa e con alcuni difetti strutturali, per questo quando si ha una semplice esigenza di sincronizzazione per la quale basterebbe un semaforo binario (quello che abbiamo definito come @@ -3323,12 +3361,11 @@ nessun inconveniente. \subsection{Il \textit{memory mapping} anonimo} \label{sec:ipc_mmap_anonymous} -\itindbeg{memory~mapping} -Abbiamo già visto che quando i processi sono \textsl{correlati}\footnote{se - cioè hanno almeno un progenitore comune.} l'uso delle pipe può costituire -una valida alternativa alle code di messaggi; nella stessa situazione si può -evitare l'uso di una memoria condivisa facendo ricorso al cosiddetto -\textit{memory mapping} anonimo. +\itindbeg{memory~mapping} Abbiamo già visto che quando i processi sono +\textsl{correlati}\footnote{se cioè hanno almeno un progenitore comune.} l'uso +delle \textit{pipe} può costituire una valida alternativa alle code di +messaggi; nella stessa situazione si può evitare l'uso di una memoria +condivisa facendo ricorso al cosiddetto \textit{memory mapping} anonimo. In sez.~\ref{sec:file_memory_map} abbiamo visto come sia possibile mappare il contenuto di un file nella memoria di un processo, e che, quando viene usato @@ -3364,7 +3401,7 @@ sez.~\ref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete. \section{L'intercomunicazione fra processi di POSIX} \label{sec:ipc_posix} -Per superare i numerosi problemi del \textit{SysV IPC}, evidenziati per i suoi +Per superare i numerosi problemi del \textit{SysV-IPC}, evidenziati per i suoi aspetti generali in coda a sez.~\ref{sec:ipc_sysv_generic} e per i singoli oggetti nei paragrafi successivi, lo standard POSIX.1b ha introdotto dei nuovi meccanismi di comunicazione, che vanno sotto il nome di POSIX IPC, definendo @@ -3382,7 +3419,7 @@ richiedono il kernel 2.6, le code di messaggi sono supportate a partire dal kernel 2.6.6. La caratteristica fondamentale dell'interfaccia POSIX è l'abbandono dell'uso -degli identificatori e delle chiavi visti nel SysV IPC, per passare ai +degli identificatori e delle chiavi visti nel \textit{SysV-IPC}, per passare ai \itindex{POSIX~IPC~names} \textit{POSIX IPC names}, che sono sostanzialmente 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; @@ -3429,7 +3466,7 @@ permessi dei file, ed il controllo di accesso segue esattamente la stessa semantica (quella illustrata in sez.~\ref{sec:file_access_control}), e non quella particolare (si ricordi quanto visto in sez.~\ref{sec:ipc_sysv_access_control}) che viene usata per gli oggetti del -SysV IPC. Per quanto riguarda l'attribuzione dell'utente e del gruppo +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: corrispondono cioè a \ids{UID} e \ids{GID} effettivi del processo che esegue la creazione. @@ -3441,8 +3478,8 @@ del processo che esegue la creazione. Le code di messaggi POSIX sono supportate da Linux a partire dalla versione 2.6.6-rc1 del kernel,\footnote{l'implementazione è dovuta a Michal Wronski e Krzysztof Benedyczak, e le relative informazioni si possono trovare su - \url{http://www.geocities.com/wronski12/posix_ipc/index.html}.} In -generale, come le corrispettive del SysV IPC, le code di messaggi sono poco + \url{http://www.geocities.com/wronski12/posix_ipc/index.html}.} In generale, +come le corrispettive del \textit{SysV-IPC}, le code di messaggi sono poco usate, dato che i socket, nei casi in cui sono sufficienti, sono più comodi, e che in casi più complessi la comunicazione può essere gestita direttamente con mutex (o semafori) e memoria condivisa con tutta la flessibilità che occorre. @@ -3624,10 +3661,11 @@ 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. +processo (questa è una delle differenze più rilevanti nei confronti di +\textit{pipe} e \textit{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 ad ogni coda di messaggi è associata una struttura \struct{mq\_attr}, che può essere letta e modificata attraverso le due @@ -4055,9 +4093,9 @@ caso di successo. La terza funzione (\texttt{\small 40--45}) è \func{RemoveShm}, e serve a cancellare un segmento di memoria condivisa. Dato che al contrario di quanto -avveniva con i segmenti del SysV IPC gli oggetti allocati nel kernel vengono -rilasciati automaticamente quando nessuna li usa più, tutto quello che c'è da -fare (\texttt{\small 44}) in questo caso è chiamare \func{shm\_unlink}, +avveniva con i segmenti del \textit{SysV-IPC} gli oggetti allocati nel kernel +vengono rilasciati automaticamente quando nessuna li usa più, tutto quello che +c'è da fare (\texttt{\small 44}) in questo caso è chiamare \func{shm\_unlink}, restituendo al chiamante il valore di ritorno. @@ -4075,8 +4113,8 @@ dei semafori POSIX che li realizzava solo a livello di \itindex{thread} estensioni \textit{real-time} della \acr{glibc}.\footnote{quelle che si accedono collegandosi alla libreria \texttt{librt}.} Esisteva inoltre una libreria che realizzava (parzialmente) l'interfaccia POSIX usando le funzioni -dei semafori di SysV IPC (mantenendo così tutti i problemi sottolineati in -sez.~\ref{sec:ipc_sysv_sem}). +dei semafori di \textit{SysV-IPC} (mantenendo così tutti i problemi +sottolineati in sez.~\ref{sec:ipc_sysv_sem}). A partire dal kernel 2.5.7 è stato introdotto un meccanismo di sincronizzazione completamente nuovo, basato sui cosiddetti @@ -4143,7 +4181,7 @@ Se si usa \const{O\_CREAT} si richiede la creazione del semaforo qualora questo non esista, ed in tal caso occorre utilizzare la seconda forma della funzione, in cui si devono specificare sia un valore iniziale con l'argomento \param{value},\footnote{e si noti come così diventa possibile, differenza di - quanto avviene per i semafori del \textit{SysV IPC}, effettuare in maniera + quanto avviene per i semafori del \textit{SysV-IPC}, effettuare in maniera atomica creazione ed inizializzazione di un semaforo usando una unica funzione.} che una maschera dei permessi con l'argomento \param{mode};\footnote{anche questo argomento prende gli stessi valori @@ -4352,7 +4390,7 @@ risorse possono restare bloccate. Si tenga poi presente che, a differenza di quanto avviene per i file, in caso di una chiamata ad \func{execve} tutti i semafori vengono chiusi automaticamente. -Come per i semafori del \textit{SysV IPC} anche quelli POSIX hanno una +Come per i semafori del \textit{SysV-IPC} anche quelli POSIX hanno una persistenza di sistema; questo significa che una volta che si è creato un semaforo con \func{sem\_open} questo continuerà ad esistere fintanto che il kernel resta attivo (vale a dire fino ad un successivo riavvio) a meno che non @@ -4625,14 +4663,14 @@ Per verificare il funzionamento dei programmi occorrerà lanciare per primo luogo ad un errore, non essendo stati creati il semaforo ed il segmento di memoria condivisa.} che inizierà a stampare una volta al secondo il contenuto del messaggio ed i suoi dati, con qualcosa del tipo: -\begin{Verbatim} -piccardi@hain:~/gapil/sources$ ./message_getter messaggio +\begin{Console} +piccardi@hain:~/gapil/sources$ \textbf{./message_getter messaggio} sem=1, Fri Dec 31 14:12:41 2010 message: messaggio sem=1, Fri Dec 31 14:12:42 2010 message: messaggio ... -\end{Verbatim} +\end{Console} %$ proseguendo indefinitamente fintanto che non si prema \texttt{C-c} per farlo uscire. Si noti come il valore del semaforo risulti sempre pari ad 1 (in @@ -4641,10 +4679,10 @@ quanto al momento esso sarà sempre libero). A questo punto si potrà lanciare \file{message\_setter} per cambiare il messaggio, nel nostro caso per rendere evidente il funzionamento del blocco richiederemo anche una attesa di 3 secondi, ed otterremo qualcosa del tipo: -\begin{Verbatim} -piccardi@hain:~/gapil/sources$ ./message_setter -t 3 ciao +\begin{Console} +piccardi@hain:~/gapil/sources$ \textbf{./message_setter -t 3 ciao} Sleeping for 3 seconds -\end{Verbatim} +\end{Console} %$ dove il programma si fermerà per 3 secondi prima di rilasciare il semaforo e terminare. @@ -4652,7 +4690,7 @@ terminare. L'effetto di questo programma si potrà però apprezzare meglio nell'uscita di \file{message\_getter}, che verrà interrotta per questo stesso tempo, prima di ricominciare con il nuovo testo: -\begin{Verbatim} +\begin{Console} ... sem=1, Fri Dec 31 14:16:27 2010 message: messaggio @@ -4665,7 +4703,7 @@ message: ciao sem=1, Fri Dec 31 14:16:33 2010 message: ciao ... -\end{Verbatim} +\end{Console} %$ E si noterà come nel momento in cui si è lanciato \file{message\_setter} le @@ -4692,7 +4730,7 @@ testo alla terminazione di quest'ultimo. % LocalWords: FortuneServer FortuneParse FortuneClient pid libgapil LD librt % LocalWords: PATH linker pathname ps tmp killall fortuned crash socket domain % LocalWords: socketpair BSD sys protocol sv EAFNOSUPPORT EPROTONOSUPPORT AF -% LocalWords: EOPNOTSUPP SOCK SysV IPC Process Comunication ipc perm key exec +% LocalWords: EOPNOTSUPP SOCK Process Comunication ipc perm key exec % LocalWords: header ftok proj stat libc SunOS glibc XPG dell'inode number uid % LocalWords: cuid cgid gid tab MSG shift group umask seq MSGMNI SEMMNI SHMMNI % LocalWords: shmmni msgmni sem sysctl IPCMNI IPCTestId msgget EACCES EEXIST diff --git a/session.tex b/session.tex index fff7812..d3bcdde 100644 --- a/session.tex +++ b/session.tex @@ -195,9 +195,9 @@ prototipo è: {La funzione ritorna l'identificatore (un numero positivo) in caso di successo e $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} - \item[\errcode{ESRCH}] il processo selezionato non esiste. \item[\errcode{EPERM}] il processo selezionato non fa parte della stessa sessione del processo corrente (solo in alcune implementazioni). + \item[\errcode{ESRCH}] il processo selezionato non esiste. \end{errlist} } \end{funcproto} @@ -264,11 +264,11 @@ il cui prototipo è: successo e $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} - \item[\errcode{ESRCH}] il processo selezionato non esiste. - \item[\errcode{EPERM}] il cambiamento non è consentito. \item[\errcode{EACCES}] il processo di cui si vuole cambiare il \ids{PGID} ha già eseguito una \func{exec}. \item[\errcode{EINVAL}] il valore di \param{pgid} è negativo. + \item[\errcode{EPERM}] il cambiamento non è consentito. + \item[\errcode{ESRCH}] il processo selezionato non esiste. \end{errlist} } \end{funcproto} @@ -403,9 +403,9 @@ funzione \funcd{tcsetpgrp}, il cui prototipo è: {La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} + \item[\errcode{ENOSYS}] il sistema non supporta il \textit{job control}. \item[\errcode{ENOTTY}] il file \param{fd} non corrisponde al terminale di controllo del processo chiamante. - \item[\errcode{ENOSYS}] il sistema non supporta il \textit{job control}. \item[\errcode{EPERM}] il \textit{process group} specificato non è nella stessa sessione del processo chiamante. \end{errlist} @@ -1147,11 +1147,11 @@ circolare esiste una apposita \textit{system call} chiamata anch'essa \item[\errcode{EINVAL}] l'argomento \param{op} non ha un valore valido, o si sono specificati valori non validi per gli altri argomenti quando questi sono richiesti. - \item[\errcode{ERESTARTSYS}] l'operazione è stata interrotta da un segnale. - \item[\errcode{EPERM}] non si hanno i privilegi richiesti per l'operazione - richiesta. \item[\errcode{ENOSYS}] il supporto per \texttt{printk} non è stato compilato nel kernel. + \item[\errcode{EPERM}] non si hanno i privilegi richiesti per l'operazione + richiesta. + \item[\errcode{ERESTARTSYS}] l'operazione è stata interrotta da un segnale. \end{errlist} } \end{funcproto} diff --git a/socket.tex b/socket.tex index 51afca6..afde744 100644 --- a/socket.tex +++ b/socket.tex @@ -293,10 +293,30 @@ seguenti costanti:\footnote{le pagine di manuale POSIX riportano solo i primi pertanto non ne parleremo ulteriormente.} \end{basedescript} -Si tenga presente che non tutte le combinazioni fra una famiglia di protocolli -e un tipo di socket sono valide, in quanto non è detto che in una famiglia -esista un protocollo per ciascuno dei diversi stili di comunicazione appena -elencati. +A partire dal kernel 2.6.27 l'argomento \param{type} della funzione +\func{socket} assume un significato ulteriore perché può essere utlizzato per +impostare dei flag relativi alle caratteristiche generali del \textit{socket} +non strettamente attinenti all'indicazione del tipo secondo i valori appena +illustrati. Essi infatti possono essere combinati con un OR aritmetico delle +ulteriori costanti: +\begin{basedescript}{\desclabelwidth{2.9cm}\desclabelstyle{\nextlinelabel}} +\item[\const{SOCK\_CLOEXEC}] imposta il flag di \textit{close-on-exec} + \itindex{close-on-exec} sul file descriptor del socket, ottenendo lo stesso + effetto del flag \const{O\_CLOEXEC} di \func{open} (vedi + tab.~\ref{tab:open_operation_flag}), di cui costituisce l'analogo. + +\item[\const{SOCK\_NONBLOCK}] crea il socket in modalità non-bloccante, con + effetti identici ad una successiva chiamata a \func{fcntl} per impostare il + flag di \const{O\_NONBLOCK} sul file descriptor (si faccia di nuovo + riferimenti al significato di quest'ultimo come spiegato in + tab.~\ref{tab:open_operation_flag}). +\end{basedescript} + + +Si tenga presente inoltre che non tutte le combinazioni fra una famiglia di +protocolli e un tipo di socket sono valide, in quanto non è detto che in una +famiglia esista un protocollo per ciascuno dei diversi stili di comunicazione +appena elencati. \begin{table}[htb] \footnotesize diff --git a/sources/IPCTestId.c b/sources/IPCTestId.c index 2cbbf4d..94ce916 100644 --- a/sources/IPCTestId.c +++ b/sources/IPCTestId.c @@ -50,7 +50,7 @@ int main(int argc, char *argv[]) * Variables definition */ int i; - int n = 5; /* default is 10 tryes */ + int n = 3; /* default is 3 times */ char type='q'; /* default is use queues */ int id; /* -- 2.30.2