%% ipc.tex
%%
-%% Copyright (C) 2000-2005 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2007 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",
%% license is included in the section entitled "GNU Free Documentation
%% License".
%%
+
\chapter{La comunicazione fra processi}
\label{cha:IPC}
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} deve poter gestire più richieste in concorrenza, e si avrebbe una
-evidente \textit{race condition}\itindex{race~condition} in caso di accesso
+evidente \itindex{race~condition} \textit{race condition} in caso di accesso
simultaneo a detto file.\footnote{il problema potrebbe essere superato
determinando in anticipo un nome appropriato per il file temporaneo, che
verrebbe utilizzato dai vari sotto-processi, e cancellato alla fine della
POSIX.1 ha definito dei nuovi oggetti, le \textit{fifo}, che hanno le stesse
caratteristiche delle pipe, ma che invece di essere strutture interne del
kernel, visibili solo attraverso un file descriptor, sono accessibili
-attraverso un inode\index{inode} che risiede sul filesystem, così che i
+attraverso un \index{inode} inode che risiede sul filesystem, così che i
processi le possono usare senza dovere per forza essere in una relazione di
\textsl{parentela}.
Utilizzando una \textit{fifo} tutti i dati passeranno, come per le pipe,
attraverso un apposito buffer nel kernel, senza transitare dal filesystem;
-l'inode\index{inode} allocato sul filesystem serve infatti solo a fornire un
+\index{inode} l'inode allocato sul filesystem serve infatti solo a fornire un
punto di riferimento per i processi, che permetta loro di accedere alla stessa
fifo; il comportamento delle funzioni di lettura e scrittura è identico a
quello illustrato per le pipe in sez.~\ref{sec:ipc_pipes}.
lettura; è possibile anche usare la fifo all'interno di un solo processo, nel
qual caso però occorre stare molto attenti alla possibili situazioni di
stallo.\footnote{se si cerca di leggere da una fifo che non contiene dati si
- avrà un deadlock\itindex{deadlock} immediato, dato che il processo si blocca
- e non potrà quindi mai eseguire le funzioni di scrittura.}
+ avrà un \itindex{deadlock} deadlock immediato, dato che il processo si
+ blocca e non potrà quindi mai eseguire le funzioni di scrittura.}
Per la loro caratteristica di essere accessibili attraverso il filesystem, è
piuttosto frequente l'utilizzo di una fifo come canale di comunicazione nelle
occorrerà definire la speciale variabile di ambiente \code{LD\_LIBRARY\_PATH}
in modo che il linker dinamico possa accedervi.
-In generale questa variabile indica il \itindex{pathname}\textit{pathname}
+In generale questa variabile indica il \itindex{pathname} \textit{pathname}
della directory contenente la libreria. Nell'ipotesi (che daremo sempre per
verificata) che si facciano le prove direttamente nella directory dei sorgenti
(dove di norma vengono creati sia i programmi che la libreria), il comando da
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
-\textit{socket}\index{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.
+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.
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 \textit{socket}\index{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
+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 file speciali
-(di tipo \textit{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} è
+(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\index{socket}, appunto),
-senza dover ricorrere ad un 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 è:
+descriptor connessi fra di loro (tramite un socket, appunto), senza dover
+ricorrere ad un 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\index{socket} connessi fra loro.
+ 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:
\begin{errlist}
- \item[\errcode{EAFNOSUPPORT}] I socket\index{socket} locali non sono
- supportati.
+ \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\index{socket}.
+ creazione di coppie di socket.
\end{errlist}
ed inoltre \errval{EMFILE}, \errval{EFAULT}.
}
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
sull'altro e viceversa. Gli argomenti \param{domain}, \param{type} e
-\param{protocol} derivano dall'interfaccia dei socket\index{socket} (vedi
+\param{protocol} derivano dall'interfaccia dei socket (vedi
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}.
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\index{socket} locali in generale) permette di trasmettere attraverso le
-linea non solo dei dati, ma anche dei file descriptor: si può cioè passare da
-un processo ad un altro un file descriptor, con una sorta di duplicazione
-dello stesso non all'interno di uno stesso processo, ma fra processi distinti
-(torneremo su questa funzionalità in sez.~\ref{sec:sock_fd_passing}).
+può sembrare limitata; in realtà l'utilizzo di questa funzione (e dei socket
+locali in generale) permette di trasmettere attraverso le linea non solo dei
+dati, ma anche dei file descriptor: si può cioè passare da un processo ad un
+altro un file descriptor, con una sorta di duplicazione dello stesso non
+all'interno di uno stesso processo, ma fra processi distinti (torneremo su
+questa funzionalità in sez.~\ref{sec:sock_fd_passing}).
\section{Il sistema di comunicazione fra processi di System V}
\end{functions}
La funzione determina un valore della chiave sulla base di \param{pathname},
-che deve specificare il \itindex{pathname}\textit{pathname} di un file
+che deve specificare il \itindex{pathname} \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
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)}
-con i 16 bit meno significativi dell'inode\index{inode} del file
+con i 16 bit meno significativi \index{inode} dell'inode del file
\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
passi elencati non comporta il fallimento dell'accesso. Un'ulteriore
differenza rispetto a quanto avviene per i file è che per gli oggetti di IPC
il valore di \var{umask} (si ricordi quanto esposto in
-sez.~\ref{sec:file_umask}) non ha alcun significato.
+sez.~\ref{sec:file_perm_management}) non ha alcun significato.
\subsection{Gli identificatori ed il loro utilizzo}
\end{figure}
-Una coda di messaggi è costituita da una \itindex{linked~list}\textit{linked
- list};\footnote{una \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.}
+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 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.}
\begin{figure}[!htb]
\footnotesize \centering
funzioni \func{select} e \func{poll}. Questo rende molto scomodo usare più di
una di queste strutture alla volta; ad esempio non si può scrivere un server
che aspetti un messaggio su più di una coda senza fare ricorso ad una tecnica
-di \textit{polling}\itindex{polling} che esegua un ciclo di attesa su
+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
messaggio ricevuto.
Proviamo allora il nostro nuovo sistema, al solito occorre definire
-\code{LD\_LIBRAY\_PATH} per accedere alla libreria \file{libgapil.so}, dopo di
+\code{LD\_LIBRARY\_PATH} per accedere alla libreria \file{libgapil.so}, dopo di
che, in maniera del tutto analoga a quanto fatto con il programma che usa le
fifo, potremo far partire il server con:
\begin{verbatim}
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 inode\index{inode} di un filesystem,
+dedicata ad una coda di messaggi che gli \index{inode} inode di un filesystem,
sia perché, con il riutilizzo dei \acr{pid} da parte dei processi, un client
eseguito in un momento successivo potrebbe ricevere un messaggio non
indirizzato a lui.
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 \textsl{sezioni critiche} \index{sezione~critica} del
-codice (si ricordi quanto detto in sez.~\ref{sec:proc_race_cond}).
+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
Nella struttura viene memorizzato il riferimento alle operazioni richieste
(nel campo \var{sops}, che è un puntatore ad una struttura \struct{sembuf}) e
al processo corrente (nel campo \var{sleeper}) poi quest'ultimo viene messo
-stato di attesa e viene invocato lo scheduler\itindex{scheduler} per passare
+stato di attesa e viene invocato lo \itindex{scheduler} scheduler per passare
all'esecuzione di un altro processo.
Se invece tutte le operazioni possono avere successo queste vengono eseguite
sblocco non servirebbe comunque, dato che l'operazione non sarebbe atomica.
Vedremo in sez.~\ref{sec:ipc_lock_file} come sia possibile ottenere
un'interfaccia analoga a quella appena illustrata, senza incorrere in questi
-problemi, usando il file locking\index{file!locking}.
+problemi, usando il \index{file!locking} \textit{file locking}.
\subsection{Memoria condivisa}
\var{shm\_perm.uid} e \var{shm\_perm.gid} occorre essere il proprietario o
il creatore del segmento, oppure l'amministratore. Compiuta l'operazione
aggiorna anche il valore del campo \var{shm\_ctime}.
-\item[\const{SHM\_LOCK}] Abilita il \textit{memory
- locking}\itindex{memory~locking}\footnote{impedisce cioè che la memoria
- usata per il segmento venga salvata su disco dal meccanismo della memoria
- virtuale\index{memoria~virtuale}; si ricordi quanto trattato in
+\item[\const{SHM\_LOCK}] Abilita il \itindex{memory~locking} \textit{memory
+ locking}\footnote{impedisce cioè che la memoria usata per il segmento
+ venga salvata su disco dal meccanismo della \index{memoria~virtuale}
+ memoria virtuale; si ricordi quanto trattato in
sez.~\ref{sec:proc_mem_lock}.} sul segmento di memoria condivisa. Solo
l'amministratore può utilizzare questo comando.
-\item[\const{SHM\_UNLOCK}] Disabilita il \textit{memory
- locking}\itindex{memory~locking} sul segmento di memoria condivisa. Solo
+\item[\const{SHM\_UNLOCK}] Disabilita il \itindex{memory~locking}
+ \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 di messaggi e
gli insiemi di semafori, gli ultimi due sono delle estensioni specifiche
previste da Linux, che permettono di abilitare e disabilitare il meccanismo
-della memoria virtuale\index{memoria~virtuale} per il segmento.
+della \index{memoria~virtuale} memoria virtuale per il segmento.
L'argomento \param{buf} viene utilizzato solo con i comandi \const{IPC\_STAT}
e \const{IPC\_SET} nel qual caso esso dovrà puntare ad una struttura
fig.~\ref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si
ricordi quanto illustrato al proposito in sez.~\ref{sec:proc_mem_layout}). In
particolare l'indirizzo finale del segmento dati (quello impostato da
-\func{brk}, vedi sez.~\ref{sec:proc_mem_sbrk_alloca}) non viene influenzato.
+\func{brk}, vedi sez.~\ref{sec:proc_mem_alloc}) non viene influenzato.
Si tenga presente infine che la funzione ha successo anche se il segmento è
stato marcato per la cancellazione.
sgancia dal processo e poi lo rimuove. Il primo passo (\texttt{\small 37}) è
la chiamata a \func{shmdt} per sganciare il segmento, restituendo
(\texttt{\small 38--39}) un valore -1 in caso di errore. Il passo successivo
-(\texttt{\small 41}) è utilizzare \func{shmget} per ottenre l'identificatore
+(\texttt{\small 41}) è utilizzare \func{shmget} per ottenere l'identificatore
associato al segmento data la chiave \var{key}. Al solito si restituisce un
valore di -1 (\texttt{\small 42--45}) in caso di errore, mentre se tutto va
bene si conclude restituendo un valore nullo.
riga di comando (che si limitano alla eventuale stampa di un messaggio di
aiuto a video ed all'impostazione della durata dell'intervallo con cui viene
ripetuto il calcolo delle proprietà della directory) controlla (\texttt{\small
- 20--23}) che sia stato specificato l'argoemnto necessario contenente il nome
+ 20--23}) che sia stato specificato l'argomento necessario contenente il nome
della directory da tenere sotto controllo, senza il quale esce immediatamente
con un messaggio di errore.
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\index{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 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.
\subsection{I \textsl{file di lock}}
\label{sec:ipc_file_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
strutturali, per questo quando si ha una semplice esigenza di sincronizzazione
sez.~\ref{sec:file_open}) che 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 \textit{race
- condition}\itindex{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}.
+ è 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}.
Un esempio dell'uso di questa funzione è mostrato dalle funzioni
\func{LockFile} ed \func{UnlockFile} riportate in fig.~\ref{fig:ipc_file_lock}
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
+In generale comunque l'uso di un \textsl{file di lock} presenta parecchi
+problemi che non lo rendono una alternativa praticabile per la
sincronizzazione: anzitutto in caso di terminazione imprevista del processo,
si lascia allocata la risorsa (il \textsl{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}\itindex{polling},
-ed è quindi molto inefficiente.
+può essere eseguito solo con una tecnica di \itindex{polling}
+\textit{polling}, ed è quindi molto inefficiente.
La tecnica dei file di lock ha comunque 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.\index{file!di lock|)}
+accedere alla seriale si limita a segnalare che la risorsa non è disponibile.
+
+\index{file!di lock|)}
\subsection{La sincronizzazione con il \textit{file locking}}
\label{sec:ipc_lock_file}
-Dato che i file di lock\index{file!di lock} presentano gli inconvenienti
+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 \textit{file locking}\index{file!locking}
+comune è quella di fare ricorso al \index{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 \textit{polling}\itindex{polling} per
+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.
\end{minipage}
\normalsize
\caption{Il codice delle funzioni che permettono per la gestione dei
- \textit{mutex} con il file locking\index{file!locking}.}
+ \textit{mutex} con il \index{file!locking} \textit{file locking}.}
\label{fig:ipc_flock_mutex}
\end{figure}
Il codice delle varie funzioni usate per implementare un mutex utilizzando il
-file locking\index{file!locking} è riportato in fig.~\ref{fig:ipc_flock_mutex};
-si è mantenuta volutamente una struttura analoga alle precedenti funzioni che
-usano i semafori, anche se le due interfacce non possono essere completamente
-equivalenti, specie per quanto riguarda la rimozione del mutex.
+\textit{file locking} \index{file!locking} è riportato in
+fig.~\ref{fig:ipc_flock_mutex}; si è mantenuta volutamente una struttura
+analoga alle precedenti funzioni che usano i semafori, anche se le due
+interfacce non possono essere completamente equivalenti, specie per quanto
+riguarda la rimozione del mutex.
La prima funzione (\texttt{\small 1--5}) è \func{CreateMutex}, e serve a
creare il mutex; la funzione è estremamente semplice, e si limita
(\texttt{\small 4}) a creare, con una opportuna chiamata ad \func{open}, il
-file che sarà usato per il successivo file locking, assicurandosi che non
-esista già (nel qual caso segnala un errore); poi restituisce il file
+file che sarà usato per il successivo \textit{file locking}, assicurandosi che
+non esista già (nel qual caso segnala un errore); poi restituisce il file
descriptor che sarà usato dalle altre funzioni per acquisire e rilasciare il
mutex.
La seconda funzione (\texttt{\small 6--10}) è \func{FindMutex}, che, come la
precedente, è stata definita per mantenere una analogia con la corrispondente
funzione basata sui semafori. Anch'essa si limita (\texttt{\small 9}) ad
-aprire il file da usare per il file locking, solo che in questo caso le
-opzioni di \func{open} sono tali che il file in questione deve esistere di
-già.
+aprire il file da usare per il \index{file!locking} \textit{file locking},
+solo che in questo caso le opzioni di \func{open} sono tali che il file in
+questione deve esistere di già.
La terza funzione (\texttt{\small 11--22}) è \func{LockMutex} e serve per
acquisire il mutex. La funzione definisce (\texttt{\small 14}) e inizializza
rilasciare il mutex. La funzione è analoga alla precedente, solo che in questo
caso si inizializza (\texttt{\small 28--31}) la struttura \var{lock} per il
rilascio del lock, che viene effettuato (\texttt{\small 33}) con la opportuna
-chiamata a \func{fcntl}. Avendo usato il file locking in semantica POSIX (si
-riveda quanto detto sez.~\ref{sec:file_posix_lock}) solo il processo che ha
-precedentemente eseguito il lock può sbloccare il mutex.
+chiamata a \func{fcntl}. Avendo usato il \index{file!locking} \textit{file
+ locking} in semantica POSIX (si riveda quanto detto
+sez.~\ref{sec:file_posix_lock}) solo il processo che ha precedentemente
+eseguito il lock può sbloccare il mutex.
La quinta funzione (\texttt{\small 36--39}) è \func{RemoveMutex} e serve a
cancellare il mutex. Anche questa funzione è stata definita per mantenere una
\end{itemize}
Data la assoluta genericità delle specifiche, il comportamento delle funzioni
-è pertanto subordinato in maniera quasi completa alla relativa
+è subordinato in maniera quasi completa alla relativa
implementazione.\footnote{tanto che Stevens in \cite{UNP2} cita questo caso
come un esempio della maniera standard usata dallo standard POSIX per
consentire implementazioni non standardizzabili.} Nel caso di Linux, sia per
-quanto riguarda la memoria condivisa, che per quanto riguarda le code di
-messaggi, tutto viene creato usando come radici delle opportune directory
-(rispettivamente \file{/dev/shm} e \file{/dev/mqueue}, per i dettagli si
-faccia riferimento a sez.~\ref{sec:ipc_posix_shm} e
-sez.~\ref{sec:ipc_posix_mq}) ed i nomi specificati nelle relative funzioni
-sono considerati come un \itindsub{pathname}{assoluto}\textit{pathname}
-assoluto (comprendente eventuali sottodirectory) rispetto a queste radici.
+quanto riguarda la memoria condivisa ed i semafori, che per quanto riguarda le
+code di messaggi, tutto viene creato usando come radici delle opportune
+directory (rispettivamente \file{/dev/shm} e \file{/dev/mqueue}, per i
+dettagli si faccia riferimento a sez.~\ref{sec:ipc_posix_shm},
+sez.~\ref{sec:ipc_posix_sem} e sez.~\ref{sec:ipc_posix_mq}) ed i nomi
+specificati nelle relative funzioni sono considerati come un
+\itindsub{pathname}{assoluto}\textit{pathname} assoluto (comprendente
+eventuali sottodirectory) rispetto a queste radici.
Il vantaggio degli oggetti di IPC POSIX è comunque che essi vengono inseriti
nell'albero dei file, e possono essere maneggiati con le usuali funzioni e
-comandi di accesso ai file,\footnote{questo è ancora più vero nel caso di
- Linux, che usa una implementazione che lo consente, non è detto che
- altrettanto valga per altri kernel. In particolare sia la memoria condivisa
- che per le code di messaggi, come si può facilmente evincere con uno
- \cmd{strace}, le system call utilizzate sono le stesse, in quanto esse sono
- realizzate con dei file in speciali filesystem.} che funzionano come su dei
-file normali.
+comandi di accesso ai file,\footnote{questo è vero nel caso di Linux, che usa
+ una implementazione che lo consente, non è detto che altrettanto valga per
+ altri kernel; in particolare sia la memoria condivisa che per le code di
+ messaggi, come si può facilmente evincere con uno \cmd{strace}, le system
+ call utilizzate sono le stesse, in quanto detti oggetti sono realizzati con
+ dei file in speciali filesystem.} che funzionano come su dei file normali.
In particolare i permessi associati agli oggetti di IPC POSIX sono identici ai
permessi dei file, e il controllo di accesso segue esattamente la stessa
semantica (quella illustrata in sez.~\ref{sec:file_access_control}), invece di
quella particolare (si ricordi quanto visto in
-sez.~\ref{sec:ipc_sysv_access_control}) usata per gli oggetti del SysV IPC. Per
-quanto riguarda l'attribuzione dell'utente e del gruppo proprietari
+sez.~\ref{sec:ipc_sysv_access_control}) usata per gli oggetti del 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 (essi corrispondono cioè a userid e groupid effettivi del
-processo che esegue la creazione).
+semantica SysV; essi corrispondono cioè a userid e groupid effettivi del
+processo che esegue la creazione.
\subsection{Code di messaggi}
\label{sec:ipc_posix_mq}
-Le code di messaggi non sono ancora supportate nel kernel ufficiale, esiste
-però una implementazione sperimentale di Michal Wronski e Krzysztof
-Benedyczak,\footnote{i patch al kernel e la relativa libreria possono essere
-trovati su \href{http://www.mat.uni.torun.pl/~wrona/posix_ipc}
-{\textsf{http://www.mat.uni.torun.pl/\tild{}wrona/posix\_ipc}}, questi sono
-stati inseriti nel kernel ufficiale a partire dalla versione 2.6.6-rc1.}. In
+Le code di messaggi POSIX sono supportate da Linux a partire dalla versione
+2.6.6-rc1 del kerne;, \footnote{l'implementazione è dovuta a Michal Wronski e
+ Krzysztof Benedyczak, e le relative informazioni si possono trovare su
+ \href{http://www.geocities.com/wronski12/posix_ipc/index.html}
+ {\texttt{http://www.geocities.com/wronski12/posix\_ipc/index.html}}.} In
generale, come le corrispettive del SysV IPC, le code di messaggi sono poco
-usate, dato che i socket\index{socket}, nei casi in cui sono sufficienti, sono
-più comodi, e che in casi più complessi la comunicazione può essere gestita
-direttamente con mutex e memoria condivisa con tutta la flessibilità che
-occorre.
-
-Per poter utilizzare le code di messaggi, oltre ad utilizzare un kernel cui
-siano stati opportunamente applicati i relativi patch, occorre utilizzare la
-libreria \file{mqueue}\footnote{i programmi che usano le code di messaggi cioè
+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.
+
+Per poter utilizzare le code di messaggi, oltre ad utilizzare un kernel
+superiore al 2.6.6 (o precedente, purché cui siano stati opportunamente
+applicati i relativi patch) occorre utilizzare la libreria
+\file{libmqueue}\footnote{i programmi che usano le code di messaggi cioè
devono essere compilati aggiungendo l'opzione \code{-lmqueue} al comando
\cmd{gcc}, dato che le funzioni non fanno parte della libreria standard, in
corrispondenza all'inclusione del supporto nel kernel ufficiale, anche le
- relative funzioni sono state inserite nelle \acr{glibc} a partire dalla
- versione 2.3.4.} che contiene le funzioni dell'interfaccia
-POSIX.\footnote{in realtà l'implementazione è realizzata tramite delle
- speciali chiamate ad \func{ioctl} sui file del filesystem speciale su cui
- vengono mantenuti questi oggetti di IPC.}
-
+ relative funzioni sono state inserite nelle \acr{glibc}, e presenti a
+ partire dalla versione 2.3.4 delle medesime.} che contiene le funzioni
+dell'interfaccia POSIX.\footnote{in realtà l'implementazione è realizzata
+ tramite delle speciali chiamate ad \func{ioctl} sui file del filesystem
+ speciale su cui vengono mantenuti questi oggetti di IPC.}
La libreria inoltre richiede la presenza dell'apposito filesystem di tipo
\texttt{mqueue} montato su \file{/dev/mqueue}; questo può essere fatto
Anche in questo caso il comportamento della funzione è analogo a quello di
\func{unlink} per i file,\footnote{di nuovo l'implementazione di Linux usa
- direttamente \func{unlink}.} la funzione rimove la coda \param{name}, così
+ direttamente \func{unlink}.} la funzione rimuove la coda \param{name}, così
che una successiva chiamata a \func{mq\_open} fallisce o crea una coda
diversa.
\const{MQ\_PRIO\_MAX}, che nel caso è pari a 32768.
Qualora la coda sia piena, entrambe le funzioni si bloccano, a meno che non
-sia stata selezionata in fase di apertura la modalità non bloccante, nel qual
-caso entrambe ritornano \errcode{EAGAIN}. La sola differenza fra le due
-funzioni è che la seconda, passato il tempo massimo impostato con l'argomento
-\param{abs\_timeout}, ritorna comunque con un errore di \errcode{ETIMEDOUT}.
-
+sia stata selezionata in fase di apertura la modalità non
+bloccante,\footnote{o si sia impostato il flag \const{O\_NONBLOCK} sul fie
+ descriptor della coda.} nel qual caso entrambe ritornano \errcode{EAGAIN}.
+La sola differenza fra le due funzioni è che la seconda, passato il tempo
+massimo impostato con l'argomento \param{abs\_timeout},\footnote{deve essere
+ specificato un tempo assoluto tramite una struttura \struct{timespec} (vedi
+ fig.~\ref{fig:sys_timeval_struct}) indicato in numero di secondi e
+ nanosecondi a partire dal 1 gennaio 1970.} ritorna comunque con un errore di
+\errcode{ETIMEDOUT}, se invece il tempo è già scaduto al momento della
+chiamata e la coda è vuota la funzione ritorna immediatamente.
Come per l'inserimento, anche per l'estrazione dei messaggi da una coda sono
previste due funzioni, \funcd{mq\_receive} e \funcd{mq\_timedreceive}, i cui
La funzione estrae dalla coda il messaggio a priorità più alta, o il più
vecchio fra quelli della stessa priorità. Una volta ricevuto il messaggio
viene tolto dalla coda e la sua dimensione viene restituita come valore di
-ritorno.
+ritorno.\footnote{si tenga presente che 0 è una dimensione valida la
+ condizione di errore è restituita dal valore -1; Stevens in \cite{UNP2} fa
+ notare che questo è uno dei casi in cui vale ciò che lo standard
+ \textsl{non} dice, una dimenzione nulla infatti, pur non essendo citata, non
+ viene proibita.}
Se la dimensione specificata da \param{msg\_len} non è sufficiente a contenere
il messaggio, entrambe le funzioni, al contrario di quanto avveniva nelle code
Si noti che con le code di messaggi POSIX non si ha la possibilità di
selezionare quale messaggio estrarre con delle condizioni sulla priorità, a
differenza di quanto avveniva con le code di messaggi di SysV che permettono
-invece la selezione in base al valore del campo \var{mtype}. Qualora non
-interessi usare la priorità dei messaggi si
+invece la selezione in base al valore del campo \var{mtype}.
-% TODO vericare questa interruzione di paragrafo
% TODO inserire i dati di /proc/sys/fs/mqueue
Qualora la coda sia vuota entrambe le funzioni si bloccano, a meno che non si
0. Questo ci dice che, se si effettua la ricezione dei messaggi usando
esclusivamente il meccanismo di notifica, è possibile ottenere le informazioni
sul processo che ha inserito un messaggio usando un gestore per il segnale in
-forma estesa\footnote{di nuovo si faccia riferimento a quanto detto al
+forma estesa.\footnote{di nuovo si faccia riferimento a quanto detto al
proposito in sez.~\ref{sec:sig_sigaction} e sez.~\ref{sec:sig_real_time}.}
In realtà a partire dal kernel 2.5.7 è stato introdotto un meccanismo di
sincronizzazione completamente nuovo, basato sui cosiddetti
\textit{futex}\footnote{la sigla sta per \textit{fast user mode mutex}.}, con
-il quale dovrebbe essere possibile implementare una versione nativa dei
-semafori; esso è già stato usato con successo per reimplementare in maniera
-più efficiente tutte le direttive di sincronizzazione previste per i thread
-POSIX. L'interfaccia corrente è stata stabilizzata a partire dal kernel
-2.5.40.
+il quale è stato possibile implementare una versione nativa dei semafori; esso
+è già stato usato con successo per reimplementare in maniera più efficiente
+tutte le direttive di sincronizzazione previste per i thread POSIX; e con il
+kernel della serie 2.6 e le nuove versioni delle \acr{glibc} che usano quella
+che viene chiamata la \textit{New Posix Thread Library} sono state
+implementate tutte le funzioni occorrenti.
+
+Anche in questo caso (come per le code di messaggi) è necessario appoggiarsi
+alla libreria per le estensioni \textit{real-time} \texttt{librt}, questo
+significa che se si vuole utilizzare questa interfaccia, oltre ad utilizzare
+gli opportuni file di definizione, occorrerà compilare i programmi con
+l'opzione \texttt{-lrt}.
-% TODO vedere se ci sono novità e trattare la cosa.
+% TODO trattare l'argomento a partire da man sem_overview.
\subsection{Memoria condivisa}
\label{sec:ipc_posix_shm}
-La memoria condivisa è l'unico degli oggetti di IPC POSIX già presente nel
-kernel ufficiale; in realtà 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 \texttt{CONFIG\_TMPFS} in fase di compilazione del kernel.
+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
+\texttt{CONFIG\_TMPFS} in fase di compilazione del kernel.
Per potere utilizzare l'interfaccia POSIX per le code di messaggi le
\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 intepretati prendendo come radice \file{/dev/shm}.\footnote{occorre
+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 libereria, il tentativo di accedere a \file{/dev/shm/dev/shm/nome}.}
+ 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
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},
-retituendo al chiamante il valore di ritorno.
-
+restituendo al chiamante il valore di ritorno.
+
+
+% LocalWords: like fifo System POSIX RPC Calls Common Object Request Brocker
+% LocalWords: Architecture descriptor kernel unistd int filedes errno EMFILE
+% LocalWords: ENFILE EFAULT BUF sez fig fork Stevens siblings EOF read SIGPIPE
+% LocalWords: EPIPE shell CGI Gateway Interface HTML JPEG URL mime type gs dup
+% LocalWords: barcode PostScript race condition stream BarCodePage WriteMess
+% LocalWords: size PS switch wait popen pclose stdio const char command NULL
+% LocalWords: EINVAL cap fully buffered Ghostscript l'Encapsulated epstopsf of
+% LocalWords: PDF EPS lseek ESPIPE PPM Portable PixMap format pnmcrop PNG pnm
+% LocalWords: pnmmargin png BarCode inode filesystem l'inode mknod mkfifo RDWR
+% LocalWords: ENXIO deadlock client reinviate fortunes fortunefilename daemon
+% LocalWords: FortuneServer FortuneParse FortuneClient pid libgapil LD
+% 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: 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
+% LocalWords: CREAT EXCL EIDRM ENOENT ENOSPC ENOMEM novo proc MSGMAX msgmax ds
+% LocalWords: MSGMNB msgmnb linked list msqid msgid linux msg qnum lspid lrpid
+% LocalWords: rtime ctime qbytes first last cbytes msgctl semctl shmctl ioctl
+% LocalWords: cmd struct buf EPERM RMID msgsnd msgbuf msgp msgsz msgflg EAGAIN
+% LocalWords: NOWAIT EINTR mtype mtext long message sizeof LENGTH ts sleep BIG
+% LocalWords: msgrcv ssize msgtyp NOERROR EXCEPT ENOMSG multiplexing select ls
+% LocalWords: poll polling queue MQFortuneServer write init HandSIGTERM
+% LocalWords: MQFortuneClient mqfortuned mutex risorse' inter semaphore semget
+% LocalWords: nsems SEMMNS SEMMSL semid otime semval sempid semncnt semzcnt nr
+% LocalWords: SEMVMX SEMOPM semop SEMMNU SEMUME SEMAEM semnum union semun arg
+% LocalWords: ERANGE SETALL SETVAL GETALL array GETNCNT GETPID GETVAL GETZCNT
+% LocalWords: sembuf sops unsigned nsops UNDO flg nsop num undo pending semadj
+% LocalWords: sleeper scheduler running next semundo MutexCreate semunion lock
+% LocalWords: MutexFind wrapper MutexRead MutexLock MutexUnlock unlock locking
+% LocalWords: MutexRemove shmget SHMALL SHMMAX SHMMIN shmid shm segsz atime FD
+% LocalWords: dtime lpid cpid nattac shmall shmmax SHMLBA SHMSEG EOVERFLOW brk
+% LocalWords: memory shmat shmdt void shmaddr shmflg SVID RND RDONLY rounded
+% LocalWords: SIGSEGV nattch exit SharedMem ShmCreate memset fill ShmFind home
+% LocalWords: ShmRemove DirMonitor DirProp chdir GaPiL shmptr DirScan ipcs NFS
+% LocalWords: ComputeValues ReadMonitor touch SIGTERM dirmonitor unlink fcntl
+% LocalWords: LockFile UnlockFile CreateMutex FindMutex LockMutex SETLKW GETLK
+% LocalWords: UnlockMutex RemoveMutex ReadMutex UNLCK WRLCK RDLCK mapping MAP
+% 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: 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
%%% Local Variables: