X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=491d29d9587f21c3160231b822b2da3ed9481c82;hp=8cb04d0729d192b99e5cd8a52a256432fd771e6e;hb=33a54e1bfa5e62cb90d84c2d5f2d0c53864f6bec;hpb=6da397ead5f7048133f833a45b3799666ddb3f0a diff --git a/ipc.tex b/ipc.tex index 8cb04d0..491d29d 100644 --- a/ipc.tex +++ b/ipc.tex @@ -1,6 +1,6 @@ %% ipc.tex %% -%% Copyright (C) 2000-2010 Simone Piccardi. Permission is granted to +%% Copyright (C) 2000-2011 Simone Piccardi. Permission is granted to %% copy, distribute and/or modify this document under the terms of the GNU Free %% Documentation License, Version 1.1 or any later version published by the %% Free Software Foundation; with the Invariant Sections being "Un preambolo", @@ -3355,7 +3355,7 @@ aggiungendo ad \conffile{/etc/fstab} una riga come: mqueue /dev/mqueue mqueue defaults 0 0 \end{verbatim} ed esso sarà utilizzato come radice sulla quale vengono risolti i nomi delle -code di messaggi che iniziano con una \texttt{/}. Le opzioni di mount +code di messaggi che iniziano con una ``\texttt{/}''. Le opzioni di mount accettate sono \texttt{uid}, \texttt{gid} e \texttt{mode} che permettono rispettivamente di impostare l'utente, il gruppo ed i permessi associati al filesystem. @@ -3374,7 +3374,7 @@ di messaggi POSIX Apre una coda di messaggi POSIX impostandone le caratteristiche. \bodydesc{La funzione restituisce il descrittore associato alla coda in caso - di successo e -1 in caso di errore; nel quel caso \var{errno} assumerà i + di successo e -1 per un errore; nel quel caso \var{errno} assumerà i valori: \begin{errlist} \item[\errcode{EACCES}] il processo non ha i privilegi per accedere al @@ -3395,16 +3395,21 @@ di messaggi POSIX La funzione apre la coda di messaggi identificata dall'argomento \param{name} restituendo il descrittore ad essa associato, del tutto analogo ad un file descriptor, con l'unica differenza che lo standard prevede un apposito tipo -\type{mqd\_t}.\footnote{nella implementazione citata questo è definito come - \ctyp{int}.} Se la coda esiste già il descrittore farà riferimento allo -stesso oggetto, consentendo così la comunicazione fra due processi diversi. +\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. La funzione è del tutto analoga ad \func{open} ed analoghi sono i valori che possono essere specificati per \param{oflag}, che deve essere specificato come maschera binaria; i valori possibili per i vari bit sono quelli visti in tab.~\ref{tab:file_open_flags} dei quali però \func{mq\_open} riconosce solo i seguenti: -\begin{basedescript}{\desclabelwidth{2cm}\desclabelstyle{\nextlinelabel}} +\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}} \item[\const{O\_RDONLY}] Apre la coda solo per la ricezione di messaggi. Il processo potrà usare il descrittore con \func{mq\_receive} ma non con \func{mq\_send}. @@ -3432,13 +3437,14 @@ per i file normali. Se la coda non esiste e la si vuole creare si deve specificare \const{O\_CREAT}, in tal caso occorre anche specificare i permessi di -creazione con l'argomento \param{mode}; i valori di quest'ultimo sono identici -a quelli usati per \func{open}, anche se per le code di messaggi han senso -solo i permessi di lettura e scrittura. Oltre ai permessi di creazione possono -essere specificati anche gli attributi specifici della coda tramite -l'argomento \param{attr}; quest'ultimo è un puntatore ad una apposita -struttura \struct{mq\_attr}, la cui definizione è riportata in -fig.~\ref{fig:ipc_mq_attr}. +creazione con l'argomento \param{mode};\footnote{fino al 2.6.14 per un bug i + valori della \textit{umask} del processo non venivano applicati a questi + permessi.} i valori di quest'ultimo sono identici a quelli usati per +\func{open}, anche se per le code di messaggi han senso solo i permessi di +lettura e scrittura. Oltre ai permessi di creazione possono essere specificati +anche gli attributi specifici della coda tramite l'argomento \param{attr}; +quest'ultimo è un puntatore ad una apposita struttura \struct{mq\_attr}, la +cui definizione è riportata in fig.~\ref{fig:ipc_mq_attr}. \begin{figure}[!htb] \footnotesize \centering @@ -3452,13 +3458,13 @@ fig.~\ref{fig:ipc_mq_attr}. \end{figure} Per la creazione della coda i campi della struttura che devono essere -specificati sono \var{mq\_msgsize} e \var{mq\_maxmsg}, che indicano -rispettivamente la dimensione massima di un messaggio ed il numero massimo di -messaggi che essa può contenere. Il valore dovrà essere positivo e minore dei -rispettivi limiti di sistema \const{MQ\_MAXMSG} e \const{MQ\_MSGSIZE}, -altrimenti la funzione fallirà con un errore di \errcode{EINVAL}. Qualora si -specifichi per \param{attr} un puntatore nullo gli attributi della coda -saranno impostati ai valori predefiniti. +specificati sono \var{mq\_maxmsg} e \var{mq\_msgsize}, che indicano +rispettivamente il numero massimo di messaggi che può contenere e la +dimensione massima di un messaggio. Il valore dovrà essere positivo e minore +dei rispettivi limiti di sistema \const{MQ\_MAXMSG} e \const{MQ\_MSGSIZE}, +altrimenti la funzione fallirà con un errore di \errcode{EINVAL}. +Se \param{attr} è un puntatore nullo gli attributi della coda saranno +impostati ai valori predefiniti. Quando l'accesso alla coda non è più necessario si può chiudere il relativo descrittore con la funzione \funcd{mq\_close}, il cui prototipo è: @@ -3467,8 +3473,8 @@ descrittore con la funzione \funcd{mq\_close}, il cui prototipo Chiude la coda \param{mqdes}. -\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di - errore; nel quel caso \var{errno} assumerà i valori \errval{EBADF} o +\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} @@ -3508,15 +3514,13 @@ coda rester 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). +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. -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 in precedenza 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: +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} @@ -3565,7 +3569,7 @@ Per inserire messaggi su di una coda sono previste due funzioni, \param{abs\_timeout}. - \bodydesc{Le funzioni restituiscono 0 in caso di successo e $-1$ in caso di + \bodydesc{Le funzioni restituiscono 0 in caso di successo e $-1$ per un errore; nel quel caso \var{errno} assumerà i valori: \begin{errlist} \item[\errcode{EAGAIN}] si è aperta la coda con \const{O\_NONBLOCK}, e la @@ -3710,34 +3714,34 @@ Il comportamento di \func{mq\_notify} dipende dal valore dell'argomento \param{notification}, che è un puntatore ad una apposita struttura \struct{sigevent}, (definita in fig.~\ref{fig:struct_sigevent}) introdotta dallo standard POSIX.1b per gestire la notifica di eventi; per altri dettagli -si può vedere quanto detto in sez.~\ref{sec:file_asyncronous_io} a proposito -dell'uso della stessa struttura per l'invio dei segnali usati per l'I/O -asincrono. - -% TODO la notifica non è più limitata al solo uso dei segnali, adesso si -% possono anche usare i thread, correggere!. +si può vedere quanto detto in sez.~\ref{sec:sig_timer_adv} a proposito +dell'uso della stessa struttura per la notifica delle scadenze dei +\textit{timer}. Attraverso questa struttura si possono impostare le modalità con cui viene -effettuata la notifica; in particolare il campo \var{sigev\_notify} deve -essere posto a \const{SIGEV\_SIGNAL}\footnote{il meccanismo di notifica basato - sui \itindex{thread} \textit{thread}, specificato tramite il valore - \const{SIGEV\_THREAD}, non è implementato.} ed il campo \var{sigev\_signo} -deve indicare il valore del segnale che sarà inviato al processo. Inoltre il -campo \var{sigev\_value} è il puntatore ad una struttura \struct{sigval\_t} -(definita in fig.~\ref{fig:sig_sigval}) che permette di restituire al gestore -del segnale un valore numerico o un indirizzo,\footnote{per il suo uso si - riveda la trattazione fatta in sez.~\ref{sec:sig_real_time} a proposito dei - segnali real-time.} posto che questo sia installato nella forma estesa vista -in sez.~\ref{sec:sig_sigaction}. +effettuata la notifica nel campo \var{sigev\_notify}, che può assumere i +valori di tab.~\ref{tab:sigevent_sigev_notify}.\footnote{la pagina di manuale + riporta soltanto i primi tre (inizialmente era possibile solo + \const{SIGEV\_SIGNAL}).} Il metodo consigliato è quello di usare +\const{SIGEV\_SIGNAL} usando il campo \var{sigev\_signo} per indicare il quale +segnale deve essere inviato al processo. Inoltre il campo \var{sigev\_value} è +un puntatore ad una struttura \struct{sigval\_t} (definita in +fig.~\ref{fig:sig_sigval}) che permette di restituire al gestore del segnale +un valore numerico o un indirizzo,\footnote{per il suo uso si riveda la + trattazione fatta in sez.~\ref{sec:sig_real_time} a proposito dei segnali + \textit{real-time}.} posto che questo sia installato nella forma estesa +vista in sez.~\ref{sec:sig_sigaction}. La funzione registra il processo chiamante per la notifica se \param{notification} punta ad una struttura \struct{sigevent} opportunamente inizializzata, o cancella una precedente registrazione se è \val{NULL}. Dato che un solo processo alla volta può essere registrato, la funzione fallisce -con \errcode{EBUSY} se c'è un altro processo già registrato. Si tenga -presente inoltre che alla chiusura del descrittore associato alla coda (e -quindi anche all'uscita del processo) ogni eventuale registrazione di notifica -presente viene cancellata. +con \errcode{EBUSY} se c'è un altro processo già registrato.\footnote{questo + significa anche che se si registra una notifica con \const{SIGEV\_NONE} il + processo non la riceverà, ma impedirà anche che altri possano registrarsi + per poterlo fare.} Si tenga presente inoltre che alla chiusura del +descrittore associato alla coda (e quindi anche all'uscita del processo) ogni +eventuale registrazione di notifica presente viene cancellata. La notifica del segnale avviene all'arrivo di un messaggio in una coda vuota (cioè solo se sulla coda non ci sono messaggi) e se non c'è nessun processo @@ -3754,11 +3758,11 @@ registrazione chiamando nuovamente \func{mq\_notify} all'interno del gestore del segnale di notifica. A differenza della situazione simile che si aveva con i segnali non affidabili,\footnote{l'argomento è stato affrontato in \ref{sec:sig_semantics}.} questa caratteristica non configura una -race-condition perché l'invio di un segnale avviene solo se la coda è vuota; -pertanto se si vuole evitare di correre il rischio di perdere eventuali -ulteriori segnali inviati nel lasso di tempo che occorre per ripetere la -richiesta di notifica basta avere cura di eseguire questa operazione prima di -estrarre i messaggi presenti dalla coda. +\itindex{race~condition} \textit{race condition} perché l'invio di un segnale +avviene solo se la coda è vuota; pertanto se si vuole evitare di correre il +rischio di perdere eventuali ulteriori segnali inviati nel lasso di tempo che +occorre per ripetere la richiesta di notifica basta avere cura di eseguire +questa operazione prima di estrarre i messaggi presenti dalla coda. L'invio del segnale di notifica avvalora alcuni campi di informazione restituiti al gestore attraverso la struttura \struct{siginfo\_t} (definita in @@ -3779,17 +3783,9 @@ forma estesa.\footnote{di nuovo si faccia riferimento a quanto detto al La memoria condivisa è stato il primo degli oggetti di IPC POSIX inserito nel kernel ufficiale; il supporto a questo tipo di oggetti è realizzato attraverso il filesystem \texttt{tmpfs}, uno speciale filesystem che mantiene tutti i -suoi contenuti in memoria,\footnote{il filesystem \texttt{tmpfs} è diverso da - un normale RAM disk, anch'esso disponibile attraverso il filesystem - \texttt{ramfs}, proprio perché realizza una interfaccia utilizzabile anche - per la memoria condivisa; esso infatti non ha dimensione fissa, ed usa - direttamente la cache interna del kernel (che viene usata anche per la - shared memory in stile SysV). In più i suoi contenuti, essendo trattati - direttamente dalla memoria virtuale \index{memoria~virtuale} possono essere - salvati sullo swap automaticamente.} che viene attivato abilitando l'opzione +suoi contenuti in memoria, che viene attivato abilitando l'opzione \texttt{CONFIG\_TMPFS} in fase di compilazione del kernel. - Per potere utilizzare l'interfaccia POSIX per la memoria condivisa le \acr{glibc}\footnote{le funzioni sono state introdotte con le glibc-2.2.} richiedono di compilare i programmi con l'opzione \code{-lrt}; inoltre è @@ -3813,24 +3809,29 @@ questo caso La funzione che permette di aprire un segmento di memoria condivisa POSIX, ed eventualmente di crearlo se non esiste ancora, è \funcd{shm\_open}; il suo prototipo è: -\begin{prototype}{mqueue.h} -{int shm\_open(const char *name, int oflag, mode\_t mode)} +\begin{functions} + \headdecl{sys/mman.h} + \headdecl{sys/stat.h} + \headdecl{fcntl.h} + + \funcdecl{int shm\_open(const char *name, int oflag, mode\_t mode)} -Apre un segmento di memoria condivisa. + Apre un segmento di memoria condivisa. -\bodydesc{La funzione restituisce un file descriptor positivo in caso di - successo e -1 in caso di errore; nel quel caso \var{errno} assumerà gli - stessi valori riportati da \func{open}.} -\end{prototype} + \bodydesc{La funzione restituisce un file descriptor positivo in caso di + successo e -1 in caso di errore; nel quel caso \var{errno} assumerà gli + stessi valori riportati da \func{open}.} +\end{functions} La funzione apre un segmento di memoria condivisa identificato dal nome -\param{name}. Come già spiegato in sez.~\ref{sec:ipc_posix_generic} questo nome -può essere specificato in forma standard solo facendolo iniziare per \file{/} -e senza ulteriori \file{/}, Linux supporta comunque nomi generici, che -verranno interpretati prendendo come radice \file{/dev/shm}.\footnote{occorre - pertanto evitare di specificare qualcosa del tipo \file{/dev/shm/nome} - all'interno di \param{name}, perché questo comporta, da parte delle funzioni - di libreria, il tentativo di accedere a \file{/dev/shm/dev/shm/nome}.} +\param{name}. Come già spiegato in sez.~\ref{sec:ipc_posix_generic} questo +nome può essere specificato in forma standard solo facendolo iniziare per +``\file{/}'' e senza ulteriori ``\file{/}''. Linux supporta comunque nomi +generici, che verranno interpretati prendendo come radice +\file{/dev/shm}.\footnote{occorre pertanto evitare di specificare qualcosa del + tipo \file{/dev/shm/nome} all'interno di \param{name}, perché questo + comporta, da parte delle funzioni di libreria, il tentativo di accedere a + \file{/dev/shm/dev/shm/nome}.} 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 @@ -3874,10 +3875,9 @@ sez.~\ref{sec:file_file_size}), prima di mapparlo in memoria con \func{mmap}. Si tenga presente che una volta chiamata \func{mmap} si può chiudere il file descriptor (con \func{close}), senza che la mappatura ne risenta. - Come per i file, quando si vuole effettivamente rimuovere segmento di memoria condivisa, occorre usare la funzione \funcd{shm\_unlink}, il cui prototipo è: -\begin{prototype}{mqueue.h} +\begin{prototype}{sys/mman.h} {int shm\_unlink(const char *name)} Rimuove un segmento di memoria condivisa. @@ -4360,6 +4360,213 @@ Si tenga presente infine che utilizzare un semaforo che caso ci si trovi in una tale evenienza occorre reinizializzare il semaforo una seconda volta con \func{sem\_init}. +Come esempio di uso sia della memoria condivisa che dei semafori POSIX si sono +scritti due semplici programmi con i quali è possibile rispettivamente +monitorare il contenuto di un segmento di memoria condivisa e modificarne il +contenuto. + +\begin{figure}[!h] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \includecodesample{listati/message_getter.c} + \end{minipage} + \normalsize + \caption{Sezione principale del codice del programma + \file{message\_getter.c}.} + \label{fig:ipc_posix_sem_shm_message_server} +\end{figure} + +Il corpo principale del primo dei due, il cui codice completo è nel file +\file{message\_getter.c} dei sorgenti allegati, è riportato in +fig.~\ref{fig:ipc_posix_sem_shm_message_server}; si è tralasciata la parte che +tratta la gestione delle opzioni a riga di comando (che consentono di +impostare un nome diverso per il semaforo e il segmento di memoria condivisa) +ed il controllo che al programma venga fornito almeno un argomento, contenente +la stringa iniziale da inserire nel segmento di memoria condivisa. + +Lo scopo del programma è quello di creare un segmento di memoria condivisa su +cui registrare una stringa, e tenerlo sotto osservazione stampando la stessa +una volta al secondo. Si utilizzerà un semaforo per proteggere l'accesso in +lettura alla stringa, in modo che questa non possa essere modificata +dall'altro programma prima di averla finita di stampare. + +La parte iniziale del programma contiene le definizioni (\texttt{\small 1--8}) +del gestore del segnale usato per liberare le risorse utilizzate, delle +variabili globali contenenti i nomi di default del segmento di memoria +condivisa e del semaforo (il default scelto è \texttt{messages}), e delle +altre variabili utilizzate dal programma. + +Come prima istruzione (\texttt{\small 10}) si è provveduto ad installare un +gestore di segnale che consentirà di effettuare le operazioni di pulizia +(usando la funzione \func{Signal} illustrata in +fig.~\ref{fig:sig_Signal_code}), dopo di che (\texttt{\small 10--16}) si è +creato il segmento di memoria condivisa con la funzione \func{CreateShm} che +abbiamo appena trattato in sez.~\ref{sec:ipc_posix_shm}, uscendo con un +messaggio in caso di errore. + +Si tenga presente che la funzione \func{CreateShm} richiede che il segmento +non sia già presente e fallirà qualora un'altra istanza, o un altro programma +abbia già allocato un segmento con quello stesso nome. Per semplicità di +gestione si è usata una dimensione fissa pari a 256 byte, definita tramite la +costante \texttt{MSGMAXSIZE}. + +Il passo successivo (\texttt{\small 17--21}) è quello della creazione del +semaforo che regola l'accesso al segmento di memoria condivisa con +\func{sem\_open}; anche in questo caso si gestisce l'uscita con stampa di un +messaggio in caso di errore. Anche per il semaforo, avendo specificato la +combinazione di flag \code{O\_CREAT|O\_EXCL} come secondo argomento, si esce +qualora fosse già esistente; altrimenti esso verrà creato con gli opportuni +permessi specificati dal terzo argomento, (indicante lettura e scrittura in +notazione ottale). Infine il semaforo verrà inizializzato ad un valore nullo +(il quarto argomento), corrispondete allo stato in cui risulta bloccato. + +A questo punto (\texttt{\small 23}) si potrà inizializzare il messaggio posto +nel segmento di memoria condivisa usando la stringa passata come argomento al +programma. Essendo il semaforo stato creato già bloccato non ci si dovrà +preoccupare di eventuali \itindex{race~condition} \textit{race condition} +qualora il programma di modifica del messaggio venisse lanciato proprio in +questo momento. Una volta inizializzato il messaggio occorrerà però +rilasciare il semaforo (\texttt{\small 25--28}) per consentirne l'uso; in +tutte queste operazioni si provvederà ad uscire dal programma con un opportuno +messaggio in caso di errore. + +Una volta completate le inizializzazioni il ciclo principale del programma +(\texttt{\small 29--47}) viene ripetuto indefinitamente (\texttt{\small 29}) +per stampare sia il contenuto del messaggio che una serie di informazioni di +controllo. Il primo passo (\texttt{\small 30--34}) è quello di acquisire (con +\func{sem\_getvalue}, con uscita in caso di errore) e stampare il valore del +semaforo ad inizio del ciclo; seguito (\texttt{\small 35--36}) dal tempo +corrente. + +\begin{figure}[!h] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \includecodesample{listati/HandSigInt.c} + \end{minipage} + \normalsize + \caption{Codice del gestore di segnale del programma + \file{message\_getter.c}.} + \label{fig:ipc_posix_sem_shm_message_server_handler} +\end{figure} + +Prima della stampa del messaggio invece si deve acquisire il semaforo +(\texttt{\small 31--34}) per evitare accessi concorrenti alla stringa da parte +del programma di modifica. Una volta eseguita la stampa (\texttt{\small 41}) +il semaforo dovrà essere rilasciato (\texttt{\small 42--45}). Il passo finale +(\texttt{\small 46}) è attendere per un secondo prima di eseguire da capo il +ciclo. + +Per uscire in maniera corretta dal programma sarà necessario interromperlo con +il break da tastiera (\texttt{C-c}), che corrisponde all'invio del segnale +\const{SIGINT}, per il quale si è installato (\texttt{\small 10}) una +opportuna funzione di gestione, riportata in +fig.~\ref{fig:ipc_posix_sem_shm_message_server_handler}. La funzione è molto +semplice e richiama le funzioni di rimozione sia per il segmento di memoria +condivisa che per il semaforo, garantendo così che possa essere riaperto +ex-novo senza errori in un futuro riutilizzo del comando. + +\begin{figure}[!h] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \includecodesample{listati/message_setter.c} + \end{minipage} + \normalsize + \caption{Sezione principale del codice del programma + \file{message\_setter.c}.} + \label{fig:ipc_posix_sem_shm_message_setter} +\end{figure} + +Il secondo programma di esempio è \file{message\_setter.c}, di cui si è +riportato il corpo principale in +fig.~\ref{fig:ipc_posix_sem_shm_message_setter},\footnote{al solito il codice + completo è nel file dei sorgenti allegati.} dove si è tralasciata, non +essendo significativa per quanto si sta trattando, la parte relativa alla +gestione delle opzioni a riga di comando e degli argomenti, che sono identici +a quelli usati da \file{message\_getter}, con l'unica aggiunta di un'opzione +``\texttt{-t}'' che consente di indicare un tempo di attesa (in secondi) in +cui il programma si ferma tenendo bloccato il semaforo. + +Una volta completata la gestione delle opzioni e degli argomenti (ne deve +essere presente uno solo, contenente la nuova stringa da usare come +messaggio), il programma procede (\texttt{\small 10--14}) con l'acquisizione +del segmento di memoria condivisa usando la funzione \func{FindShm} (trattata +in sez.~\ref{sec:ipc_posix_shm}) che stavolta deve già esistere. Il passo +successivo (\texttt{\small 16--19}) è quello di aprire il semaforo, e a +differenza di \file{message\_getter}, in questo caso si richiede a +\func{sem\_open} che questo esista, passando uno zero come secondo ed unico +argomento. + +Una volta completate con successo le precedenti inizializzazioni, il passo +seguente (\texttt{\small 21--24}) è quello di acquisire il semaforo, dopo di +che sarà possibile eseguire la sostituzione del messaggio (\texttt{\small 25}) +senza incorrere in possibili \itindex{race~condition} \textit{race condition} +con la stampa dello stesso da parte di \file{message\_getter}. + +Una volta effettuata la modifica viene stampato (\texttt{\small 26}) il tempo +di attesa impostato con l'opzione ``\texttt{-t}'' dopo di che (\texttt{\small + 27}) viene eseguita la stessa, senza rilasciare il semaforo che resterà +quindi bloccato (causando a questo punto una interruzione delle stampe +eseguite da \file{message\_getter}). Terminato il tempo di attesa si rilascerà +(\texttt{\small 29--32}) il semaforo per poi uscire. + +Per verificare il funzionamento dei programmi occorrerà lanciare per primo +\file{message\_getter}\footnote{lanciare per primo \file{message\_setter} darà + 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 +sem=1, Fri Dec 31 14:12:41 2010 +message: messaggio +sem=1, Fri Dec 31 14:12:42 2010 +message: messaggio +... +\end{Verbatim} +%$ +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 +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 +Sleeping for 3 seconds +\end{Verbatim} +%$ +dove il programma si fermerà per 3 secondi prima di rilasciare il semaforo e +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} +... +sem=1, Fri Dec 31 14:16:27 2010 +message: messaggio +sem=1, Fri Dec 31 14:16:28 2010 +message: messaggio +sem=0, Fri Dec 31 14:16:29 2010 +message: ciao +sem=1, Fri Dec 31 14:16:32 2010 +message: ciao +sem=1, Fri Dec 31 14:16:33 2010 +message: ciao +... +\end{Verbatim} +%$ + +E si noterà come nel momento in cui si è lanciato \file{message\_setter} le +stampe di \file{message\_getter} si bloccheranno, come corretto, dopo aver +registrato un valore nullo per il semaforo. Il programma infatti resterà +bloccato nella \func{sem\_wait} (quella di riga (\texttt{\small 37}) in +fig.~\ref{fig:ipc_posix_sem_shm_message_server}) fino alla scadenza +dell'attesa di \file{message\_setter} (con l'esecuzione della \func{sem\_post} +della riga (\texttt{\small 29}) di +fig.~\ref{fig:ipc_posix_sem_shm_message_setter}), e riprenderanno con il nuovo +testo alla terminazione di quest'ultimo. + % LocalWords: like fifo System POSIX RPC Calls Common Object Request Brocker % LocalWords: Architecture descriptor kernel unistd int filedes errno EMFILE @@ -4403,15 +4610,20 @@ seconda volta con \func{sem\_init}. % LocalWords: SHARED ANONYMOUS thread patch names strace system call userid Di % LocalWords: groupid Michal Wronski Krzysztof Benedyczak wrona posix mqueue % LocalWords: lmqueue gcc mount mqd name oflag attr maxmsg msgsize receive ptr -% LocalWords: send WRONLY NONBLOCK close mqdes EBADF getattr setattr mqstat +% LocalWords: send WRONLY NONBLOCK close mqdes EBADF getattr setattr mqstat to % LocalWords: omqstat curmsgs flags timedsend len prio timespec abs EMSGSIZE % LocalWords: ETIMEDOUT timedreceive getaddr notify sigevent notification l'I % LocalWords: EBUSY sigev SIGNAL signo value sigval siginfo all'userid MESGQ % LocalWords: Konstantin Knizhnik futex tmpfs ramfs cache shared swap CONFIG % LocalWords: lrt blocks PAGECACHE TRUNC CLOEXEC mmap ftruncate munmap FindShm -% LocalWords: CreateShm RemoveShm LIBRARY Library libmqueue FAILED EACCESS +% LocalWords: CreateShm RemoveShm LIBRARY Library libmqueue FAILED EACCESS has % LocalWords: ENAMETOOLONG qualchenome RESTART trywait XOPEN SOURCE timedwait -% LocalWords: process getvalue sval execve pshared ENOSYS heap PAGE destroy +% LocalWords: process getvalue sval execve pshared ENOSYS heap PAGE destroy it +% LocalWords: xffffffff Arrays owner perms Queues used bytes messages device +% LocalWords: Cannot find such Segments getter Signal MSGMAXSIZE been stable +% LocalWords: for now it's break Berlin sources Let's an accidental feature +% LocalWords: Larry Wall Escape the Hell William ipctestid Identifier segment +% LocalWords: violation dell'I SIGINT setter Fri Dec Sleeping seconds %%% Local Variables: