%% ipc.tex
%%
-%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2009 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",
accennato concetto di funzionamento di una pipe è semplice: quello che si
scrive nel file descriptor aperto in scrittura viene ripresentato tale e quale
nel file descriptor aperto in lettura. I file descriptor infatti non sono
-connessi a nessun file reale, ma ad un buffer nel kernel, la cui dimensione è
-specificata dal parametro di sistema \const{PIPE\_BUF}, (vedi
+connessi a nessun file reale, ma, come accennato in
+sez.~\ref{sec:file_sendfile_splice}, ad un buffer nel kernel, la cui
+dimensione è specificata dal parametro di sistema \const{PIPE\_BUF}, (vedi
sez.~\ref{sec:sys_file_limits}). Lo schema di funzionamento di una pipe è
illustrato in fig.~\ref{fig:ipc_pipe_singular}, in cui sono illustrati i due
capi della pipe, associati a ciascun file descriptor, con le frecce che
è il loro uso più comune, analogo a quello effettuato della shell, e che
consiste nell'inviare l'output di un processo (lo standard output) sull'input
di un altro. Realizzeremo il programma di esempio nella forma di un
-\textit{CGI}\footnote{Un CGI (\textit{Common Gateway Interface}) è un
+\textit{CGI}\footnote{un CGI (\textit{Common Gateway Interface}) è un
programma che permette la creazione dinamica di un oggetto da inserire
all'interno di una pagina HTML.} per Apache, che genera una immagine JPEG
di un codice a barre, specificato come argomento in ingresso.
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
- loro esecuzione; ma a questo le cose non sarebbero più tanto semplici.}
-L'uso di una 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.
+ loro esecuzione; ma a questo punto le cose non sarebbero più tanto
+ semplici.} L'uso di una 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
A questo punto il server resta (se non ci sono altri client che stanno
effettuando richieste) con la fifo chiusa sul lato in lettura, ed in questo
stato la funzione \func{read} non si bloccherà in attesa di input, ma
-ritornerà in continuazione, restituendo un end-of-file.\footnote{Si è usata
+ritornerà in continuazione, restituendo un end-of-file.\footnote{si è usata
questa tecnica per compatibilità, Linux infatti supporta l'apertura delle
fifo in lettura/scrittura, per cui si sarebbe potuto effettuare una singola
apertura con \const{O\_RDWR}, la doppia apertura comunque ha il vantaggio
\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 \textit{minor
- number}, come \file{/dev/hda1} e \file{/dev/sda1}.
+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}.
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
a differenza di quanto avviene per i permessi dei file, fallire in uno dei
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
+il valore di \itindex{umask} \textit{umask} (si ricordi quanto esposto in
sez.~\ref{sec:file_perm_management}) non ha alcun significato.
altri limiti relativi al \textit{SysV IPC}) solo con una ricompilazione del
kernel, andando a modificarne la definizione nei relativi header file. A
partire dal kernel 2.4.x è possibile cambiare questi valori a sistema attivo
- scrivendo sui file \file{shmmni}, \file{msgmni} e \file{sem} di
- \file{/proc/sys/kernel} o con l'uso di \func{sysctl}.} e per ciascuno di
+ scrivendo sui file \procrelfile{/proc/sys/kernel}{shmmni},
+ \procrelfile{/proc/sys/kernel}{msgmni} e \procrelfile{/proc/sys/kernel}{sem}
+ di \file{/proc/sys/kernel} o con l'uso di \func{sysctl}.} e per ciascuno di
essi viene mantenuto in \var{seq} un numero di sequenza progressivo che viene
incrementato di uno ogni volta che l'oggetto viene cancellato. Quando
l'oggetto viene creato usando uno spazio che era già stato utilizzato in
\hline
\hline
\const{MSGMNI}& 16& \file{msgmni} & Numero massimo di code di
- messaggi. \\
+ messaggi.\\
\const{MSGMAX}& 8192& \file{msgmax} & Dimensione massima di un singolo
messaggio.\\
\const{MSGMNB}&16384& \file{msgmnb} & Dimensione massima del contenuto di
negli header e corrispondenti alle prime tre costanti riportate in
tab.~\ref{tab:ipc_msg_limits}, come accennato però in Linux è possibile
modificare questi limiti attraverso l'uso di \func{sysctl} o scrivendo nei
-file \file{msgmax}, \file{msgmnb} e \file{msgmni} di \file{/proc/sys/kernel/}.
+file \procrelfile{/proc/sys/kernel}{msgmax},
+\procrelfile{/proc/sys/kernel}{msgmnb} e
+\procrelfile{/proc/sys/kernel}{msgmni} di \file{/proc/sys/kernel/}.
\begin{figure}[htb]
\textbf{Costante} & \textbf{Valore} & \textbf{Significato} \\
\hline
\hline
- \const{SEMMNI}& 128 & Numero massimo di insiemi di semafori. \\
+ \const{SEMMNI}& 128 & Numero massimo di insiemi di semafori.\\
\const{SEMMSL}& 250 & Numero massimo di semafori per insieme.\\
\const{SEMMNS}&\const{SEMMNI}*\const{SEMMSL}& Numero massimo di semafori
- nel sistema .\\
+ nel sistema.\\
\const{SEMVMX}& 32767 & Massimo valore per un semaforo.\\
\const{SEMOPM}& 32 & Massimo numero di operazioni per chiamata a
\func{semop}. \\
\const{SEMMNU}&\const{SEMMNS}& Massimo numero di strutture di ripristino.\\
\const{SEMUME}&\const{SEMOPM}& Massimo numero di voci di ripristino.\\
- \const{SEMAEM}&\const{SEMVMX}& valore massimo per l'aggiustamento
+ \const{SEMAEM}&\const{SEMVMX}& Valore massimo per l'aggiustamento
all'uscita. \\
\hline
\end{tabular}
serie di limiti, i cui valori sono associati ad altrettante costanti, che si
sono riportate in tab.~\ref{tab:ipc_sem_limits}. Alcuni di questi limiti sono
al solito accessibili e modificabili attraverso \func{sysctl} o scrivendo
-direttamente nel file \file{/proc/sys/kernel/sem}.
+direttamente nel file \procfile{/proc/sys/kernel/sem}.
La funzione che permette di effettuare le varie operazioni di controllo sui
semafori (fra le quali, come accennato, è impropriamente compresa anche la
\textbf{Operazione} & \textbf{Valore restituito} \\
\hline
\hline
- \const{GETNCNT}& valore di \var{semncnt}.\\
- \const{GETPID} & valore di \var{sempid}.\\
- \const{GETVAL} & valore di \var{semval}.\\
- \const{GETZCNT}& valore di \var{semzcnt}.\\
+ \const{GETNCNT}& Valore di \var{semncnt}.\\
+ \const{GETPID} & Valore di \var{sempid}.\\
+ \const{GETVAL} & Valore di \var{semval}.\\
+ \const{GETZCNT}& Valore di \var{semzcnt}.\\
\hline
\end{tabular}
\caption{Valori di ritorno della funzione \func{semctl}.}
& \textbf{Significato} \\
\hline
\hline
- \const{SHMALL}& 0x200000&\file{shmall}& Numero massimo di pagine che
- possono essere usate per i segmenti di
- memoria condivisa. \\
- \const{SHMMAX}&0x2000000&\file{shmmax}& Dimensione massima di un segmento
- di memoria condivisa.\\
- \const{SHMMNI}& 4096&\file{msgmni}& Numero massimo di segmenti di
- memoria condivisa presenti nel
- kernel.\\
+ \const{SHMALL}& 0x200000&\procrelfile{/proc/sys/kernel}{shmall}
+ & Numero massimo di pagine che
+ possono essere usate per i segmenti di
+ memoria condivisa.\\
+ \const{SHMMAX}&0x2000000&\procrelfile{/proc/sys/kernel}{shmmax}
+ & Dimensione massima di un segmento di memoria
+ condivisa.\\
+ \const{SHMMNI}& 4096&\procrelfile{/proc/sys/kernel}{msgmni}
+ & Numero massimo di segmenti di memoria condivisa
+ presenti nel kernel.\\
\const{SHMMIN}& 1& --- & Dimensione minima di un segmento di
- memoria condivisa. \\
+ memoria condivisa.\\
\const{SHMLBA}&\const{PAGE\_SIZE}&--- & Limite inferiore per le dimensioni
minime di un segmento (deve essere
allineato alle dimensioni di una
- pagina di memoria). \\
+ pagina di memoria).\\
\const{SHMSEG}& --- & --- & Numero massimo di segmenti di
- memoria condivisa
- per ciascun processo.\\
+ memoria condivisa per ciascun
+ processo.\\
\hline
\begin{errlist}
\item[\errcode{EACCES}] si è richiesto \const{IPC\_STAT} ma i permessi non
consentono l'accesso in lettura al segmento.
- \item[\errcode{EINVAL}] O \param{shmid} non è un identificatore valido o
+ \item[\errcode{EINVAL}] o \param{shmid} non è un identificatore valido o
\param{cmd} non è un comando valido.
\item[\errcode{EIDRM}] l'argomento \param{shmid} fa riferimento ad un
segmento che è stato cancellato.
\label{fig:ipc_shmem_layout}
\end{figure}
-L'argomento \param{shmaddr} specifica a quale indirizzo\footnote{Lo standard
+L'argomento \param{shmaddr} specifica a quale indirizzo\footnote{lo standard
SVID prevede che l'argomento \param{shmaddr} sia di tipo \ctyp{char *}, così
- come il valore di ritorno della funzione. In Linux è stato così con le
+ come il valore di ritorno della funzione; in Linux è stato così con le
\acr{libc4} e le \acr{libc5}, con il passaggio alle \acr{glibc} il tipo di
\param{shmaddr} è divenuto un \ctyp{const void *} e quello del valore di
ritorno un \ctyp{void *}.} deve essere associato il segmento, se il valore
L'uso di \const{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 \const{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.
+caso un tentativo di scrivere sul segmento comporterà una
+\itindex{segment~violation} violazione di accesso con l'emissione di un
+segnale di \const{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
\struct{shmid\_ds}:
Oggi Linux supporta tutti gli oggetti definito nello standard POSIX per l'IPC,
ma a lungo non è stato così; la memoria condivisa è presente a partire dal
kernel 2.4.x, i semafori sono forniti dalle \acr{glibc} nella sezione che
-implementa i thread POSIX di nuova generazione che richiedono il kernel 2.6,
-le code di messaggi sono supportate a partire dal kernel 2.6.6.
+implementa i \itindex{thread} \textit{thread} POSIX di nuova generazione che
+richiedono il kernel 2.6, le code di messaggi sono supportate a partire dal
+kernel 2.6.6.
La caratteristica fondamentale dell'interfaccia POSIX è l'abbandono dell'uso
degli identificatori e delle chiavi visti nel SysV IPC, per passare ai
2.6.6-rc1 del kernel,\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
+ {\textsf{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, nei casi in cui sono sufficienti, sono più comodi, e
che in casi più complessi la comunicazione può essere gestita direttamente con
La libreria inoltre richiede la presenza dell'apposito filesystem di tipo
\texttt{mqueue} montato su \file{/dev/mqueue}; questo può essere fatto
-aggiungendo ad \file{/etc/fstab} una riga come:
+aggiungendo ad \conffile{/etc/fstab} una riga come:
\begin{verbatim}
mqueue /dev/mqueue mqueue defaults 0 0
\end{verbatim}
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
+ fig.~\ref{fig:sys_timespec_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.
Attraverso questa struttura si possono impostare le modalità con cui viene
effettuata la notifica; in particolare il campo \var{sigev\_notify} deve
essere posto a \const{SIGEV\_SIGNAL}\footnote{il meccanismo di notifica basato
- sui thread, specificato tramite il valore \const{SIGEV\_THREAD}, non è
- implementato.} ed il campo \var{sigev\_signo} deve indicare il valore del
-segnale che sarà inviato al processo. Inoltre il campo \var{sigev\_value} è il
-puntatore ad una struttura \struct{sigval\_t} (definita in
-fig.~\ref{fig:sig_sigval}) che permette di restituire al gestore del segnale un
-valore numerico o un indirizzo,\footnote{per il suo uso si riveda la
- trattazione fatta in sez.~\ref{sec:sig_real_time} a proposito dei segnali
- real-time.} posto che questo sia installato nella forma estesa vista in
-sez.~\ref{sec:sig_sigaction}.
+ sui \itindex{thread} \textit{thread}, specificato tramite il valore
+ \const{SIGEV\_THREAD}, non è implementato.} ed il campo \var{sigev\_signo}
+deve indicare il valore del segnale che sarà inviato al processo. Inoltre il
+campo \var{sigev\_value} è il puntatore ad una struttura \struct{sigval\_t}
+(definita in fig.~\ref{fig:sig_sigval}) che permette di restituire al gestore
+del segnale un valore numerico o un indirizzo,\footnote{per il suo uso si
+ riveda la trattazione fatta in sez.~\ref{sec:sig_real_time} a proposito dei
+ segnali real-time.} posto che questo sia installato nella forma estesa vista
+in sez.~\ref{sec:sig_sigaction}.
La funzione registra il processo chiamante per la notifica se
\param{notification} punta ad una struttura \struct{sigevent} opportunamente
\begin{verbatim}
tmpfs /dev/shm tmpfs defaults 0 0
\end{verbatim}
-ad \file{/etc/fstab}. In realtà si può montare un filesystem \texttt{tmpfs}
+ad \conffile{/etc/fstab}. In realtà si può montare un filesystem \texttt{tmpfs}
dove si vuole, per usarlo come RAM disk, con un comando del tipo:
\begin{verbatim}
mount -t tmpfs -o size=128M,nr_inodes=10k,mode=700 tmpfs /mytmpfs
\label{sec:ipc_posix_sem}
Fino alla serie 2.4.x del kernel esisteva solo una implementazione parziale
-dei semafori POSIX che li realizzava solo a livello di thread e non di
-processi,\footnote{questo significava che i semafori erano visibili solo
- all'interno dei thread creati da un singolo processo, e non potevano essere
- usati come meccanismo di sincronizzazione fra processi diversi.} fornita
-attraverso la sezione delle estensioni \textit{real-time} delle
-\acr{glibc}.\footnote{quelle che si accedono collegandosi alla libreria
- \texttt{librt}.} Esisteva inoltre una libreria che realizzava (parzialmente)
-l'interfaccia POSIX usando le funzioni dei semafori di SysV IPC (mantenendo
-così tutti i problemi sottolineati in sez.~\ref{sec:ipc_sysv_sem}).
+dei semafori POSIX che li realizzava solo a livello di \itindex{thread}
+\textit{thread} e non di processi,\footnote{questo significava che i semafori
+ erano visibili solo all'interno dei \itindex{thread} \textit{thread} creati
+ da un singolo processo, e non potevano essere usati come meccanismo di
+ sincronizzazione fra processi diversi.} fornita attraverso la sezione delle
+estensioni \textit{real-time} delle \acr{glibc}.\footnote{quelle che si
+ accedono collegandosi alla libreria \texttt{librt}.} Esisteva inoltre una
+libreria che realizzava (parzialmente) l'interfaccia POSIX usando le funzioni
+dei semafori di SysV IPC (mantenendo così tutti i problemi sottolineati in
+sez.~\ref{sec:ipc_sysv_sem}).
A partire dal kernel 2.5.7 è stato introdotto un meccanismo di
sincronizzazione completamente nuovo, basato sui cosiddetti
Questo significa che un nuovo semaforo viene sempre creato con l'user-ID ed il
group-ID effettivo del processo chiamante, e che i permessi indicati con
-\param{mode} vengono filtrati dal valore della \textit{umask} del processo.
-Inoltre per poter aprire un semaforo è necessario avere su di esso sia il
-permesso di lettura che quello di scrittura.
+\param{mode} vengono filtrati dal valore della \itindex{umask} \textit{umask}
+del processo. Inoltre per poter aprire un semaforo è necessario avere su di
+esso sia il permesso di lettura che quello di scrittura.
Una volta che si sia ottenuto l'indirizzo di un semaforo, sarà possibile
utilizzarlo; se si ricorda quanto detto all'inizio di
La funzione incrementa di uno il valore corrente del semaforo indicato
dall'argomento \param{sem}, se questo era nullo la relativa risorsa risulterà
-sbloccata, cosicché un altro processo (o thread) eventualmente bloccato in una
-\func{sem\_wait} sul semaforo potrà 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}).
+sbloccata, cosicché un altro processo (o \itindex{thread} \textit{thread})
+eventualmente bloccato in una \func{sem\_wait} sul semaforo potrà 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}).
Se invece di operare su un semaforo se ne vuole solamente leggere il valore,
si può usare la funzione \funcd{sem\_getvalue}, il cui prototipo è:
La funzione inizializza un semaforo all'indirizzo puntato dall'argomento
\param{sem}, e come per \func{sem\_open} consente di impostare un valore
iniziale con \param{value}. L'argomento \param{pshared} serve ad indicare se
-il semaforo deve essere utilizzato dai \itindex{thread} thread di uno stesso
-processo (con un valore nullo) o condiviso fra processi diversi (con un valore
-non nullo).
+il semaforo deve essere utilizzato dai \itindex{thread} \textit{thread} di uno
+stesso processo (con un valore nullo) o condiviso fra processi diversi (con un
+valore non nullo).
-Qualora il semaforo debba essere condiviso dai \itindex{thread} thread di uno
-stesso processo (nel qual caso si parla di \textit{thread-shared semaphore}),
-occorrerà che \param{sem} sia l'indirizzo di una variabile visibile da tutti i
-\itindex{thread} thread, si dovrà usare cioè una variabile globale o una
-variabile allocata dinamicamente nello \itindex{heap} heap.
+Qualora il semaforo debba essere condiviso dai \itindex{thread}
+\textit{thread} di uno stesso processo (nel qual caso si parla di
+\textit{thread-shared semaphore}), occorrerà che \param{sem} sia l'indirizzo
+di una variabile visibile da tutti i \itindex{thread} \textit{thread}, si
+dovrà usare cioè una variabile globale o una variabile allocata dinamicamente
+nello \itindex{heap} heap.
Qualora il semaforo debba essere condiviso fra più processi (nel qual caso si
parla di \textit{process-shared semaphore}) la sola scelta possibile per
semaforo può dar luogo ad un comportamento indefinito.
-Una volta che non si indenda più utilizzare un semaforo anonimo questo può
+Una volta che non si intenda più utilizzare un semaforo anonimo questo può
essere eliminato da sistema; per far questo di deve utilizzare una apposita
funzione, \funcd{sem\_destroy}, il cui prototipo è:
\begin{functions}
essere stato inizializzato con \func{sem\_init}; non deve quindi essere
applicata a semafori creati con \func{sem\_open}. Inoltre si deve essere
sicuri che il semaforo sia effettivamente inutilizzato, la distruzione di un
-semaforo su cui sono presenti processi (o thread) in attesa (cioè bloccati in
-una \func{sem\_wait}) provoca un comportamento indefinito.
+semaforo su cui sono presenti processi (o \itindex{thread} \textit{thread}) in
+attesa (cioè bloccati in una \func{sem\_wait}) provoca un comportamento
+indefinito.
Si tenga presente infine che utilizzare un semaforo che è stato distrutto con
\func{sem\_destroy} di nuovo può dare esito a comportamenti indefiniti. Nel
% LocalWords: lrt blocks PAGECACHE TRUNC CLOEXEC mmap ftruncate munmap FindShm
% LocalWords: CreateShm RemoveShm LIBRARY Library libmqueue FAILED EACCESS
% LocalWords: ENAMETOOLONG qualchenome RESTART trywait XOPEN SOURCE timedwait
-% LocalWords: process getvalue sval execve pshared ENOSYS heap
+% LocalWords: process getvalue sval execve pshared ENOSYS heap PAGE destroy
%%% Local Variables: