Si potrebbe obiettare che sarebbe molto più semplice salvare il risultato
intermedio su un file temporaneo. Questo però non tiene conto del fatto che un
\textit{CGI} può essere eseguito più volte in contemporanea, e si avrebbe una
-evidente \itindex{race~condition} \textit{race condition} in caso di accesso
-simultaneo a detto file da istanze diverse. Il problema potrebbe essere
-superato utilizzando un sempre diverso per il file temporaneo, che verrebbe
-creato all'avvio di ogni istanza, utilizzato dai sottoprocessi, e cancellato
-alla fine della sua esecuzione; ma a questo punto le cose non sarebbero più
-tanto semplici. L'uso di una \textit{pipe} invece permette di risolvere il
-problema in maniera semplice ed elegante, oltre ad essere molto più
-efficiente, dato che non si deve scrivere su disco.
+evidente \textit{race condition} in caso di accesso simultaneo a detto file da
+istanze diverse. Il problema potrebbe essere superato utilizzando un sempre
+diverso per il file temporaneo, che verrebbe creato all'avvio di ogni istanza,
+utilizzato dai sottoprocessi, e cancellato alla fine della sua esecuzione; ma
+a questo punto le cose non sarebbero più tanto semplici. L'uso di una
+\textit{pipe} invece permette di risolvere il problema in maniera semplice ed
+elegante, oltre ad essere molto più efficiente, dato che non si deve scrivere
+su disco.
Il programma ci servirà anche come esempio dell'uso delle funzioni di
duplicazione dei file descriptor che abbiamo trattato in
lettura. Infine è possibile anche usare la \textit{fifo} all'interno di un
solo processo, nel qual caso però occorre stare molto attenti alla possibili
situazioni di stallo: se si cerca di leggere da una \textit{fifo} che non
-contiene dati si avrà infatti un \itindex{deadlock} \textit{deadlock}
-immediato, dato che il processo si blocca e quindi non potrà mai eseguire le
-funzioni di scrittura.
+contiene dati si avrà infatti un \textit{deadlock} immediato, dato che il
+processo si blocca e quindi non potrà mai eseguire le funzioni di scrittura.
Per la loro caratteristica di essere accessibili attraverso il filesystem, è
piuttosto frequente l'utilizzo di una \textit{fifo} come canale di
Verifichiamo allora il comportamento dei nostri programmi, in questo, come in
altri esempi precedenti, si fa uso delle varie funzioni di servizio, che sono
-state raccolte nella libreria \file{libgapil.so}, per poter usare quest'ultima
+state raccolte nella libreria \file{libgapil.so}, e per poterla usare
occorrerà definire la variabile di ambiente \envvar{LD\_LIBRARY\_PATH} in modo
che il linker dinamico possa accedervi.
possono essere specificati sono rispettivamente \const{AF\_UNIX},
\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}).
+A partire dal kernel 2.6.27 la funzione supporta nell'indicazione del tipo di
+socket anche i due flag \const{SOCK\_NONBLOCK} e \const{SOCK\_CLOEXEC}
+(trattati in sez.~\ref{sec:sock_type}), 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
\param{pathname} (che vengono ottenuti attraverso \func{stat}, da cui derivano
i possibili errori), e gli 8 bit meno significativi del numero del dispositivo
su cui è il file. Diventa perciò relativamente facile ottenere delle
-collisioni, specie se i file sono su dispositivi con lo stesso
-\itindex{minor~number} \textit{minor number}, come \file{/dev/hda1} e
-\file{/dev/sda1}.
+collisioni, specie se i file sono su dispositivi con lo stesso \textit{minor
+ number}, come \file{/dev/hda1} e \file{/dev/sda1}.
In genere quello che si fa è utilizzare un file comune usato dai programmi che
devono comunicare (ad esempio un header comune, o uno dei programmi che devono
\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
- 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 uno schema
-semplificato con cui queste strutture vengono mantenute dal kernel. 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 (e non esiste una struttura \struct{msqid\_ds}
-nel kernel), ma abbiamo mantenuto lo schema precedente dato che illustra in
-maniera più che adeguata i principi di funzionamento delle code di messaggi.
+\itindbeg{linked~list}
+
+Una coda di messaggi è costituita da una \textit{linked 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 uno schema semplificato con cui
+queste strutture vengono mantenute dal kernel. 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 (e non esiste una struttura \struct{msqid\_ds} nel kernel), ma
+abbiamo mantenuto lo schema precedente dato che illustra in maniera più che
+adeguata i principi di funzionamento delle code di messaggi.
+
+\itindend{linked~list}
\begin{figure}[!htb]
\centering \includegraphics[width=13cm]{img/mqstruct}
\includestruct{listati/semun.h}
\end{minipage}
\normalsize
- \caption{La definizione dei possibili valori di una \direct{union}
+ \caption{La definizione dei possibili valori di una \dirct{union}
\structd{semun}, usata come quarto argomento della funzione
\func{semctl}.}
\label{fig:ipc_semun}
Il secondo flag aggiuntivo, introdotto a partire dal kernel 2.6.15, è
\const{SHM\_NORESERVE}, ed ha lo stesso scopo del flag \const{MAP\_NORESERVE}
di \func{mmap} (vedi sez.~\ref{sec:file_memory_map}): non vengono riservate
-delle pagine di swap ad uso del meccanismo del \textit{copy on write}
-\itindex{copy~on~write} per mantenere le modifiche fatte sul segmento. Questo
-significa che caso di scrittura sul segmento quando non c'è più memoria
-disponibile, si avrà l'emissione di un \signal{SIGSEGV}.
+delle pagine di swap ad uso del meccanismo del \textit{copy on write} per
+mantenere le modifiche fatte sul segmento. Questo significa che caso di
+scrittura sul segmento quando non c'è più memoria disponibile, si avrà
+l'emissione di un \signal{SIGSEGV}.
Infine l'argomento \param{size} specifica la dimensione del segmento di
memoria condivisa; il valore deve essere specificato in byte, ma verrà
\subsection{I \textsl{file di lock}}
\label{sec:ipc_file_lock}
-\index{file!di lock|(}
+\index{file!di~lock|(}
Come illustrato in sez.~\ref{sec:ipc_sysv_sem} i semafori del \textit{SysV-IPC}
presentano una interfaccia inutilmente complessa e con alcuni difetti
prevede\footnote{questo è quanto dettato dallo standard POSIX.1, ciò non
toglie che in alcune implementazioni questa tecnica possa non funzionare; in
particolare per Linux, nel caso di NFS, si è comunque soggetti alla
- possibilità di una \itindex{race~condition} \textit{race condition}.} che
-essa ritorni un errore quando usata con i flag di \const{O\_CREAT} e
-\const{O\_EXCL}. In tal modo la creazione di un \textsl{file di lock} può
-essere eseguita atomicamente, il processo che crea il file con successo si può
-considerare come titolare del lock (e della risorsa ad esso associata) mentre
-il rilascio si può eseguire con una chiamata ad \func{unlink}.
+ possibilità di una \textit{race condition}.} che essa ritorni un errore
+quando usata con i flag di \const{O\_CREAT} e \const{O\_EXCL}. In tal modo la
+creazione di un \textsl{file di lock} può essere eseguita atomicamente, il
+processo che crea il file con successo si può considerare come titolare del
+lock (e della risorsa ad esso associata) mentre il rilascio si può eseguire
+con una chiamata ad \func{unlink}.
Un esempio dell'uso di questa funzione è mostrato dalle funzioni
\func{LockFile} ed \func{UnlockFile} riportate in fig.~\ref{fig:ipc_file_lock}
più programmi: qualora si trovi un file di lock il programma che cerca di
accedere alla seriale si limita a segnalare che la risorsa non è disponibile.
-\index{file!di lock|)}
+\index{file!di~lock|)}
\subsection{La sincronizzazione con il \textit{file locking}}
\label{sec:ipc_lock_file}
-Dato che i \index{file!di lock} file di lock presentano gli inconvenienti
-illustrati in precedenza, la tecnica alternativa di sincronizzazione più
-comune è quella di fare ricorso al \itindex{file~locking} \textit{file
- locking} (trattato in sez.~\ref{sec:file_locking}) usando \func{fcntl} su un
-file creato per l'occasione per ottenere un write lock. In questo modo potremo
-usare il lock come un \textit{mutex}: per bloccare la risorsa basterà
-acquisire il lock, per sbloccarla basterà rilasciare il lock. Una richiesta
-fatta con un write lock metterà automaticamente il processo in stato di
-attesa, senza necessità di ricorrere al \itindex{polling} \textit{polling} per
-determinare la disponibilità della risorsa, e al rilascio della stessa da
-parte del processo che la occupava si otterrà il nuovo lock atomicamente.
+Dato che i file di lock presentano gli inconvenienti illustrati in precedenza,
+la tecnica alternativa di sincronizzazione più comune è quella di fare ricorso
+al \itindex{file~locking} \textit{file locking} (trattato in
+sez.~\ref{sec:file_locking}) usando \func{fcntl} su un file creato per
+l'occasione per ottenere un write lock. In questo modo potremo usare il lock
+come un \textit{mutex}: per bloccare la risorsa basterà acquisire il lock, per
+sbloccarla basterà rilasciare il lock. Una richiesta fatta con un write lock
+metterà automaticamente il processo in stato di attesa, senza necessità di
+ricorrere al \itindex{polling} \textit{polling} per determinare la
+disponibilità della risorsa, e al rilascio della stessa da parte del processo
+che la occupava si otterrà il nuovo lock atomicamente.
Questo approccio presenta il notevole vantaggio che alla terminazione di un
processo tutti i lock acquisiti vengono rilasciati automaticamente (alla
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 (l'argomento è stato affrontato in
-\ref{sec:sig_semantics}) questa caratteristica non configura una
-\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.
+\ref{sec:sig_semantics}) questa caratteristica non configura una \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
sbloccata, cosicché un altro processo (o \itindex{thread} \textit{thread})
eventualmente bloccato in una \func{sem\_wait} sul semaforo possa essere
svegliato e rimesso in esecuzione. Si tenga presente che la funzione è sicura
-\index{funzioni!sicure} per l'uso all'interno di un gestore di segnali (si
-ricordi quanto detto in sez.~\ref{sec:sig_signal_handler}).
+per l'uso all'interno di un gestore di segnali (si ricordi quanto detto in
+sez.~\ref{sec:sig_signal_handler}).
Se invece di operare su un semaforo se ne volesse semplicemente leggere il
valore, si potrà usare la funzione \funcd{sem\_getvalue}, il cui prototipo è:
A questo punto (\texttt{\small 22}) 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 24-27}) per consentirne l'uso; in
-tutte queste operazioni si provvederà ad uscire dal programma con un opportuno
-messaggio in caso di errore.
+preoccupare di eventuali \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 24-27}) 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})
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}.
+senza incorrere in possibili \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
\end{Console}
%$
-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
+E si noterà come nel momento in cui si lancia \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