+%% ipc.tex
+%%
+%% Copyright (C) 2000-2002 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 "Prefazione",
+%% with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the
+%% license is included in the section entitled "GNU Free Documentation
+%% License".
+%%
\chapter{La comunicazione fra processi}
\label{cha:IPC}
\param{protocol} derivano dall'interfaccia dei socket (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
-\macro{AF\_UNIX}, \macro{SOCK\_STREAM} e \macro{0}.
+\macro{AF\_UNIX}, \macro{SOCK\_STREAM} e \var{0}.
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
Il primo difetto è che non esiste una funzione che permetta di creare ed
inizializzare un semaforo in un'unica chiamata; occorre prima creare l'insieme
dei semafori con \func{semget} e poi inizializzarlo con \func{semctl}, si
-perde così ogni possibilità di eseguire atomicamente questa operazione.
+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
\param{semid} o sul singolo semaforo di un insieme, specificato da
\param{semnum}.
-Qualora la funzione operi con quattro argomenti \param{arg} è
-un argomento generico, che conterrà un dato diverso a seconda dell'azione
-richiesta; per unificare l'argomento esso deve essere passato come una
-\var{union semun}, la cui definizione, con i possibili valori che può
-assumere, è riportata in \figref{fig:ipc_semun}.
-
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
\label{fig:ipc_semun}
\end{figure}
+Qualora la funzione operi con quattro argomenti \param{arg} è
+un argomento generico, che conterrà un dato diverso a seconda dell'azione
+richiesta; per unificare l'argomento esso deve essere passato come una
+\var{union semun}, la cui definizione, con i possibili valori che può
+assumere, è riportata in \figref{fig:ipc_semun}.
+
Come già accennato sia il comportamento della funzione che il numero di
parametri con cui deve essere invocata, dipendono dal valore dell'argomento
\param{cmd}, che specifica l'azione da intraprendere; i valori validi (che
Come esempio di uso dell'interfaccia dei semafori vediamo come implementare
con essa dei semplici \textit{mutex} (cioè semafori binari), tutto il codice
-in questione, contenuto nel file \file{wrappers.h} allegato ai sorgenti, è
+in questione, contenuto nel file \file{Mutex.c} allegato ai sorgenti, è
riportato in \figref{fig:ipc_mutex_create}. Utilizzeremo l'interfaccia per
creare un insieme contenente un singolo semaforo, per il quale poi useremo un
valore unitario per segnalare la disponibilità della risorsa, ed un valore
/*
* Function MutexCreate: create a mutex/semaphore
*/
-inline int MutexCreate(key_t ipc_key)
+int MutexCreate(key_t ipc_key)
{
const union semun semunion={1}; /* semaphore union structure */
int sem_id, ret;
/*
* Function MutexFind: get the semaphore/mutex Id given the IPC key value
*/
-inline int MutexFind(key_t ipc_key)
+int MutexFind(key_t ipc_key)
{
return semget(ipc_key,1,0);
}
/*
* Function MutexRead: read the current value of the mutex/semaphore
*/
-inline int MutexRead(int sem_id)
+int MutexRead(int sem_id)
{
return semctl(sem_id, 0, GETVAL);
}
struct sembuf sem_ulock={ /* to unlock semaphore */
0, /* semaphore number (only one so 0) */
1, /* operation (1 to release resource) */
- SEM_UNO}; /* flag (in this case 0) */
+ SEM_UNDO}; /* flag (in this case 0) */
/*
* Function MutexLock: to lock a mutex/semaphore
*/
-inline int MutexLock(int sem_id)
+int MutexLock(int sem_id)
{
return semop(sem_id, &sem_lock, 1);
}
/*
* Function MutexUnlock: to unlock a mutex/semaphore
*/
-inline int MutexUnlock(int sem_id)
+int MutexUnlock(int sem_id)
{
return semop(sem_id, &sem_ulock, 1);
}
strutture \var{sem\_lock} e \var{sem\_unlock} definite in precedenza
(\texttt{\small 32--42}). Si noti come per queste ultime si sia fatto uso
dell'opzione \macro{SEM\_UNDO} per evitare che il semaforo resti bloccato in
-caso di terminazione imprevista del processo. Si noti infine come, essendo
-tutte le funzioni riportate in \figref{fig:ipc_mutex_create} estremamente
-semplici, se si sono definite tutte come \ctyp{inline}.\footnote{la direttiva
- \func{inline} viene usata per dire al compilatore di non trattare la
- funzione cui essa fa riferimento come una funzione, ma di inserire il codice
- direttamente nel testo del programma. Anche se i compilatori più moderni
- sono in grado di effettuare da soli queste manipolazioni (impostando le
- opportune ottimizzazioni) questa è una tecnica usata per migliorare le
- prestazioni per le funzioni piccole ed usate di frequente, in tal caso
- infatti le istruzioni per creare un nuovo frame nello stack per chiamare la
- funzione costituirebbero una parte rilevante del codice, appesantendo
- inutilmente il programma. Originariamente questa era fatto utilizzando delle
- macro, ma queste hanno tutta una serie di problemi di sintassi nel passaggio
- degli argomenti (si veda ad esempio \cite{PratC} che in questo modo possono
- essere evitati.}
+caso di terminazione imprevista del processo.%% Si noti infine come, essendo
+%% tutte le funzioni riportate in \figref{fig:ipc_mutex_create} estremamente
+%% semplici, se si sono definite tutte come \ctyp{inline}.\footnote{la direttiva
+%% \func{inline} viene usata per dire al compilatore di non trattare la
+%% funzione cui essa fa riferimento come una funzione, ma di inserire il codice
+%% direttamente nel testo del programma. Anche se i compilatori più moderni
+%% sono in grado di effettuare da soli queste manipolazioni (impostando le
+%% opportune ottimizzazioni) questa è una tecnica usata per migliorare le
+%% prestazioni per le funzioni piccole ed usate di frequente, in tal caso
+%% infatti le istruzioni per creare un nuovo frame nello stack per chiamare la
+%% funzione costituirebbero una parte rilevante del codice, appesantendo
+%% inutilmente il programma. Originariamente questa era fatto utilizzando delle
+%% macro, ma queste hanno tutta una serie di problemi di sintassi nel passaggio
+%% degli argomenti (si veda ad esempio \cite{PratC} che in questo modo possono
+%% essere evitati.}
Chiamare \func{MutexLock} decrementa il valore del semaforo: se questo è
-
-
\subsection{Memoria condivisa}
\label{sec:ipc_sysv_shm}
non abbia completato le operazioni di scrittura, inoltre nel corso di una
lettura si deve essere sicuri che i dati restano coerenti e non vengono
sovrascritti da un accesso in scrittura sullo stesso segmento da parte di un
-altro processo; per questo in genere la memoria condivisa viene sempre
+altro processo. Per questo in genere la memoria condivisa viene sempre
utilizzata in abbinamento ad un meccanismo di sincronizzazione, il che, di
norma, significa insieme a dei semafori.
inizializzato al valore di \param{size}.
\item il campo \var{shm\_ctime}, che esprime il tempo di creazione del
segmento, viene inizializzato al tempo corrente.
-\item i campi \var{shm\_atime} e \var{shm\_atime}, che esprimono
+\item i campi \var{shm\_atime} e \var{shm\_dtime}, che esprimono
rispettivamente il tempo dell'ultima volta che il segmento è stato
agganciato o sganciato da un processo, vengono inizializzati a zero.
\item il campo \var{shm\_lpid}, che esprime il \acr{pid} del processo che ha
\end{itemize*}
Come per le code di messaggi e gli insiemi di semafori, anche per i segmenti
-di memoria condivisa esistono una serie di limiti, i cui valori, riportati in
-\tabref{tab:ipc_shm_limits} sono associati ad altrettante costanti. Alcuni di
-questi limiti sono al solito accessibili e modificabili attraverso
+di memoria condivisa esistono una serie di limiti imposti dal sistema. Alcuni
+di questi limiti sono al solito accessibili e modificabili attraverso
\func{sysctl} o scrivendo direttamente nei rispettivi file di
-\file{/proc/sys/kernel/}.
+\file{/proc/sys/kernel/}. In \tabref{tab:ipc_shm_limits} si sono riportate le
+costanti simboliche associate a ciascuno di essi, il loro significato, i
+valori preimpostati, e, quando presente, il file in \file{/proc/sys/kernel/}
+che permettono di cambiarne il valore.
+
\begin{table}[htb]
\footnotesize
& \textbf{Significato} \\
\hline
\hline
- \macro{SHMALL}&0x200000&\file{shmall}& Numero massimo di pagine che
+ \macro{SHMALL}& 0x200000&\file{shmall}& Numero massimo di pagine che
possono essere usate per i segmenti di
memoria condivisa. \\
\macro{SHMMAX}&0x2000000&\file{shmmax}& Dimensione massima di un segmento
- di memoria condivisa.\\
- \macro{SHMMNI}&4096&\file{msgmni}& Numero massimo di segmenti di memoria
- condivisa presenti nel kernel.\\
- \macro{SHMMIN}& 1& --- & Dimensione minima di un segmento di
- memoria condivisa. \\
+ di memoria condivisa.\\
+ \macro{SHMMNI}& 4096&\file{msgmni}& Numero massimo di segmenti di
+ memoria condivisa presenti nel
+ kernel.\\
+ \macro{SHMMIN}& 1& --- & Dimensione minima di un segmento di
+ memoria condivisa. \\
+ \macro{SHMLBA}&\macro{PAGE\_SIZE}&--- & Limite inferiore per le dimensioni
+ minime di un segmento (deve essere
+ allineato alle dimensioni di una
+ pagina di memoria). \\
+ \macro{SHMSEG}& --- & --- & Numero massimo di segmenti di
+ memoria condivisa
+ per ciascun processo.\\
+
+
\hline
\end{tabular}
\caption{Valori delle costanti associate ai limiti dei segmenti di memoria
\item[\macro{IPC\_RMID}] Marca il segmento di memoria condivisa per la
rimozione, questo verrà cancellato effettivamente solo quando l'ultimo
processo ad esso agganciato si sarà staccato. Questo comando può essere
- eseguito solo da un processo con userid effettivo, corrispondente al
- creatore o al proprietario della coda, o all'amministratore.
+ eseguito solo da un processo con userid effettivo corrispondente o al
+ creatore della coda, o al proprietario della coda, o all'amministratore.
\item[\macro{IPC\_SET}] Permette di modificare i permessi ed il proprietario
del segmento. Per modificare i valori di \var{shm\_perm.mode},
\var{shm\_perm.uid} e \var{shm\_perm.gid} occorre essere il proprietario o
il creatore della coda, oppure l'amministratore. Compiuta l'operazione
aggiorna anche il valore del campo \var{shm\_ctime}.
\item[\macro{SHM\_LOCK}] Abilita il \textit{memory locking}\index{memory
- locking} (vedi \secref{sec:proc_mem_lock}) sul segmento di memoria
+ locking}\footnote{impedisce cioè che la memoria usata per il segmento
+ venga salvata su disco dal meccanismo della memoria virtuale; si ricordi
+ quanto trattato in \secref{sec:proc_mem_lock}.} sul segmento di memoria
condivisa. Solo l'amministratore può utilizzare questo comando.
-\item[\macro{SHM\_UNLOCK}] Disabilita il \textit{memory locking}. Solo
- l'amministratore può utilizzare questo comando.
+\item[\macro{SHM\_UNLOCK}] Disabilita il \textit{memory locking} sul segmento
+ di memoria condivisa. Solo l'amministratore può utilizzare questo comando.
\end{basedescript}
i primi tre comandi sono gli stessi già visti anche per le code ed i semafori,
gli ultimi due sono delle estensioni previste da Linux.
spazio di indirizzi del processo, in modo che questo possa accedervi
direttamente, la situazione dopo l'esecuzione di \func{shmat} è illustrata in
\figref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si
-ricordi quanto illustrato al proposito in \secref{sec:proc_mem_layout}). Si
-tenga presente che la funzione ha successo anche se il segmento è stato
+ricordi quanto illustrato al proposito in \secref{sec:proc_mem_layout}). In
+particolare l'indirizzo finale del segmento dati (quello impostato da
+\func{brk}, vedi \secref{sec:proc_mem_sbrk}) non viene influenzato. Si tenga
+presente infine che la funzione ha successo anche se il segmento è stato
marcato per la cancellazione.
\begin{figure}[htb]
Altrimenti il kernel aggancia il segmento all'indirizzo specificato da
\param{shmaddr}; questo però può avvenire solo se l'indirizzo coincide con il
limite di una pagina, cioè se è un multiplo esatto del parametro di sistema
-\macro{SHMLBA}, che in Linux è sempre uguale \macro{PAGE\_SIZE}.
+\macro{SHMLBA}, che in Linux è sempre uguale \macro{PAGE\_SIZE}.
+
+Si tenga presente però che quando si usa \macro{NULL} come valore di
+\param{shmaddr}, l'indirizzo restituito da \func{shmat} può cambiare da
+processo a processo; pertanto se nell'area di memoria condivisa si salvano
+anche degli indirizzi, si deve avere cura di usare valori relativi (in genere
+riferiti all'indirizzo di partenza del segmento).
L'argomento \param{shmflg} permette di cambiare il comportamento della
funzione; esso va specificato come maschera binaria, i bit utilizzati sono
un valore qualunque per \param{shmaddr}, e il segmento verrà comunque
agganciato, ma al più vicino multiplo di \macro{SHMLBA} (il nome della
costante sta infatti per \textit{rounded}, e serve per specificare un
-indirizzo come arrotondamento).
+indirizzo come arrotondamento, in Linux è equivalente a \macro{PAGE\_SIZE}).
-Il secondo bit permette di agganciare il segmento in sola lettura (si ricordi
-che anche le pagine di memoria hanno dei permessi), in tal caso un tentativo
-di scrivere sul segmento comporterà una violazione di accesso con l'emissione
-di un segnale di \macro{SIGSEGV}. Il comportamento usuale di \func{shmat} è
-quello di agganciare il segmento con l'accesso in lettura e scrittura (ed il
-processo deve aver questi permessi in \var{shm\_perm}), non è prevista la
-possibilità di agganciare un segmento in sola scrittura.
+L'uso di \macro{SHM\_RDONLY} permette di agganciare il segmento in sola
+lettura (si ricordi che anche le pagine di memoria hanno dei permessi), in tal
+caso un tentativo di scrivere sul segmento comporterà una violazione di
+accesso con l'emissione di un segnale di \macro{SIGSEGV}. Il comportamento
+usuale di \func{shmat} è quello di agganciare il segmento con l'accesso in
+lettura e scrittura (ed il processo deve aver questi permessi in
+\var{shm\_perm}), non è prevista la possibilità di agganciare un segmento in
+sola scrittura.
In caso di successo la funzione aggiorna anche i seguenti campi di
\var{shmid\_ds}:
automaticamente sganciati. Lo stesso avviene all'uscita del processo
attraverso una \func{exit}.
-
Una volta che un segmento di memoria condivisa non serve più, si può
sganciarlo esplicitamente dal processo usando l'altra funzione
dell'interfaccia, \func{shmdt}, il cui prototipo è:
restituito dalla precedente chiamata a \func{shmat} con il quale era stato
agganciato al processo.
-Per capire meglio il funzionamento delle funzioni facciamo ancora una volta
-riferimento alle strutture con cui il kernel implementa i segmenti di memoria
-condivisa; uno schema semplificato della struttura è illustrato in
-\figref{fig:ipc_shm_struct}.
+In caso di successo la funzione aggiorna anche i seguenti campi di
+\var{shmid\_ds}:
+\begin{itemize*}
+\item il tempo \var{shm\_dtime} dell'ultima operazione di sganciamento viene
+ impostato al tempo corrente.
+\item il \acr{pid} \var{shm\_lpid} dell'ultimo processo che ha operato sul
+ segmento viene impostato a quello del processo corrente.
+\item il numero \var{shm\_nattch} di processi agganciati al segmento viene
+ decrementato di uno.
+\end{itemize*}
+inoltre la regione di indirizzi usata per il segmento di memoria condivisa
+viene tolta dallo spazio di indirizzi del processo.
+
-\begin{figure}[htb]
- \centering
- \includegraphics[width=10cm]{img/shmstruct}
- \caption{Schema dell'implementazione dei segmenti di memoria condivisa in
- Linux.}
- \label{fig:ipc_shm_struct}
-\end{figure}
+%% Per capire meglio il funzionamento delle funzioni facciamo ancora una volta
+%% riferimento alle strutture con cui il kernel implementa i segmenti di memoria
+%% condivisa; uno schema semplificato della struttura è illustrato in
+%% \figref{fig:ipc_shm_struct}.
+
+%% \begin{figure}[htb]
+%% \centering
+%% \includegraphics[width=10cm]{img/shmstruct}
+%% \caption{Schema dell'implementazione dei segmenti di memoria condivisa in
+%% Linux.}
+%% \label{fig:ipc_shm_struct}
+%% \end{figure}
\section{Tecniche alternative}
\label{sec:ipc_alternatives}
-Come abbiamo visto in \secref{sec:ipc_sysv_generic} il \textit{SysV IPC}
+Come abbiamo detto in \secref{sec:ipc_sysv_generic}, e ripreso nella
+descrizione dei signoli oggetti che ne fan parte, il \textit{SysV IPC}
presenta numerosi problemi; in \cite{APUE}\footnote{in particolare nel
- capitolo 14.} Stevens effettua una accurata analisi (alcuni dei concetti
-sono già stati accennati in precedenza) ed elenca alcune possibili
-alternative, che vogliamo riprendere in questa sezione.
+ capitolo 14.} Stevens ne eeffettua una accurata analisi (alcuni dei
+concetti sono già stati accennati in precedenza) ed elenca alcune possibili
+tecniche alternative, che vogliamo riprendere in questa sezione.
\subsection{Alternative alle code di messaggi}
-\subsection{La sincronizzazione con il \textit{file locking}}
+\subsection{I \textsl{file di lock}}
\label{sec:ipc_file_lock}
Come illustrato in \secref{sec:ipc_sysv_sem} i semafori del \textit{SysV IPC}
tecnica possa non funzionare; in particolare per Linux, nel caso di NFS, si
è comunque soggetti alla possibilità di una race condition.} che essa
ritorni un errore quando usata con i flag di \macro{O\_CREAT} e
-\macro{O\_EXCL}. In tal modo la creazione di un file di lock può essere
-eseguita atomicamente, il processo che crea il file con successo si può
+\macro{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}.\footnote{abbiamo già accennato in \secref{sec:file_open} che
- questa tecnica può non funzionare se il filesystem su cui si va ad operare è
- su NFS; in tal caso si può adottare una tecnica alternativa che prevede
- l'uso di \func{link} per creare come file di lock un hard link ad un file
- esistente; se il link esiste già e la funzione fallisce, significa che la
- risorsa è bloccata e potrà essere sbloccata solo con un \func{unlink},
- altrimenti il link è creato ed il lock acquisito; il controllo e l'eventuale
- acquisizione sono atomici; il difetto di questa soluzione è che funziona
- solo se si opera all'interno di uno stesso filesystem.}
-
-L'uso di un file di lock presenta però parecchi problemi, che non lo rendono
-una alternativa praticabile per la sincronizzazione:\footnote{ma può essere
- una tecnica usata con successo quando l'esigenza è solo quella di segnalare
- l'occupazione di una risorsa, senza necessità di attendere che questa si
- liberi; ad esempio la si usa spesso per evitare interferenze sull'uso delle
- porte seriali da parte di 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.} anzitutto anche in questo caso in caso di
-terminazione imprevista del processo lascia allocata la risorsa (il file di
-lock) e questa deve essere sempre cancellata esplicitamente. Inoltre il
-controllo della disponibilità può essere fatto solo con una tecnica di
-\textit{polling}\index{polling}, che è molto inefficiente.
-
-Per questo motivo la tecnica alternativa più pulita è quella di fare ricorso
-al \textit{file locking} trattato in \secref{sec:file_locking} ed utilizzare
-\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
-\textit{polling}\index{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.
+il rilascio si può eseguire con una chiamata ad \func{unlink}.
-Questo approccio presenta il notevole vantaggio che alla terminazione di un
-processo tutti i lock acquisiti vengono rilasciati automaticamente (alla
-chiusura dei relativi file) e non ci si deve preoccupare di niente, e non
-consuma risorse permanentemente allocate nel sistema, lo svantaggio è che
-dovendo fare ricorso a delle operazioni sul filesystem esso è in genere
-leggermente più lento.
+Un esempio dell'uso di questa funzione è mostrato dalle funzioni
+\func{LockFile} ed \func{UnlockFile} riportate in \figref{fig:ipc_file_lock}
+(sono contenute in \file{LockFile.c}, un'altro dei sorgenti allegati alla
+guida) che permettono rispettivamente di creare e rimuovere un \textsl{file di
+ lock}. Come si può notare entrambe le funzioni sono elementari; la prima
+(\texttt{\small 4--10}) si limita ad aprire il file di lock (\texttt{\small
+ 9}) nella modalità descritta, mentre la seconda (\texttt{\small 11--17}) lo
+cancella con \func{unlink}.
-Il codice per implementare un mutex utilizzando il file locking è riportato in
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h> /* unix standard functions */
+/*
+ * Function LockFile:
+ */
+int LockFile(const char* path_name)
+{
+ return open(path_name, O_EXCL|O_CREAT);
+}
+/*
+ * Function UnlockFile:
+ */
+int UnlockFile(const char* path_name)
+{
+ return unlink(path_name);
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Il codice delle funzioni \func{LockFile} e \func{UnlockFile} che
+ permettono di creare e rimuovere un \textsl{file di lock}.}
+ \label{fig:ipc_file_lock}
+\end{figure}
+Uno dei limiti di questa tecnica è che, come abbiamo già accennato in
+\secref{sec:file_open}, questo comportamento di \func{open} può non funzionare
+(la funzione viene eseguita, ma non è garantita l'atomicità dell'operazione)
+se il filesystem su cui si va ad operare è su NFS; in tal caso si può adottare
+una tecnica alternativa che prevede l'uso della \func{link} per creare come
+file di lock un hard link ad un file esistente; se il link esiste già e la
+funzione fallisce, significa che la risorsa è bloccata e potrà essere
+sbloccata solo con un \func{unlink}, altrimenti il link è creato ed il lock
+acquisito; il controllo e l'eventuale acquisizione sono atomici; la soluzione
+funziona anche su NFS, ma ha un'altro difetto è che è quello di poterla usare
+solo se si opera all'interno di uno stesso filesystem.
+
+Un generale comunque l'uso di un \textsl{file di lock} presenta parecchi
+problemi, che non lo rendono una alternativa praticabile per la
+sincronizzazione: anzitutto anche in questo caso, in caso di terminazione
+imprevista del processo, si lascia allocata la risorsa (il file di lock) e
+questa deve essere sempre cancellata esplicitamente. Inoltre il controllo
+della disponibilità può essere eseguito solo con una tecnica di
+\textit{polling}\index{polling}, ed è quindi molto inefficiente.
+
+La tecnica dei file di lock non di meno ha una sua utilità, e può essere usata
+con successo quando l'esigenza è solo quella di segnalare l'occupazione di una
+risorsa, senza necessità di attendere che questa si liberi; ad esempio la si
+usa spesso per evitare interferenze sull'uso delle porte seriali da parte di
+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.
+\subsection{La sincronizzazione con il \textit{file locking}}
+\label{sec:ipc_lock_file}
+
+Dato che i file di lock presentano gli inconvenienti illustrati in precedenza,
+la tecnica alternativa più comune è quella di fare ricorso al \textit{file
+ locking} (trattato in \secref{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 \textit{polling}\index{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
+chiusura dei relativi file) e non ci si deve preoccupare di niente, inoltre
+non consuma risorse permanentemente allocate nel sistema, lo svantaggio è che
+dovendo fare ricorso a delle operazioni sul filesystem esso è in genere
+leggermente più lento.
-\subsection{Il \textit{memory mapping} anonimo}
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+/*
+ * Function LockMutex: lock a file (creating it if not existent).
+ */
+int LockMutex(const char *path_name)
+{
+ int fd, res;
+ struct flock lock; /* file lock structure */
+ /* first open the file (creating it if not existent) */
+ if ( (fd = open(path_name, O_EXCL|O_CREAT)) < 0) { /* first open file */
+ return fd;
+ }
+ /* set flock structure */
+ lock.l_type = F_WRLCK; /* set type: read or write */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = 0; /* set the start of the locked region */
+ lock.l_len = 0; /* set the length of the locked region */
+ /* do locking */
+ if ( (res = fcntl(fd, F_SETLKW, &lock)) < 0 ) {
+ return res;
+ }
+ return 0;
+}
+/*
+ * Function UnLockMutex: unlock a file.
+ */
+int UnlockMutex(const char *path_name)
+{
+ int fd, res;
+ struct flock lock; /* file lock structure */
+ /* first open the file */
+ if ( (fd = open(path_name, O_RDWR)) < 0) { /* first open file */
+ return fd;
+ }
+ /* set flock structure */
+ lock.l_type = F_UNLCK; /* set type: unlock */
+ lock.l_whence = SEEK_SET; /* start from the beginning of the file */
+ lock.l_start = 0; /* set the start of the locked region */
+ lock.l_len = 0; /* set the length of the locked region */
+ /* do locking */
+ if ( (res = fcntl(fd, F_SETLK, &lock)) < 0 ) {
+ return res;
+ }
+ return 0;
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Il codice delle funzioni che permettono di creare un
+ \textit{mutex} utilizzando il file locking.}
+ \label{fig:ipc_flock_mutex}
+\end{figure}
+
+Il codice per implementare un mutex utilizzando il file locking è riportato in
+\figref{fig:ipc_flock_mutex}; a differenza del precedente caso in cui si sono
+usati i semafori le funzioni questa volta sono sufficienti due funzioni,
+\func{LockMutex} e \func{UnlockMutex}, usate rispettivamente per acquisire e
+rilasciare il mutex.
+
+La prima funzione (\texttt{\small 1--22}) serve per acquisire il mutex.
+Anzitutto si apre (\texttt{\small 9--11}), creandolo se non esiste, il file
+specificato dall'argomento \param{pathname}. In caso di errore si ritorna
+immediatamente, altrimenti si prosegue impostando (\texttt{\small 12--16}) la
+struttura \var{lock} in modo da poter acquisire un write lock sul file. Infine
+si richiede (\texttt{\small 17--20}) il file lock (restituendo il codice di
+ritorno di \func{fcntl} caso di errore). Se il file è libero il lock è
+acquisito e la funzione ritorna immediatamente; altrimenti \func{fcntl} si
+bloccherà (si noti che la si è chiamata con \func{F\_SETLKW}) fino al rilascio
+del lock.
+
+La seconda funzione (\texttt{\small 23--44}) serve a rilasciare il mutex. Di
+nuovo si apre (\texttt{\small 30--33}) il file specificato dall'argomento
+\param{pathname} (che stavolta deve esistere), ritornando immediatamente in
+caso di errore. Poi si passa ad inizializzare (\texttt{\small 34--38}) la
+struttura \var{lock} per il rilascio del lock, che viene effettuato
+(\texttt{\small 39--42}) subito dopo.
+
+ \subsection{Il \textit{memory mapping} anonimo}
\label{sec:ipc_mmap_anonymous}
-Abbiamo visto in \secref{sec:file_memory_map} come sia possibile mappare il
-contenuto di un file nella memoria di un processo. Una della opzioni possibili
-utilizzabili con Linux è quella del \textit{memory mapping}
-anonimo\footnote{in altri sistemi una funzionalità simile a questa viene
- implementata mappando il file speciale \file{/dev/zero}.}, in tal caso
-infatti
+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.
+
+Abbiamo visto in \secref{sec:file_memory_map} che è possibile mappare il
+contenuto di un file nella memoria di un processo, e che, quando viene usato
+il flag \macro{MAP\_SHARED}, le modifiche effettuate al contenuto del file
+vengono viste da tutti i processi che lo hanno mappato. Utilizzare questa
+tecnica per creare una memoria condivisa fra processi diversi è estremamente
+inefficiente, in quanto occorre passare attraverso il disco. Però abbiamo
+visto anche che se si esegue la mappatura con il flag \macro{MAP\_ANONYMOUS}
+la regione mappata non viene associata a nessun file, anche se quanto scritto
+rimane in memoria e può essere riletto; allora, dato che un processo figlio
+mantiene nel suo spazio degli indirizzi anche le regioni mappate, esso sarà
+anche in grado di accedere a quanto in esse è contenuto.
+
+In questo modo diventa possibile creare una memoria condivisa fra processi
+diversi, purché questi abbiano almeno un progenitore comune che ha effettuato
+il \textit{memory mapping} anonimo.\footnote{nei sistemi derivati da SysV una
+ funzionalità simile a questa viene implementata mappando il file speciale
+ \file{/dev/zero}. In tal caso i valori scritti nella regione mappata non
+ vengono ignorati (come accade qualora si scriva direttamente sul file), ma
+ restano in memoria e possono essere riletti secondo le stesse modalità usate
+ nele \textit{memory mapping} anonimo.} Un esempio di utilizzo di questa
+tecnica è mostrato in
+
\section{La comunicazione fra processi di POSIX}
Il Linux non tutti gli oggetti del POSIX IPC sono supportati nel kernel
ufficiale; solo la memoria condivisa è presente, ma solo a partire dal kernel
-2.4.x, per gli altri oggetti esistono patch e librerie non
-ufficiali. Nonostante questo è importante esaminare questa interfaccia per la
-sua netta superiorità nei confronti di quella del \textit{SysV IPC}.
+2.4.x, per gli altri oggetti esistono patch e librerie non ufficiali.
+Nonostante questo è importante esaminare questa interfaccia per la sua netta
+superiorità nei confronti di quella del \textit{SysV IPC}.
\subsection{Code di messaggi}