%% ipc.tex
%%
-%% Copyright (C) 2000-2014 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2016 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",
su entrambi i file descriptor restituiti dalla funzione i relativi flag, già
descritti per \func{open} in tab.~\ref{tab:open_operation_flag}, che attivano
rispettivamente la modalità di accesso \textsl{non-bloccante} ed il
-\textit{close-on-exec} \itindex{close-on-exec}.
+\textit{close-on-exec}.
Chiaramente creare una \textit{pipe} all'interno di un singolo processo non
serve a niente; se però ricordiamo quanto esposto in
Si potrebbe obiettare che sarebbe molto più semplice salvare il risultato
intermedio su un file temporaneo. Questo però non tiene conto del fatto che un
\textit{CGI} può essere eseguito più volte in contemporanea, e si avrebbe una
-evidente \itindex{race~condition} \textit{race condition} in caso di accesso
-simultaneo a detto file da istanze diverse. Il problema potrebbe essere
-superato utilizzando un sempre diverso per il file temporaneo, che verrebbe
-creato all'avvio di ogni istanza, utilizzato dai sottoprocessi, e cancellato
-alla fine della sua esecuzione; ma a questo punto le cose non sarebbero più
-tanto semplici. L'uso di una \textit{pipe} invece permette di risolvere il
-problema in maniera semplice ed elegante, oltre ad essere molto più
-efficiente, dato che non si deve scrivere su disco.
+evidente \textit{race condition} in caso di accesso simultaneo a detto file da
+istanze diverse. Il problema potrebbe essere superato utilizzando un sempre
+diverso per il file temporaneo, che verrebbe creato all'avvio di ogni istanza,
+utilizzato dai sottoprocessi, e cancellato alla fine della sua esecuzione; ma
+a questo punto le cose non sarebbero più tanto semplici. L'uso di una
+\textit{pipe} invece permette di risolvere il problema in maniera semplice ed
+elegante, oltre ad essere molto più efficiente, dato che non si deve scrivere
+su disco.
Il programma ci servirà anche come esempio dell'uso delle funzioni di
duplicazione dei file descriptor che abbiamo trattato in
\label{fig:ipc_barcodepage_code}
\end{figure}
-La prima operazione del programma (\texttt{\small 4--12}) è quella di creare
+La prima operazione del programma (\texttt{\small 4-12}) è quella di creare
le due \textit{pipe} che serviranno per la comunicazione fra i due comandi
utilizzati per produrre il codice a barre; si ha cura di controllare la
riuscita della chiamata, inviando in caso di errore un messaggio invece
quest'ultimo possa essere visualizzato correttamente da un browser.
Una volta create le \textit{pipe}, il programma può creare (\texttt{\small
- 13--17}) il primo processo figlio, che si incaricherà (\texttt{\small
- 19--25}) di eseguire \cmd{barcode}. Quest'ultimo legge dallo standard input
+ 13-17}) il primo processo figlio, che si incaricherà (\texttt{\small
+ 19-25}) di eseguire \cmd{barcode}. Quest'ultimo legge dallo standard input
una stringa di caratteri, la converte nell'immagine PostScript del codice a
barre ad essa corrispondente, e poi scrive il risultato direttamente sullo
standard output.
PostScript del codice a barre sul capo in scrittura della seconda
\textit{pipe}; a questo punto si può eseguire la seconda conversione, da PS a
JPEG, usando il programma \cmd{gs}. Per questo si crea (\texttt{\small
- 30--34}) un secondo processo figlio, che poi (\texttt{\small 35--42})
+ 30-34}) un secondo processo figlio, che poi (\texttt{\small 35-42})
eseguirà questo programma leggendo l'immagine PostScript creata da
\cmd{barcode} dallo \textit{standard input}, per convertirla in JPEG.
input}) in caso di \code{w}. A partire dalla versione 2.9 delle \acr{glibc}
(questa è una estensione specifica di Linux) all'argomento \param{type} può
essere aggiunta la lettera ``\texttt{e}'' per impostare automaticamente il
-flag di \textit{close-on-exec} \itindex{close-on-exec} sul file descriptor
-sottostante (si ricordi quanto spiegato in sez.~\ref{sec:file_open_close}).
+flag di \textit{close-on-exec} sul file descriptor sottostante (si ricordi
+quanto spiegato in sez.~\ref{sec:file_open_close}).
Lo \textit{stream} restituito da \func{popen} è identico a tutti gli effetti
ai \textit{file stream} visti in sez.~\ref{sec:files_std_interface}, anche se
\textit{standard output} e può tranquillamente provvedere alla redirezione.
Dato che i vari programmi devono essere lanciati in successione, si è
-approntato un ciclo (\texttt{\small 15--19}) che esegue le operazioni in
+approntato un ciclo (\texttt{\small 15-19}) che esegue le operazioni in
sequenza: prima crea una \textit{pipe} (\texttt{\small 17}) per la scrittura
eseguendo il programma con \func{popen}, in modo che essa sia collegata allo
\textit{standard input}, e poi redirige (\texttt{\small 18}) lo
primo processo della catena, che nel caso è \cmd{barcode}, e scrivere
(\texttt{\small 23}) la stringa del codice a barre sulla \textit{pipe}, che è
collegata al suo \textit{standard input}, infine si può eseguire
-(\texttt{\small 24--27}) un ciclo che chiuda con \func{pclose}, nell'ordine
+(\texttt{\small 24-27}) un ciclo che chiuda con \func{pclose}, nell'ordine
inverso rispetto a quello in cui le si sono create, tutte le \textit{pipe}
create in precedenza.
Utilizzando una \textit{fifo} tutti i dati passeranno, come per le
\textit{pipe}, attraverso un buffer nel kernel, senza transitare dal
-filesystem. Il fatto che siano associate ad un \itindex{inode}
-\textit{inode} presente sul filesystem serve infatti solo a fornire un punto
-di accesso per i processi, che permetta a questi ultimi di accedere alla
-stessa \textit{fifo} senza avere nessuna relazione, con una semplice
-\func{open}. Il comportamento delle funzioni di lettura e scrittura è identico
-a quello illustrato per le \textit{pipe} in sez.~\ref{sec:ipc_pipes}.
+filesystem. Il fatto che siano associate ad un \textit{inode} presente sul
+filesystem serve infatti solo a fornire un punto di accesso per i processi,
+che permetta a questi ultimi di accedere alla stessa \textit{fifo} senza avere
+nessuna relazione, con una semplice \func{open}. Il comportamento delle
+funzioni di lettura e scrittura è identico a quello illustrato per le
+\textit{pipe} in sez.~\ref{sec:ipc_pipes}.
Abbiamo già trattato in sez.~\ref{sec:file_mknod} le funzioni \func{mknod} e
\func{mkfifo} che permettono di creare una \textit{fifo}. Per utilizzarne una
-un processo non avrà che da aprire il relativo \index{file!speciali} file
-speciale o in lettura o scrittura; nel primo caso il processo sarà collegato
-al capo di uscita della \textit{fifo}, e dovrà leggere, nel secondo al capo di
-ingresso, e dovrà scrivere.
+un processo non avrà che da aprire il relativo file speciale o in lettura o
+scrittura; nel primo caso il processo sarà collegato al capo di uscita della
+\textit{fifo}, e dovrà leggere, nel secondo al capo di ingresso, e dovrà
+scrivere.
Il kernel alloca un singolo buffer per ciascuna \textit{fifo} che sia stata
aperta, e questa potrà essere acceduta contemporaneamente da più processi, sia
lettura. Infine è possibile anche usare la \textit{fifo} all'interno di un
solo processo, nel qual caso però occorre stare molto attenti alla possibili
situazioni di stallo: se si cerca di leggere da una \textit{fifo} che non
-contiene dati si avrà infatti un \itindex{deadlock} \textit{deadlock}
-immediato, dato che il processo si blocca e quindi non potrà mai eseguire le
-funzioni di scrittura.
+contiene dati si avrà infatti un \textit{deadlock} immediato, dato che il
+processo si blocca e quindi non potrà mai eseguire le funzioni di scrittura.
Per la loro caratteristica di essere accessibili attraverso il filesystem, è
piuttosto frequente l'utilizzo di una \textit{fifo} come canale di
\var{fortune} avviene solo quando questa dimensione viene specificata, la
presenza di un valore nullo provoca l'uscita dal programma attraverso la
funzione (non riportata) che ne stampa le modalità d'uso. Dopo di che
-installa (\texttt{\small 13--15}) la funzione che gestisce i segnali di
+installa (\texttt{\small 13-15}) la funzione che gestisce i segnali di
interruzione (anche questa non è riportata in fig.~\ref{fig:ipc_fifo_server})
che si limita a rimuovere dal filesystem la \textit{fifo} usata dal server per
comunicare.
Anche il codice della funzione non è riportato, in quanto non direttamente
attinente allo scopo dell'esempio.
-Il passo successivo (\texttt{\small 17--22}) è quello di creare con
+Il passo successivo (\texttt{\small 17-22}) è quello di creare con
\func{mkfifo} la \textit{fifo} nota sulla quale il server ascolterà le
richieste, qualora si riscontri un errore il server uscirà (escludendo
ovviamente il caso in cui la funzione \func{mkfifo} fallisce per la precedente
di inizializzazione è completata. A questo punto (\texttt{\small 23}) si può
chiamare la funzione \func{daemon} per far proseguire l'esecuzione del
programma in background come demone. Si può quindi procedere (\texttt{\small
- 24--33}) alla apertura della \textit{fifo}: si noti che questo viene fatto
+ 24-33}) alla apertura della \textit{fifo}: si noti che questo viene fatto
due volte, prima in lettura e poi in scrittura, per evitare di dover gestire
all'interno del ciclo principale il caso in cui il server è in ascolto ma non
ci sono client che effettuano richieste. Si ricordi infatti che quando una
vantaggio che non si può scrivere per errore sul capo aperto in sola lettura.
Per questo motivo, dopo aver eseguito l'apertura in lettura (\texttt{\small
- 24--28}),\footnote{di solito si effettua l'apertura del capo in lettura di
+ 24-28}),\footnote{di solito si effettua l'apertura del capo in lettura di
una \textit{fifo} in modalità non bloccante, per evitare il rischio di uno
stallo: se infatti nessuno apre la \textit{fifo} in scrittura il processo
non ritornerà mai dalla \func{open}. Nel nostro caso questo rischio non
esiste, mentre è necessario potersi bloccare in lettura in attesa di una
richiesta.} si esegue una seconda apertura in scrittura (\texttt{\small
- 29--32}), scartando il relativo file descriptor, che non sarà mai usato, in
+ 29-32}), scartando il relativo file descriptor, che non sarà mai usato, in
questo modo però la \textit{fifo} resta comunque aperta anche in scrittura,
cosicché le successive chiamate a \func{read} possono bloccarsi.
A questo punto si può entrare nel ciclo principale del programma che fornisce
-le risposte ai client (\texttt{\small 34--50}); questo viene eseguito
+le risposte ai client (\texttt{\small 34-50}); questo viene eseguito
indefinitamente (l'uscita del server viene effettuata inviando un segnale, in
modo da passare attraverso la funzione di chiusura che cancella la
\textit{fifo}).
Il server è progettato per accettare come richieste dai client delle stringhe
che contengono il nome della \textit{fifo} sulla quale deve essere inviata la
-risposta. Per cui prima (\texttt{\small 35--39}) si esegue la lettura dalla
+risposta. Per cui prima (\texttt{\small 35-39}) si esegue la lettura dalla
stringa di richiesta dalla \textit{fifo} nota (che a questo punto si bloccherà
tutte le volte che non ci sono richieste). Dopo di che, una volta terminata la
stringa (\texttt{\small 40}) e selezionato (\texttt{\small 41}) un numero
casuale per ricavare la frase da inviare, si procederà (\texttt{\small
- 42--46}) all'apertura della \textit{fifo} per la risposta, che poi
-(\texttt{\small 47--48}) vi sarà scritta. Infine (\texttt{\small 49}) si
+ 42-46}) all'apertura della \textit{fifo} per la risposta, che poi
+(\texttt{\small 47-48}) vi sarà scritta. Infine (\texttt{\small 49}) si
chiude la \textit{fifo} di risposta che non serve più.
Il codice del client è invece riportato in fig.~\ref{fig:ipc_fifo_client},
La prima istruzione (\texttt{\small 12}) compone il nome della \textit{fifo}
che dovrà essere utilizzata per ricevere la risposta dal server. Si usa il
\ids{PID} del processo per essere sicuri di avere un nome univoco; dopo di che
-(\texttt{\small 13--18}) si procede alla creazione del relativo file, uscendo
+(\texttt{\small 13-18}) si procede alla creazione del relativo file, uscendo
in caso di errore (a meno che il file non sia già presente sul filesystem).
A questo punto il client può effettuare l'interrogazione del server, per
-questo prima si apre la \textit{fifo} nota (\texttt{\small 19--23}), e poi ci
+questo prima si apre la \textit{fifo} nota (\texttt{\small 19-23}), e poi ci
si scrive (\texttt{\small 24}) la stringa composta in precedenza, che contiene
il nome della \textit{fifo} da utilizzare per la risposta. Infine si richiude
la \textit{fifo} del server che a questo punto non serve più (\texttt{\small
25}).
Inoltrata la richiesta si può passare alla lettura della risposta; anzitutto
-si apre (\texttt{\small 26--30}) la \textit{fifo} appena creata, da cui si
+si apre (\texttt{\small 26-30}) la \textit{fifo} appena creata, da cui si
deve riceverla, dopo di che si effettua una lettura (\texttt{\small 31})
nell'apposito buffer; si è supposto, come è ragionevole, che le frasi inviate
dal server siano sempre di dimensioni inferiori a \const{PIPE\_BUF},
Verifichiamo allora il comportamento dei nostri programmi, in questo, come in
altri esempi precedenti, si fa uso delle varie funzioni di servizio, che sono
-state raccolte nella libreria \file{libgapil.so}, per poter usare quest'ultima
+state raccolte nella libreria \file{libgapil.so}, e per poterla usare
occorrerà definire la variabile di ambiente \envvar{LD\_LIBRARY\_PATH} in modo
che il linker dinamico possa accedervi.
cosiddetti \textsl{socket locali} (o \textit{Unix domain socket}). Tratteremo
in generale i socket in cap.~\ref{cha:socket_intro}, nell'ambito
dell'interfaccia che essi forniscono per la programmazione di rete, e vedremo
-anche (in~sez.~\ref{sec:sock_sa_local}) come si possono utilizzare i
-\index{file!speciali} file speciali di tipo socket, analoghi a quelli
-associati alle \textit{fifo} (si rammenti sez.~\ref{sec:file_file_types}) cui
-si accede però attraverso quella medesima interfaccia; vale però la pena
-esaminare qui una modalità di uso dei socket locali che li rende
-sostanzialmente identici ad una \textit{pipe} bidirezionale.
+anche (in~sez.~\ref{sec:sock_sa_local}) come si possono utilizzare i file
+speciali di tipo socket, analoghi a quelli associati alle \textit{fifo} (si
+rammenti sez.~\ref{sec:file_file_types}) cui si accede però attraverso quella
+medesima interfaccia; vale però la pena esaminare qui una modalità di uso dei
+socket locali che li rende sostanzialmente identici ad una \textit{pipe}
+bidirezionale.
La funzione di sistema \funcd{socketpair}, introdotta da BSD ma supportata in
genere da qualunque sistema che fornisca l'interfaccia dei socket ed inclusa
in POSIX.1-2001, consente infatti di creare una coppia di file descriptor
connessi fra loro (tramite un socket, appunto) senza dover ricorrere ad un
-\index{file!speciali} 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 è:
+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{funcproto}{
\fhead{sys/types.h}
possono essere specificati sono rispettivamente \const{AF\_UNIX},
\const{SOCK\_STREAM} e \val{0}.
-A partire dal kernel 2.6.27 la funzione supporta anche l'uso dei flag
-\const{SOCK\_NONBLOCK} e \const{SOCK\_CLOEXEC} (trattati in
-sez.~\ref{sec:sock_type}) nell'indicazione del tipo di socket, con effetto
-identico agli analoghi \const{O\_CLOEXEC} e \const{O\_NONBLOCK} di una
-\func{open} (vedi tab.~\ref{tab:open_operation_flag}).
+A partire dal kernel 2.6.27 la funzione supporta nell'indicazione del tipo di
+socket anche i due flag \const{SOCK\_NONBLOCK} e \const{SOCK\_CLOEXEC}
+(trattati in sez.~\ref{sec:sock_type}), con effetto identico agli analoghi
+\const{O\_CLOEXEC} e \const{O\_NONBLOCK} di una \func{open} (vedi
+tab.~\ref{tab:open_operation_flag}).
L'utilità di chiamare questa funzione per evitare due chiamate a \func{pipe}
può sembrare limitata; in realtà l'utilizzo di questa funzione (e dei socket
\end{minipage}
\normalsize
\caption{La struttura \structd{ipc\_perm}, come definita in
- \headfile{sys/ipc.h}.}
+ \headfiled{sys/ipc.h}.}
\label{fig:ipc_ipc_perm}
\end{figure}
associato ad un oggetto ed accedervi. Il problema che sorge a questo punto è
come devono fare per accordarsi sull'uso di una stessa chiave. Se i processi
sono \textsl{imparentati} la soluzione è relativamente semplice, in tal caso
-infatti si può usare il valore speciale \texttt{IPC\_PRIVATE} per creare un
+infatti si può usare il valore speciale \constd{IPC\_PRIVATE} per creare un
nuovo oggetto nel processo padre, l'identificatore così ottenuto sarà
disponibile in tutti i figli, e potrà essere passato come argomento attraverso
una \func{exec}.
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 \itindex{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
-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}.
+con i 16 bit meno significativi 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 collisioni, specie se i
+file sono su dispositivi con lo stesso \textit{minor number}, come
+\file{/dev/hda1} e \file{/dev/sda1}.
In genere quello che si fa è utilizzare un file comune usato dai programmi che
devono comunicare (ad esempio un header comune, o uno dei programmi che devono
Se però si vogliono usare le costanti simboliche di
tab.~\ref{tab:file_mode_flags} occorrerà includere anche il file
-\headfile{sys/stat.h}; alcuni sistemi definiscono le costanti \const{MSG\_R}
-(il valore ottale \texttt{0400}) e \const{MSG\_W} (il valore ottale
+\headfile{sys/stat.h}; alcuni sistemi definiscono le costanti \constd{MSG\_R}
+(il valore ottale \texttt{0400}) e \constd{MSG\_W} (il valore ottale
\texttt{0200}) per indicare i permessi base di lettura e scrittura per il
proprietario, da utilizzare, con gli opportuni shift, pure per il gruppo e gli
altri. In Linux, visto la loro scarsa utilità, queste costanti non sono
controlli è simile a quello dei file, ed avviene secondo questa sequenza:
\begin{itemize*}
\item se il processo ha i privilegi di amministratore (più precisamente la
- capacità \itindex{capability} \const{CAP\_IPC\_OWNER}) l'accesso è sempre
- consentito.
+ capacità \const{CAP\_IPC\_OWNER}) l'accesso è sempre consentito.
\item se l'\ids{UID} effettivo del processo corrisponde o al valore del campo
\var{cuid} o a quello del campo \var{uid} ed il permesso per il proprietario
in \var{mode} è appropriato\footnote{per appropriato si intende che è
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 \itindex{umask} \textit{umask} (si ricordi quanto esposto in
+il valore di \textit{umask} (si ricordi quanto esposto in
sez.~\ref{sec:file_perm_management}) non ha alcun significato.
relativi al \textit{SysV-IPC}) solo con una ricompilazione del kernel. A
partire dal kernel 2.4.x è possibile cambiare questi valori a sistema attivo
scrivendo sui file \sysctlrelfile{kernel}{shmmni},
-\sysctlrelfile{kernel}{msgmni} e \sysctlrelfile{kernel}{sem} di
+\sysctlrelfile{kernel}{msgmni} e \sysctlrelfiled{kernel}{sem} di
\file{/proc/sys/kernel} o con l'uso di \func{sysctl}.
\begin{figure}[!htb]
Questo in realtà è quanto avveniva fino ai kernel della serie 2.2, dalla serie
2.4 viene usato lo stesso fattore di moltiplicazione per qualunque tipo di
-oggetto, utilizzando il valore dalla costante \const{IPCMNI} (definita in
+oggetto, utilizzando il valore dalla costante \constd{IPCMNI} (definita in
\file{include/linux/ipc.h}), che indica il limite massimo complessivo per il
numero di tutti gli oggetti presenti nel \textit{SysV-IPC}, ed il cui default
è 32768. Si evita così il riutilizzo degli stessi numeri, e si fa sì che
I valori di default sono per l'uso delle code di messaggi e per 5 ripetizioni
del ciclo. Per questo motivo se non si utilizzano opzioni verrà eseguito per
-cinque volte il ciclo (\texttt{\small 7--11}), in cui si crea una coda di
+cinque volte il ciclo (\texttt{\small 7-11}), in cui si crea una coda di
messaggi (\texttt{\small 8}), se ne stampa l'identificativo (\texttt{\small
9}) e la si rimuove (\texttt{\small 10}). Non stiamo ad approfondire adesso
il significato delle funzioni utilizzate, che verranno esaminate nelle
Se invece si vuole creare una nuova coda di messaggi \param{flag} non può
essere nullo e deve essere fornito come maschera binaria, impostando il bit
-corrispondente al valore \const{IPC\_CREAT}. In questo caso i nove bit meno
+corrispondente al valore \constd{IPC\_CREAT}. In questo caso i nove bit meno
significativi di \param{flag} saranno usati come permessi per il nuovo
oggetto, secondo quanto illustrato in sez.~\ref{sec:ipc_sysv_access_control}.
-Se si imposta anche il bit corrispondente a \const{IPC\_EXCL} la funzione avrà
+Se si imposta anche il bit corrispondente a \constd{IPC\_EXCL} la funzione avrà
successo solo se l'oggetto non esiste già, fallendo con un errore di
\errcode{EEXIST} altrimenti.
& \textbf{Significato} \\
\hline
\hline
- \const{MSGMNI}& 16& \file{msgmni} & Numero massimo di code di
+ \constd{MSGMNI}& 16& \file{msgmni} & Numero massimo di code di
messaggi.\\
- \const{MSGMAX}& 8192& \file{msgmax} & Dimensione massima di un singolo
+ \constd{MSGMAX}& 8192& \file{msgmax} & Dimensione massima di un singolo
messaggio.\\
- \const{MSGMNB}&16384& \file{msgmnb} & Dimensione massima del contenuto di
+ \constd{MSGMNB}&16384& \file{msgmnb} & Dimensione massima del contenuto di
una coda.\\
\hline
\end{tabular}
definiti staticamente e corrispondenti alle prime tre costanti riportate in
tab.~\ref{tab:ipc_msg_limits}. Come accennato però con tutte le versioni più
recenti del kernel con Linux è possibile modificare questi limiti attraverso
-l'uso di \func{sysctl} o scrivendo nei file \sysctlrelfile{kernel}{msgmax},
-\sysctlrelfile{kernel}{msgmnb} e \sysctlrelfile{kernel}{msgmni} di
+l'uso di \func{sysctl} o scrivendo nei file \sysctlrelfiled{kernel}{msgmax},
+\sysctlrelfiled{kernel}{msgmnb} e \sysctlrelfiled{kernel}{msgmni} di
\file{/proc/sys/kernel/}.
-Una coda di messaggi è costituita da una \itindex{linked~list} \textit{linked
- list}.\footnote{una \itindex{linked~list} \textit{linked list} è una tipica
- struttura di dati, organizzati in una lista in cui ciascun elemento contiene
- un puntatore al successivo. In questo modo la struttura è veloce
- nell'estrazione ed immissione dei dati dalle estremità dalla lista (basta
- aggiungere un elemento in testa o in coda ed aggiornare un puntatore), e
- relativamente veloce da attraversare in ordine sequenziale (seguendo i
- puntatori), è invece relativamente lenta nell'accesso casuale e nella
- ricerca.} I nuovi messaggi vengono inseriti in coda alla lista e vengono
-letti dalla cima, in fig.~\ref{fig:ipc_mq_schema} si è riportato uno schema
-semplificato con cui queste strutture vengono mantenute dal kernel. Lo schema
-illustrato in realtà è una semplificazione di quello usato fino ai kernel
-della serie 2.2. A partire della serie 2.4 la gestione delle code di messaggi
-è effettuata in maniera diversa (e non esiste una struttura \struct{msqid\_ds}
-nel kernel), ma abbiamo mantenuto lo schema precedente dato che illustra in
-maniera più che adeguata i principi di funzionamento delle code di messaggi.
+\itindbeg{linked~list}
+
+Una coda di messaggi è costituita da una \textit{linked list}.\footnote{una
+ \textit{linked list} è una tipica struttura di dati, organizzati in una
+ lista in cui ciascun elemento contiene un puntatore al successivo. In questo
+ modo la struttura è veloce nell'estrazione ed immissione dei dati dalle
+ estremità dalla lista (basta aggiungere un elemento in testa o in coda ed
+ aggiornare un puntatore), e relativamente veloce da attraversare in ordine
+ sequenziale (seguendo i puntatori), è invece relativamente lenta
+ nell'accesso casuale e nella ricerca.} I nuovi messaggi vengono inseriti in
+coda alla lista e vengono letti dalla cima, in fig.~\ref{fig:ipc_mq_schema} si
+è riportato uno schema semplificato con cui queste strutture vengono mantenute
+dal kernel. Lo schema illustrato in realtà è una semplificazione di quello
+usato fino ai kernel della serie 2.2. A partire della serie 2.4 la gestione
+delle code di messaggi è effettuata in maniera diversa (e non esiste una
+struttura \kstruct{msqid\_ds} nel kernel), ma abbiamo mantenuto lo schema
+precedente dato che illustra in maniera più che adeguata i principi di
+funzionamento delle code di messaggi.
+
+\itindend{linked~list}
\begin{figure}[!htb]
\centering \includegraphics[width=13cm]{img/mqstruct}
- \caption{Schema della struttura di una coda messaggi.}
+ \caption{Schema delle strutture di una coda di messaggi
+ (\kstructd{msqid\_ds} e \kstructd{msg}).}
\label{fig:ipc_mq_schema}
\end{figure}
-A ciascuna coda è associata una struttura \struct{msqid\_ds} la cui
+A ciascuna coda è associata una struttura \kstruct{msqid\_ds} la cui
definizione è riportata in fig.~\ref{fig:ipc_msqid_ds} ed a cui si accede
-includendo \headfile{sys/msg.h};
+includendo \headfiled{sys/msg.h};
%
% INFO: sotto materiale obsoleto e non interessante
% In questa struttura il
che specifica il tipo di azione da eseguire. I valori possibili
per \param{cmd} sono:
\begin{basedescript}{\desclabelwidth{1.6cm}\desclabelstyle{\nextlinelabel}}
-\item[\const{IPC\_STAT}] Legge le informazioni riguardo la coda nella
+\item[\constd{IPC\_STAT}] Legge le informazioni riguardo la coda nella
struttura \struct{msqid\_ds} indicata da \param{buf}. Occorre avere il
permesso di lettura sulla coda.
-\item[\const{IPC\_RMID}] Rimuove la coda, cancellando tutti i dati, con
+\item[\constd{IPC\_RMID}] Rimuove la coda, cancellando tutti i dati, con
effetto immediato. Tutti i processi che cercheranno di accedere alla coda
riceveranno un errore di \errcode{EIDRM}, e tutti processi in attesa su
funzioni di lettura o di scrittura sulla coda saranno svegliati ricevendo
il medesimo errore. Questo comando può essere eseguito solo da un processo
con \ids{UID} effettivo corrispondente al creatore o al proprietario della
coda, o all'amministratore.
-\item[\const{IPC\_SET}] Permette di modificare i permessi ed il proprietario
+\item[\constd{IPC\_SET}] Permette di modificare i permessi ed il proprietario
della coda, ed il limite massimo sulle dimensioni del totale dei messaggi in
essa contenuti (\var{msg\_qbytes}). I valori devono essere passati in una
struttura \struct{msqid\_ds} puntata da \param{buf}. Per modificare i
occorre essere il proprietario o il creatore della coda, oppure
l'amministratore e lo stesso vale per \var{msg\_qbytes}. Infine solo
l'amministratore (più precisamente un processo con la capacità
- \itindex{capability} \const{CAP\_IPC\_RESOURCE}) ha la facoltà di
- incrementarne il valore a limiti superiori a \const{MSGMNB}. Se eseguita con
- successo la funzione aggiorna anche il campo \var{msg\_ctime}.
+ \const{CAP\_IPC\_RESOURCE}) ha la facoltà di incrementarne il valore a
+ limiti superiori a \const{MSGMNB}. Se eseguita con successo la funzione
+ aggiorna anche il campo \var{msg\_ctime}.
\end{basedescript}
A questi tre valori, che sono quelli previsti dallo standard, su Linux se ne
-affiancano altri tre (\const{IPC\_INFO}, \const{MSG\_STAT} e
-\const{MSG\_INFO}) introdotti ad uso del programma \cmd{ipcs} per ottenere le
+affiancano altri tre (\constd{IPC\_INFO}, \constd{MSG\_STAT} e
+\constd{MSG\_INFO}) introdotti ad uso del programma \cmd{ipcs} per ottenere le
informazioni generali relative alle risorse usate dalle code di
messaggi. Questi potranno essere modificati o rimossi in favore dell'uso di
\texttt{/proc}, per cui non devono essere usati e non li tratteremo.
cioè \var{message} è una propria struttura che si passa alla funzione,
\param{msgsz} dovrà essere uguale a \code{sizeof(message)-sizeof(long)}, (se
consideriamo il caso dell'esempio in fig.~\ref{fig:ipc_msbuf}, \param{msgsz}
-dovrà essere pari a \const{LENGTH}).
+dovrà essere pari a \var{LENGTH}).
Per capire meglio il funzionamento della funzione riprendiamo in
considerazione la struttura della coda illustrata in
-fig.~\ref{fig:ipc_mq_schema}. Alla chiamata di \func{msgsnd} il nuovo messaggio
-sarà aggiunto in fondo alla lista inserendo una nuova struttura \struct{msg},
-il puntatore \var{msg\_last} di \struct{msqid\_ds} verrà aggiornato, come pure
-il puntatore al messaggio successivo per quello che era il precedente ultimo
-messaggio; il valore di \var{mtype} verrà mantenuto in \var{msg\_type} ed il
-valore di \param{msgsz} in \var{msg\_ts}; il testo del messaggio sarà copiato
-all'indirizzo specificato da \var{msg\_spot}.
+fig.~\ref{fig:ipc_mq_schema}. Alla chiamata di \func{msgsnd} il nuovo
+messaggio sarà aggiunto in fondo alla lista inserendo una nuova struttura
+\kstruct{msg}, il puntatore \var{msg\_last} di \kstruct{msqid\_ds} verrà
+aggiornato, come pure il puntatore al messaggio successivo per quello che era
+il precedente ultimo messaggio; il valore di \var{mtype} verrà mantenuto in
+\var{msg\_type} ed il valore di \param{msgsz} in \var{msg\_ts}; il testo del
+messaggio sarà copiato all'indirizzo specificato da \var{msg\_spot}.
Il valore dell'argomento \param{flag} permette di specificare il comportamento
della funzione. Di norma, quando si specifica un valore nullo, la funzione
ritorna immediatamente a meno che si sia ecceduto il valore di
\var{msg\_qbytes}, o il limite di sistema sul numero di messaggi, nel qual
caso si blocca. Se si specifica per \param{flag} il valore
-\const{IPC\_NOWAIT} la funzione opera in modalità non-bloccante, ed in questi
+\constd{IPC\_NOWAIT} la funzione opera in modalità non-bloccante, ed in questi
casi ritorna immediatamente con un errore di \errcode{EAGAIN}.
Se non si specifica \const{IPC\_NOWAIT} la funzione resterà bloccata fintanto
formato analogo a quello di fig.~\ref{fig:ipc_msbuf}. Una volta estratto, il
messaggio sarà rimosso dalla coda. L'argomento \param{msgsz} indica la
lunghezza massima del testo del messaggio (equivalente al valore del parametro
-\const{LENGTH} nell'esempio di fig.~\ref{fig:ipc_msbuf}).
+\var{LENGTH} nell'esempio di fig.~\ref{fig:ipc_msbuf}).
Se il testo del messaggio ha lunghezza inferiore a \param{msgsz} esso viene
rimosso dalla coda; in caso contrario, se \param{msgflg} è impostato a
-\const{MSG\_NOERROR}, il messaggio viene troncato e la parte in eccesso viene
+\constd{MSG\_NOERROR}, il messaggio viene troncato e la parte in eccesso viene
perduta, altrimenti il messaggio non viene estratto e la funzione ritorna con
un errore di \errcode{E2BIG}.
Il valore di \param{msgflg} permette di controllare il comportamento della
funzione, esso può essere nullo o una maschera binaria composta da uno o più
valori. Oltre al precedente \const{MSG\_NOERROR}, sono possibili altri due
-valori: \const{MSG\_EXCEPT}, che permette, quando \param{msgtyp} è positivo,
+valori: \constd{MSG\_EXCEPT}, che permette, quando \param{msgtyp} è positivo,
di leggere il primo messaggio nella coda con tipo diverso da \param{msgtyp}, e
\const{IPC\_NOWAIT} che causa il ritorno immediato della funzione quando non
ci sono messaggi sulla coda.
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 \itindex{polling} \textit{polling} che esegua un ciclo di attesa su
-ciascuna di esse.
+di \textit{polling} che esegua un ciclo di attesa su ciascuna di esse.
Come esempio dell'uso delle code di messaggi possiamo riscrivere il nostro
server di \textit{fortunes} usando queste al posto delle \textit{fifo}. In
Il programma, oltre alle solite variabili per il nome del file da cui leggere
le \textit{fortunes} e per il vettore di stringhe che contiene le frasi,
definisce due strutture appositamente per la comunicazione; con
-\var{msgbuf\_read} vengono passate (\texttt{\small 8--11}) le richieste mentre
-con \var{msgbuf\_write} vengono restituite (\texttt{\small 12--15}) le frasi.
+\var{msgbuf\_read} vengono passate (\texttt{\small 8-11}) le richieste mentre
+con \var{msgbuf\_write} vengono restituite (\texttt{\small 12-15}) le frasi.
La gestione delle opzioni si è al solito omessa, essa si curerà di impostare
nella variabile \var{n} il numero di frasi da leggere specificato a linea di
comando ed in \var{fortunefilename} il file da cui leggerle. Dopo aver
-installato (\texttt{\small 19--21}) i gestori dei segnali per trattare
+installato (\texttt{\small 19-21}) i gestori dei segnali per trattare
l'uscita dal server, viene prima controllato (\texttt{\small 22}) il numero di
frasi richieste abbia senso (cioè sia maggiore di zero), le quali poi vengono
lette (\texttt{\small 23}) nel vettore in memoria con la stessa funzione
sorgenti del server) con la quale poi si esegue (\texttt{\small 26}) la
creazione della stessa (si noti come si sia chiamata \func{msgget} con un
valore opportuno per l'argomento \param{flag}), avendo cura di abortire il
-programma (\texttt{\small 27--29}) in caso di errore.
+programma (\texttt{\small 27-29}) in caso di errore.
Finita la fase di inizializzazione il server prima (\texttt{\small 32}) chiama
la funzione \func{daemon} per andare in background e poi esegue in permanenza
-il ciclo principale (\texttt{\small 33--40}). Questo inizia (\texttt{\small
+il ciclo principale (\texttt{\small 33-40}). Questo inizia (\texttt{\small
34}) con il porsi in attesa di un messaggio di richiesta da parte di un
client. Si noti infatti come \func{msgrcv} richieda un messaggio con
\var{mtype} uguale a 1, questo è il valore usato per le richieste dato che
funzione potrà bloccarsi fintanto che non venga liberato dello spazio.
Si noti che il programma può terminare solo grazie ad una interruzione da
-parte di un segnale; in tal caso verrà eseguito (\texttt{\small 45--48}) il
+parte di un segnale; in tal caso verrà eseguito (\texttt{\small 45-48}) il
gestore \code{HandSIGTERM}, che semplicemente si limita a cancellare la coda
(\texttt{\small 46}) ed ad uscire (\texttt{\small 47}).
fig.~\ref{fig:ipc_mq_fortune_server}.
Il client in questo caso è molto semplice; la prima parte del programma
-(\texttt{\small 4--9}) si occupa di accedere alla coda di messaggi, ed è
+(\texttt{\small 4-9}) si occupa di accedere alla coda di messaggi, ed è
identica a quanto visto per il server, solo che in questo caso \func{msgget}
non viene chiamata con il flag di creazione in quanto la coda deve essere
preesistente. In caso di errore (ad esempio se il server non è stato avviato)
il programma termina immediatamente.
Una volta acquisito l'identificatore della coda il client compone
-(\texttt{\small 12--13}) il messaggio di richiesta in \var{msg\_read}, usando
+(\texttt{\small 12-13}) il messaggio di richiesta in \var{msg\_read}, usando
1 per il tipo ed inserendo il proprio \ids{PID} come dato da passare al
server. Calcolata (\texttt{\small 14}) la dimensione, provvede
(\texttt{\small 15}) ad immettere la richiesta sulla coda.
\textit{fifo} si aveva il problema delle \textit{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
-\itindex{inode} \textit{inode} di un filesystem, sia perché, con il riutilizzo
-dei \ids{PID} da parte dei processi, un client eseguito in un momento
-successivo potrebbe ricevere un messaggio non indirizzato a lui.
+\textit{inode} di un filesystem, sia perché, con il riutilizzo dei \ids{PID}
+da parte dei processi, un client eseguito in un momento successivo potrebbe
+ricevere un messaggio non indirizzato a lui.
\subsection{I semafori}
I semafori non sono propriamente meccanismi di intercomunicazione come
\textit{pipe}, \textit{fifo} e code di messaggi, poiché non consentono di
scambiare dati fra processi, ma servono piuttosto come meccanismi di
-sincronizzazione o 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 infatti non è altro che un
-contatore mantenuto nel kernel che determina se consentire o meno la
-prosecuzione dell'esecuzione di un programma. In questo modo si può
-controllare l'accesso ad una risorsa condivisa da più processi, associandovi
-un semaforo che assicuri che non possa essere usata da più di un processo alla
-volta.
+sincronizzazione o di protezione per le \textsl{sezioni critiche} del codice
+(si ricordi quanto detto in sez.~\ref{sec:proc_race_cond}). Un semaforo
+infatti non è altro che un contatore mantenuto nel kernel che determina se
+consentire o meno la prosecuzione dell'esecuzione di un programma. In questo
+modo si può controllare l'accesso ad una risorsa condivisa da più processi,
+associandovi un semaforo che assicuri che non possa essere usata da più di un
+processo alla volta.
Il concetto di semaforo è uno dei concetti base nella programmazione ed è
assolutamente generico, così come del tutto generali sono modalità con cui lo
\textbf{Costante} & \textbf{Valore} & \textbf{Significato} \\
\hline
\hline
- \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.\\
- \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
- all'uscita. \\
+ \constd{SEMMNI}& 128 & Numero massimo di insiemi di semafori.\\
+ \constd{SEMMSL}& 250 & Numero massimo di semafori per insieme.\\
+ \constd{SEMMNS}&\const{SEMMNI}*\const{SEMMSL}& Numero massimo di semafori
+ nel sistema.\\
+ \constd{SEMVMX}& 32767 & Massimo valore per un semaforo.\\
+ \constd{SEMOPM}& 32 & Massimo numero di operazioni per chiamata a
+ \func{semop}. \\
+ \constd{SEMMNU}&\const{SEMMNS}& Massimo numero di strutture di ripristino.\\
+ \constd{SEMUME}&\const{SEMOPM}& Massimo numero di voci di ripristino.\\
+ \constd{SEMAEM}&\const{SEMVMX}& Valore massimo per l'aggiustamento
+ all'uscita. \\
\hline
\end{tabular}
\caption{Valori delle costanti associate ai limiti degli insiemi di
\includestruct{listati/semun.h}
\end{minipage}
\normalsize
- \caption{La definizione dei possibili valori di una \direct{union}
+ \caption{La definizione dei possibili valori di una \dirct{union}
\structd{semun}, usata come quarto argomento della funzione
\func{semctl}.}
\label{fig:ipc_semun}
\file{sys/sem.h}, ma nelle versioni più recenti questo non avviene più in
quanto lo standard POSIX.1-2001 richiede che sia sempre definita a cura del
chiamante. In questa seconda evenienza le \acr{glibc} definiscono però la
-macro \macro{\_SEM\_SEMUN\_UNDEFINED} che può essere usata per controllare la
+macro \macrod{\_SEM\_SEMUN\_UNDEFINED} che può essere usata per controllare la
situazione.
Come già accennato sia il comportamento della funzione che il numero di
\var{sem\_ctime}. L'\ids{UID} effettivo del processo deve corrispondere o
al creatore o al proprietario dell'insieme, o all'amministratore.
L'argomento \param{semnum} viene ignorato.
-\item[\const{GETALL}] Restituisce il valore corrente di ciascun semaforo
+\item[\constd{GETALL}] Restituisce il valore corrente di ciascun semaforo
dell'insieme (corrispondente al campo \var{semval} di \struct{sem}) nel
vettore indicato da \param{arg.array}. Occorre avere il permesso di lettura.
L'argomento \param{semnum} viene ignorato.
-\item[\const{GETNCNT}] Restituisce come valore di ritorno della funzione il
+\item[\constd{GETNCNT}] Restituisce come valore di ritorno della funzione il
numero di processi in attesa che il semaforo \param{semnum} dell'insieme
\param{semid} venga incrementato (corrispondente al campo \var{semncnt} di
\struct{sem}). Va invocata con tre argomenti. Occorre avere il permesso di
lettura.
-\item[\const{GETPID}] Restituisce come valore di ritorno della funzione il
+\item[\constd{GETPID}] Restituisce come valore di ritorno della funzione il
\ids{PID} dell'ultimo processo che ha compiuto una operazione sul semaforo
\param{semnum} dell'insieme \param{semid} (corrispondente al campo
\var{sempid} di \struct{sem}). Va invocata con tre argomenti. Occorre avere
il permesso di lettura.
-\item[\const{GETVAL}] Restituisce come valore di ritorno della funzione il il
+\item[\constd{GETVAL}] Restituisce come valore di ritorno della funzione il il
valore corrente del semaforo \param{semnum} dell'insieme \param{semid}
(corrispondente al campo \var{semval} di \struct{sem}). Va invocata con tre
argomenti. Occorre avere il permesso di lettura.
-\item[\const{GETZCNT}] Restituisce come valore di ritorno della funzione il
+\item[\constd{GETZCNT}] Restituisce come valore di ritorno della funzione il
numero di processi in attesa che il valore del semaforo \param{semnum}
dell'insieme \param{semid} diventi nullo (corrispondente al campo
\var{semncnt} di \struct{sem}). Va invocata con tre argomenti. Occorre
avere il permesso di lettura.
-\item[\const{SETALL}] Inizializza il valore di tutti i semafori dell'insieme,
+\item[\constd{SETALL}] Inizializza il valore di tutti i semafori dell'insieme,
aggiornando il campo \var{sem\_ctime} di \struct{semid\_ds}. I valori devono
essere passati nel vettore indicato da \param{arg.array}. Si devono avere i
privilegi di scrittura. L'argomento \param{semnum} viene ignorato.
-\item[\const{SETVAL}] Inizializza il semaforo \param{semnum} al valore passato
+\item[\constd{SETVAL}] Inizializza il semaforo \param{semnum} al valore passato
dall'argomento \param{arg.val}, aggiornando il campo \var{sem\_ctime} di
\struct{semid\_ds}. Si devono avere i privilegi di scrittura.
\end{basedescript}
Come per \func{msgctl} esistono tre ulteriori valori, \const{IPC\_INFO},
-\const{SEM\_STAT} e \const{SEM\_INFO}, specifici di Linux e fuori da ogni
+\constd{SEM\_STAT} e \constd{SEM\_INFO}, specifici di Linux e fuori da ogni
standard, creati specificamente ad uso del comando \cmd{ipcs}. Dato che anche
questi potranno essere modificati o rimossi, non devono essere utilizzati e
pertanto non li tratteremo.
Il campo \var{sem\_flg} è un flag, mantenuto come maschera binaria, per il
quale possono essere impostati i due valori \const{IPC\_NOWAIT} e
-\const{SEM\_UNDO}. Impostando \const{IPC\_NOWAIT} si fa si che in tutti quei
+\constd{SEM\_UNDO}. Impostando \const{IPC\_NOWAIT} si fa si che in tutti quei
casi in cui l'esecuzione di una operazione richiederebbe di porre il processo
vada nello stato di \textit{sleep}, invece di bloccarsi \func{semop} ritorni
immediatamente (abortendo così le eventuali operazioni restanti) con un errore
\begin{figure}[!htb]
\centering \includegraphics[width=12cm]{img/semtruct}
- \caption{Schema della struttura di un insieme di semafori.}
+ \caption{Schema delle varie strutture di un insieme di semafori
+ (\kstructd{semid\_ds}, \kstructd{sem}, \kstructd{sem\_queue} e
+ \kstructd{sem\_undo}).}
\label{fig:ipc_sem_schema}
\end{figure}
Alla creazione di un nuovo insieme viene allocata una nuova strutture
-\struct{semid\_ds} ed il relativo vettore di strutture \struct{sem}. Quando si
-richiede una operazione viene anzitutto verificato che tutte le operazioni
+\kstruct{semid\_ds} ed il relativo vettore di strutture \kstruct{sem}. Quando
+si richiede una operazione viene anzitutto verificato che tutte le operazioni
possono avere successo; se una di esse comporta il blocco del processo il
kernel crea una struttura \kstruct{sem\_queue} che viene aggiunta in fondo
alla coda di attesa associata a ciascun insieme di semafori, che viene
referenziata tramite i campi \var{sem\_pending} e \var{sem\_pending\_last} di
-\struct{semid\_ds}. Nella struttura viene memorizzato il riferimento alle
+\kstruct{semid\_ds}. 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
-\itindex{scheduler} \textit{scheduler} per passare all'esecuzione di un altro
-processo.
+\textit{scheduler} per passare all'esecuzione di un altro processo.
Se invece tutte le operazioni possono avere successo queste vengono eseguite
immediatamente, dopo di che il kernel esegue una scansione della coda di
\label{fig:ipc_mutex_create}
\end{figure}
-La prima funzione (\texttt{\small 2--15}) è \func{MutexCreate} che data una
+La prima funzione (\texttt{\small 2-15}) è \func{MutexCreate} che data una
chiave crea il semaforo usato per il mutex e lo inizializza, restituendone
l'identificatore. Il primo passo (\texttt{\small 6}) è chiamare \func{semget}
con \const{IPC\_CREATE} per creare il semaforo qualora non esista,
assegnandogli i privilegi di lettura e scrittura per tutti. In caso di errore
-(\texttt{\small 7--9}) si ritorna subito il risultato di \func{semget},
+(\texttt{\small 7-9}) si ritorna subito il risultato di \func{semget},
altrimenti (\texttt{\small 10}) si inizializza il semaforo chiamando
\func{semctl} con il comando \const{SETVAL}, utilizzando l'unione
\struct{semunion} dichiarata ed avvalorata in precedenza (\texttt{\small 4})
ad 1 per significare che risorsa è libera. In caso di errore (\texttt{\small
- 11--13}) si restituisce il valore di ritorno di \func{semctl}, altrimenti
+ 11-13}) si restituisce il valore di ritorno di \func{semctl}, altrimenti
(\texttt{\small 14}) si ritorna l'identificatore del semaforo.
-La seconda funzione (\texttt{\small 17--20}) è \func{MutexFind}, che, data una
+La seconda funzione (\texttt{\small 17-20}) è \func{MutexFind}, che, data una
chiave, restituisce l'identificatore del semaforo ad essa associato. La
comprensione del suo funzionamento è immediata in quanto essa è soltanto un
\textit{wrapper}\footnote{si chiama così una funzione usata per fare da
l'identificatore associato alla chiave, il valore di ritorno di quest'ultima
viene passato all'indietro al chiamante.
-La terza funzione (\texttt{\small 22--25}) è \func{MutexRead} che, dato un
+La terza funzione (\texttt{\small 22-25}) è \func{MutexRead} che, dato un
identificatore, restituisce il valore del semaforo associato al mutex. Anche
in questo caso la funzione è un \textit{wrapper} per una chiamata a
\func{semctl} con il comando \const{GETVAL}, che permette di restituire il
valore del semaforo.
-La quarta e la quinta funzione (\texttt{\small 36--44}) sono \func{MutexLock},
+La quarta e la quinta funzione (\texttt{\small 36-44}) sono \func{MutexLock},
e \func{MutexUnlock}, che permettono rispettivamente di bloccare e sbloccare
il mutex. Entrambe fanno da wrapper per \func{semop}, utilizzando le due
strutture \var{sem\_lock} e \var{sem\_unlock} definite in precedenza
-(\texttt{\small 27--34}). Si noti come per queste ultime si sia fatto uso
+(\texttt{\small 27-34}). Si noti come per queste ultime si sia fatto uso
dell'opzione \const{SEM\_UNDO} per evitare che il semaforo resti bloccato in
caso di terminazione imprevista del processo.
-L'ultima funzione (\texttt{\small 46--49}) della serie, è \func{MutexRemove},
+L'ultima funzione (\texttt{\small 46-49}) della serie, è \func{MutexRemove},
che rimuove il mutex. Anche in questo caso si ha un wrapper per una chiamata a
\func{semctl} con il comando \const{IPC\_RMID}, che permette di cancellare il
semaforo; il valore di ritorno di quest'ultima viene passato all'indietro.
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 \itindex{file~locking} \textit{file locking}.
+problemi, usando il \textit{file locking}.
\subsection{Memoria condivisa}
di gestione del segmento di memoria condivisa in relazione al sistema della
memoria virtuale.
-Il primo dei due flag è \const{SHM\_HUGETLB} che consente di richiedere la
-creazione del segmento usando una \itindex{huge~page} \textit{huge page}, le
-pagine di memoria di grandi dimensioni introdotte con il kernel 2.6 per
-ottimizzare le prestazioni nei sistemi più recenti che hanno grandi quantità
-di memoria. L'operazione è privilegiata e richiede che il processo abbia la
-\itindex{capability} \textit{capability} \const{CAP\_IPC\_LOCK}. Questa
-funzionalità è specifica di Linux e non è portabile.
+Il primo dei due flag è \constd{SHM\_HUGETLB} che consente di richiedere la
+creazione del segmento usando una \textit{huge page}, le pagine di memoria di
+grandi dimensioni introdotte con il kernel 2.6 per ottimizzare le prestazioni
+nei sistemi più recenti che hanno grandi quantità di memoria. L'operazione è
+privilegiata e richiede che il processo abbia la \textit{capability}
+\const{CAP\_IPC\_LOCK}. Questa funzionalità è specifica di Linux e non è
+portabile.
Il secondo flag aggiuntivo, introdotto a partire dal kernel 2.6.15, è
-\const{SHM\_NORESERVE}, ed ha lo stesso scopo del flag \const{MAP\_NORESERVE}
+\constd{SHM\_NORESERVE}, ed ha lo stesso scopo del flag \const{MAP\_NORESERVE}
di \func{mmap} (vedi sez.~\ref{sec:file_memory_map}): non vengono riservate
-delle pagine di swap ad uso del meccanismo del \textit{copy on write}
-\itindex{copy~on~write} per mantenere le modifiche fatte sul segmento. Questo
-significa che caso di scrittura sul segmento quando non c'è più memoria
-disponibile, si avrà l'emissione di un \signal{SIGSEGV}.
+delle pagine di swap ad uso del meccanismo del \textit{copy on write} per
+mantenere le modifiche fatte sul segmento. Questo significa che caso di
+scrittura sul segmento quando non c'è più memoria disponibile, si avrà
+l'emissione di un \signal{SIGSEGV}.
Infine l'argomento \param{size} specifica la dimensione del segmento di
memoria condivisa; il valore deve essere specificato in byte, ma verrà
& \textbf{Significato} \\
\hline
\hline
- \const{SHMALL}& 0x200000&\sysctlrelfile{kernel}{shmall}
- & Numero massimo di pagine che
- possono essere usate per i segmenti di
- memoria condivisa.\\
- \const{SHMMAX}&0x2000000&\sysctlrelfile{kernel}{shmmax}
- & Dimensione massima di un segmento di memoria
- condivisa.\\
- \const{SHMMNI}& 4096&\sysctlrelfile{kernel}{msgmni}
- & Numero massimo di segmenti di memoria condivisa
+ \constd{SHMALL}& 0x200000&\sysctlrelfiled{kernel}{shmall}
+ & Numero massimo di pagine che
+ possono essere usate per i segmenti di
+ memoria condivisa.\\
+ \constd{SHMMAX}&0x2000000&\sysctlrelfiled{kernel}{shmmax}
+ & Dimensione massima di un segmento di memoria
+ condivisa.\\
+ \constd{SHMMNI}& 4096&\sysctlrelfiled{kernel}{shmmni}
+ & Numero massimo di segmenti di memoria condivisa
presenti nel kernel.\\
- \const{SHMMIN}& 1& --- & Dimensione minima di un segmento di
- 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).\\
- \const{SHMSEG}& --- & --- & Numero massimo di segmenti di
- memoria condivisa per ciascun
- processo (l'implementazione non
- prevede l'esistenza di questo
- limite).\\
+ \constd{SHMMIN}& 1& --- & Dimensione minima di un segmento di
+ memoria condivisa.\\
+ \constd{SHMLBA}&\const{PAGE\_SIZE}&--- & Limite inferiore per le dimensioni
+ minime di un segmento (deve essere
+ allineato alle dimensioni di una
+ pagina di memoria).\\
+ \constd{SHMSEG}& --- & --- & Numero massimo di segmenti di
+ memoria condivisa per ciascun
+ processo (l'implementazione non
+ prevede l'esistenza di questo
+ limite).\\
\hline
si ha a cuore la portabilità. Questi comandi aggiuntivi sono:
\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
-\item[\const{SHM\_LOCK}] Abilita il \itindex{memory~locking} \textit{memory
- locking} sul segmento di memoria condivisa, impedendo che la memoria usata
- per il segmento venga salvata su disco dal meccanismo della
- \index{memoria~virtuale} memoria virtuale. Come illustrato in
+\item[\constd{SHM\_LOCK}] Abilita il \textit{memory locking} sul segmento di
+ memoria condivisa, impedendo che la memoria usata per il segmento venga
+ salvata su disco dal meccanismo della memoria virtuale. Come illustrato in
sez.~\ref{sec:proc_mem_lock} fino al kernel 2.6.9 solo l'amministratore
poteva utilizzare questa capacità,\footnote{che richiedeva la
\textit{capability} \const{CAP\_IPC\_LOCK}.} a partire dal dal kernel
2.6.10 anche gli utenti normali possono farlo fino al limite massimo
determinato da \const{RLIMIT\_MEMLOCK} (vedi
sez.~\ref{sec:sys_resource_limit}).
-\item[\const{SHM\_UNLOCK}] Disabilita il \itindex{memory~locking}
- \textit{memory locking} sul segmento di memoria condivisa. Fino al kernel
- 2.6.9 solo l'amministratore poteva utilizzare questo comando in
- corrispondenza di un segmento da lui bloccato.
+\item[\constd{SHM\_UNLOCK}] Disabilita il \textit{memory locking} sul segmento
+ di memoria condivisa. Fino al kernel 2.6.9 solo l'amministratore poteva
+ utilizzare questo comando in corrispondenza di un segmento da lui bloccato.
\end{basedescript}
A questi due, come per \func{msgctl} e \func{semctl}, si aggiungono tre
-ulteriori valori, \const{IPC\_INFO}, \const{MSG\_STAT} e \const{MSG\_INFO},
+ulteriori valori, \const{IPC\_INFO}, \constd{SHM\_STAT} e \constd{SHM\_INFO},
introdotti ad uso del programma \cmd{ipcs} per ottenere le informazioni
generali relative alle risorse usate dai segmenti di memoria condivisa. Dato
che potranno essere modificati o rimossi in favore dell'uso di \texttt{/proc},
}
{La funzione ritorna l'indirizzo del segmento in caso di successo e $-1$ (in
- un cast a \type{void *}) per un errore, nel qual caso \var{errno} assumerà
+ un cast a \ctyp{void *}) per un errore, nel qual caso \var{errno} assumerà
uno dei valori:
\begin{errlist}
\item[\errcode{EACCES}] il processo non ha i privilegi per accedere al
\const{SHM\_RDONLY} e \const{SHM\_REMAP} che vanno combinate con un OR
aritmetico.
-Specificando \const{SHM\_RND} si evita che \func{shmat} ritorni un errore
+Specificando \constd{SHM\_RND} si evita che \func{shmat} ritorni un errore
quando \param{shmaddr} non è allineato ai confini di una pagina. Si può quindi
usare un valore qualunque per \param{shmaddr}, e il segmento verrà comunque
agganciato, ma al più vicino multiplo di \const{SHMLBA}; il nome della
costante sta infatti per \textit{rounded}, e serve per specificare un
indirizzo come arrotondamento.
-L'uso di \const{SHM\_RDONLY} permette di agganciare il segmento in sola
+L'uso di \constd{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
-\itindex{segment~violation} violazione di accesso con l'emissione di un
-segnale di \signal{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.
-
-Infine \const{SHM\_REMAP} è una estensione specifica di Linux (quindi non
+caso un tentativo di scrivere sul segmento comporterà una violazione di
+accesso con l'emissione di un segnale di \signal{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.
+
+Infine \constd{SHM\_REMAP} è una estensione specifica di Linux (quindi non
portabile) che indica che la mappatura del segmento deve rimpiazzare ogni
precedente mappatura esistente nell'intervallo iniziante
all'indirizzo \param{shmaddr} e di dimensione pari alla lunghezza del
segmento. In condizioni normali questo tipo di richiesta fallirebbe con un
errore di \errval{EINVAL}. Ovviamente usando \const{SHM\_REMAP}
-l'argomento \param{shmaddr} non può essere nullo.
+l'argomento \param{shmaddr} non può essere nullo.
In caso di successo la funzione \func{shmat} aggiorna anche i seguenti campi
della struttura \struct{shmid\_ds}:
più comuni; il codice, contenuto nel file \file{SharedMem.c}, è riportato in
fig.~\ref{fig:ipc_sysv_shm_func}.
-La prima funzione (\texttt{\small 1--16}) è \func{ShmCreate} che, data una
+La prima funzione (\texttt{\small 1-16}) è \func{ShmCreate} che, data una
chiave, crea il segmento di memoria condivisa restituendo il puntatore allo
stesso. La funzione comincia (\texttt{\small 6}) con il chiamare
\func{shmget}, usando il flag \const{IPC\_CREATE} per creare il segmento
qualora non esista, ed assegnandogli i privilegi specificati dall'argomento
\var{perm} e la dimensione specificata dall'argomento \var{shm\_size}. In
-caso di errore (\texttt{\small 7--9}) si ritorna immediatamente un puntatore
+caso di errore (\texttt{\small 7-9}) si ritorna immediatamente un puntatore
nullo, altrimenti (\texttt{\small 10}) si prosegue agganciando il segmento di
memoria condivisa al processo con \func{shmat}. In caso di errore
-(\texttt{\small 11--13}) si restituisce di nuovo un puntatore nullo, infine
+(\texttt{\small 11-13}) si restituisce di nuovo un puntatore nullo, infine
(\texttt{\small 14}) si inizializza con \func{memset} il contenuto del
segmento al valore costante specificato dall'argomento \var{fill}, e poi si
ritorna il puntatore al segmento stesso.
-La seconda funzione (\texttt{\small 17--31}) è \func{ShmFind}, che, data una
+La seconda funzione (\texttt{\small 17-31}) è \func{ShmFind}, che, data una
chiave, restituisce l'indirizzo del segmento ad essa associato. Anzitutto
(\texttt{\small 22}) si richiede l'identificatore del segmento con
-\func{shmget}, ritornando (\texttt{\small 23--25}) un puntatore nullo in caso
+\func{shmget}, ritornando (\texttt{\small 23-25}) un puntatore nullo in caso
di errore. Poi si prosegue (\texttt{\small 26}) agganciando il segmento al
-processo con \func{shmat}, restituendo (\texttt{\small 27--29}) di nuovo un
+processo con \func{shmat}, restituendo (\texttt{\small 27-29}) di nuovo un
puntatore nullo in caso di errore, se invece non ci sono errori si restituisce
il puntatore ottenuto da \func{shmat}.
-La terza funzione (\texttt{\small 32--51}) è \func{ShmRemove} che, data la
+La terza funzione (\texttt{\small 32-51}) è \func{ShmRemove} che, data la
chiave ed il puntatore associati al segmento di memoria condivisa, prima lo
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 38-39}) un valore -1 in caso di errore. Il passo successivo
(\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
+valore di -1 (\texttt{\small 42-45}) in caso di errore, mentre se tutto va
bene si conclude restituendo un valore nullo.
Benché la memoria condivisa costituisca il meccanismo di intercomunicazione
In fig.~\ref{fig:ipc_dirmonitor_main} si è riportata la sezione principale del
corpo del programma server, insieme alle definizioni delle altre funzioni
-usate nel programma e delle \index{variabili!globali} variabili globali,
-omettendo tutto quello che riguarda la gestione delle opzioni e la stampa
-delle istruzioni di uso a video; al solito il codice completo si trova con i
-sorgenti allegati nel file \file{DirMonitor.c}.
+usate nel programma e delle variabili globali, omettendo tutto quello che
+riguarda la gestione delle opzioni e la stampa delle istruzioni di uso a
+video; al solito il codice completo si trova con i sorgenti allegati nel file
+\file{DirMonitor.c}.
\begin{figure}[!htbp]
\footnotesize \centering
\label{fig:ipc_dirmonitor_main}
\end{figure}
-Il programma usa delle \index{variabili!globali} variabili globali
-(\texttt{\small 2--14}) per mantenere i valori relativi agli oggetti usati per
-la comunicazione inter-processo; si è definita inoltre una apposita struttura
-\struct{DirProp} che contiene i dati relativi alle proprietà che si vogliono
-mantenere nella memoria condivisa, per l'accesso da parte dei client.
+Il programma usa delle variabili globali (\texttt{\small 2-14}) per mantenere
+i valori relativi agli oggetti usati per la comunicazione inter-processo; si è
+definita inoltre una apposita struttura \struct{DirProp} che contiene i dati
+relativi alle proprietà che si vogliono mantenere nella memoria condivisa, per
+l'accesso da parte dei client.
Il programma, dopo la sezione, omessa, relativa alla gestione delle opzioni da
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'argomento 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.
Poi, per verificare che l'argomento specifichi effettivamente una directory,
-si esegue (\texttt{\small 24--26}) su di esso una \func{chdir}, uscendo
+si esegue (\texttt{\small 24-26}) su di esso una \func{chdir}, uscendo
immediatamente in caso di errore. Questa funzione serve anche per impostare
-la \index{directory~di~lavoro} directory di lavoro del programma nella
-directory da tenere sotto controllo, in vista del successivo uso della
-funzione \func{daemon}. Si noti come si è potuta fare questa scelta,
-nonostante le indicazioni illustrate in sez.~\ref{sec:sess_daemon}, per il
-particolare scopo del programma, che necessita comunque di restare all'interno
-di una directory.
-
-Infine (\texttt{\small 27--29}) si installano i gestori per i vari segnali di
+la directory di lavoro del programma nella directory da tenere sotto
+controllo, in vista del successivo uso della funzione \func{daemon}. Si noti
+come si è potuta fare questa scelta, nonostante le indicazioni illustrate in
+sez.~\ref{sec:sess_daemon}, per il particolare scopo del programma, che
+necessita comunque di restare all'interno di una directory.
+
+Infine (\texttt{\small 27-29}) si installano i gestori per i vari segnali di
terminazione che, avendo a che fare con un programma che deve essere eseguito
come server, sono il solo strumento disponibile per concluderne l'esecuzione.
-Il passo successivo (\texttt{\small 30--39}) è quello di creare gli oggetti di
+Il passo successivo (\texttt{\small 30-39}) è quello di creare gli oggetti di
intercomunicazione necessari. Si inizia costruendo (\texttt{\small 30}) la
chiave da usare come riferimento con il nome del programma,\footnote{si è
usato un riferimento relativo alla home dell'utente, supposto che i sorgenti
richiede (\texttt{\small 31}) la creazione di un segmento di memoria condivisa
con usando la funzione \func{ShmCreate} illustrata in precedenza (una pagina
di memoria è sufficiente per i dati che useremo), uscendo (\texttt{\small
- 32--35}) qualora la creazione ed il successivo agganciamento al processo non
+ 32-35}) qualora la creazione ed il successivo agganciamento al processo non
abbia successo. Con l'indirizzo \var{shmptr} così ottenuto potremo poi
accedere alla memoria condivisa, che, per come abbiamo lo abbiamo definito,
sarà vista nella forma data da \struct{DirProp}. Infine (\texttt{\small
- 36--39}) utilizzando sempre la stessa chiave, si crea, tramite le funzioni
+ 36-39}) utilizzando sempre la stessa chiave, si crea, tramite le funzioni
di interfaccia già descritte in sez.~\ref{sec:ipc_sysv_sem}, anche un mutex,
che utilizzeremo per regolare l'accesso alla memoria condivisa.
-\begin{figure}[!htbp]
- \footnotesize \centering
- \begin{minipage}[c]{\codesamplewidth}
- \includecodesample{listati/ComputeValues.c}
- \end{minipage}
- \normalsize
- \caption{Codice delle funzioni ausiliarie usate da \file{DirMonitor.c}.}
- \label{fig:ipc_dirmonitor_sub}
-\end{figure}
-
Completata l'inizializzazione e la creazione degli oggetti di
intercomunicazione il programma entra nel ciclo principale (\texttt{\small
- 40--49}) dove vengono eseguite indefinitamente le attività di monitoraggio.
+ 40-49}) dove vengono eseguite indefinitamente le attività di monitoraggio.
Il primo passo (\texttt{\small 41}) è eseguire \func{daemon} per proseguire
con l'esecuzione in background come si conviene ad un programma demone; si
noti che si è mantenuta, usando un valore non nullo del primo argomento, la
-\index{directory~di~lavoro} directory di lavoro corrente. Una volta che il
-programma è andato in background l'esecuzione prosegue all'interno di un ciclo
-infinito (\texttt{\small 42--48}).
+directory di lavoro corrente. Una volta che il programma è andato in
+background l'esecuzione prosegue all'interno di un ciclo infinito
+(\texttt{\small 42-48}).
Si inizia (\texttt{\small 43}) bloccando il mutex con \func{MutexLock} per
poter accedere alla memoria condivisa (la funzione si bloccherà
effettuare la scansione delle voci della directory, chiamando per ciascuna di
esse la funzione \func{ComputeValues}, che esegue tutti i calcoli necessari.
+\begin{figure}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \includecodesample{listati/ComputeValues.c}
+ \end{minipage}
+ \normalsize
+ \caption{Codice delle funzioni ausiliarie usate da \file{DirMonitor.c}.}
+ \label{fig:ipc_dirmonitor_sub}
+\end{figure}
+
+
Il codice di quest'ultima è riportato in fig.~\ref{fig:ipc_dirmonitor_sub}.
-Come si vede la funzione (\texttt{\small 2--16}) è molto semplice e si limita
-a chiamare (\texttt{\small 5}) la funzione \func{stat} sul file indicato da
+Come si vede la funzione (\texttt{\small 2-16}) è molto semplice e si limita a
+chiamare (\texttt{\small 5}) la funzione \func{stat} sul file indicato da
ciascuna voce, per ottenerne i dati, che poi utilizza per incrementare i vari
-contatori nella memoria condivisa, cui accede grazie alla
-\index{variabili!globali} variabile globale \var{shmptr}.
+contatori nella memoria condivisa, cui accede grazie alla variabile globale
+\var{shmptr}.
Dato che la funzione è chiamata da \myfunc{dir\_scan}, si è all'interno del
ciclo principale del programma, con un mutex acquisito, perciò non è
necessario effettuare nessun controllo e si può accedere direttamente alla
memoria condivisa usando \var{shmptr} per riempire i campi della struttura
-\struct{DirProp}; così prima (\texttt{\small 6--7}) si sommano le dimensioni
+\struct{DirProp}; così prima (\texttt{\small 6-7}) si sommano le dimensioni
dei file ed il loro numero, poi, utilizzando le macro di
-tab.~\ref{tab:file_type_macro}, si contano (\texttt{\small 8--14}) quanti ce
+tab.~\ref{tab:file_type_macro}, si contano (\texttt{\small 8-14}) quanti ce
ne sono per ciascun tipo.
In fig.~\ref{fig:ipc_dirmonitor_sub} è riportato anche il codice
-(\texttt{\small 17--23}) del gestore dei segnali di terminazione, usato per
+(\texttt{\small 17-23}) del gestore dei segnali di terminazione, usato per
chiudere il programma. Esso, oltre a provocare l'uscita del programma, si
incarica anche di cancellare tutti gli oggetti di intercomunicazione non più
necessari. Per questo anzitutto (\texttt{\small 19}) acquisisce il mutex con
per identificare il segmento di memoria condivisa ed il mutex, poi
(\texttt{\small 8}) richiede con \func{ShmFind} l'indirizzo della memoria
condivisa agganciando al contempo il segmento al processo, Infine
-(\texttt{\small 17--20}) con \func{MutexFind} si richiede l'identificatore del
+(\texttt{\small 17-20}) con \func{MutexFind} si richiede l'identificatore del
mutex. Completata l'inizializzazione ed ottenuti i riferimenti agli oggetti
di intercomunicazione necessari viene eseguito il corpo principale del
-programma (\texttt{\small 21--33}); si comincia (\texttt{\small 22})
+programma (\texttt{\small 21-33}); si comincia (\texttt{\small 22})
acquisendo il mutex con \func{MutexLock}; qui avviene il blocco del processo
-se la memoria condivisa non è disponibile. Poi (\texttt{\small 23--31}) si
+se la memoria condivisa non è disponibile. Poi (\texttt{\small 23-31}) si
stampano i vari valori mantenuti nella memoria condivisa attraverso l'uso di
\var{shmptr}. Infine (\texttt{\small 41}) con \func{MutexUnlock} si rilascia
il mutex, prima di uscire.
\subsection{I \textsl{file di lock}}
\label{sec:ipc_file_lock}
-\index{file!di lock|(}
+\index{file!di~lock|(}
Come illustrato in sez.~\ref{sec:ipc_sysv_sem} i semafori del \textit{SysV-IPC}
presentano una interfaccia inutilmente complessa e con alcuni difetti
prevede\footnote{questo è quanto dettato dallo standard POSIX.1, ciò non
toglie che in alcune implementazioni questa tecnica possa non funzionare; in
particolare per Linux, nel caso di NFS, si è comunque soggetti alla
- possibilità di una \itindex{race~condition} \textit{race condition}.} che
-essa ritorni un errore quando usata con i flag di \const{O\_CREAT} e
-\const{O\_EXCL}. In tal modo la creazione di un \textsl{file di lock} può
-essere eseguita atomicamente, il processo che crea il file con successo si può
-considerare come titolare del lock (e della risorsa ad esso associata) mentre
-il rilascio si può eseguire con una chiamata ad \func{unlink}.
+ possibilità di una \textit{race condition}.} che essa ritorni un errore
+quando usata con i flag di \const{O\_CREAT} e \const{O\_EXCL}. In tal modo la
+creazione di un \textsl{file di lock} può essere eseguita atomicamente, il
+processo che crea il file con successo si può considerare come titolare del
+lock (e della risorsa ad esso associata) mentre il rilascio si può eseguire
+con una chiamata ad \func{unlink}.
Un esempio dell'uso di questa funzione è mostrato dalle funzioni
\func{LockFile} ed \func{UnlockFile} riportate in fig.~\ref{fig:ipc_file_lock}
(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
+(\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}.
\begin{figure}[!htbp]
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 \itindex{polling}
-\textit{polling}, ed è quindi molto inefficiente.
+può essere eseguito solo con una tecnica di \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
più programmi: qualora si trovi un file di lock il programma che cerca di
accedere alla seriale si limita a segnalare che la risorsa non è disponibile.
-\index{file!di lock|)}
+\index{file!di~lock|)}
\subsection{La sincronizzazione con il \textit{file locking}}
\label{sec:ipc_lock_file}
-Dato che i \index{file!di lock} file di lock presentano gli inconvenienti
-illustrati in precedenza, la tecnica alternativa di sincronizzazione più
-comune è quella di fare ricorso al \itindex{file~locking} \textit{file
- locking} (trattato in sez.~\ref{sec:file_locking}) usando \func{fcntl} su un
-file creato per l'occasione per ottenere un write lock. In questo modo potremo
-usare il lock come un \textit{mutex}: per bloccare la risorsa basterà
-acquisire il lock, per sbloccarla basterà rilasciare il lock. Una richiesta
-fatta con un write lock metterà automaticamente il processo in stato di
-attesa, senza necessità di ricorrere al \itindex{polling} \textit{polling} per
-determinare la disponibilità della risorsa, e al rilascio della stessa da
+Dato che i file di lock presentano gli inconvenienti illustrati in precedenza,
+la tecnica alternativa di sincronizzazione più comune è quella di fare ricorso
+al \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}
+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
\includecodesample{listati/MutexLocking.c}
\end{minipage}
\normalsize
- \caption{Il codice delle funzioni che permettono per la gestione dei
- \textit{mutex} con il \itindex{file~locking} \textit{file locking}.}
+ \caption{Il codice delle funzioni che permettono per la gestione dei
+ \textit{mutex} con il \textit{file locking}.}
\label{fig:ipc_flock_mutex}
\end{figure}
Il codice delle varie funzioni usate per implementare un mutex utilizzando il
-\textit{file locking} \itindex{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} è 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
+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 \textit{file locking}, assicurandosi che
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
+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 \itindex{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à.
+aprire il file da usare per il \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
+La terza funzione (\texttt{\small 11-22}) è \func{LockMutex} e serve per
acquisire il mutex. La funzione definisce (\texttt{\small 14}) e inizializza
-(\texttt{\small 16--19}) la struttura \var{lock} da usare per acquisire un
+(\texttt{\small 16-19}) la struttura \var{lock} da usare per acquisire un
write lock sul file, che poi (\texttt{\small 21}) viene richiesto con
\func{fcntl}, restituendo il valore di ritorno di quest'ultima. Se il file è
libero il lock viene acquisito e la funzione ritorna immediatamente;
altrimenti \func{fcntl} si bloccherà (si noti che la si è chiamata con
\const{F\_SETLKW}) fino al rilascio del lock.
-La quarta funzione (\texttt{\small 24--34}) è \func{UnlockMutex} e serve a
+La quarta funzione (\texttt{\small 24-34}) è \func{UnlockMutex} e serve a
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
+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 \itindex{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.
+chiamata a \func{fcntl}. Avendo usato il \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
+La quinta funzione (\texttt{\small 36-39}) è \func{RemoveMutex} e serve a
cancellare il mutex. Anche questa funzione è stata definita per mantenere una
analogia con le funzioni basate sui semafori, e si limita a cancellare
(\texttt{\small 38}) il file con una chiamata ad \func{unlink}. Si noti che in
per rilasciare un mutex occorrerà prima chiamare \func{UnlockMutex} oppure
chiudere il file usato per il lock.
-La sesta funzione (\texttt{\small 41--55}) è \func{ReadMutex} e serve a
-leggere lo stato del mutex. In questo caso si prepara (\texttt{\small 46--49})
+La sesta funzione (\texttt{\small 41-55}) è \func{ReadMutex} e serve a
+leggere lo stato del mutex. In questo caso si prepara (\texttt{\small 46-49})
la solita struttura \var{lock} come l'acquisizione del lock, ma si effettua
(\texttt{\small 51}) la chiamata a \func{fcntl} usando il comando
\const{F\_GETLK} per ottenere lo stato del lock, e si restituisce
\subsection{Il \textit{memory mapping} anonimo}
\label{sec:ipc_mmap_anonymous}
-\itindbeg{memory~mapping} Abbiamo già visto che quando i processi sono
-\textsl{correlati}, se cioè hanno almeno un progenitore comune, l'uso delle
-\textit{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.
+\itindbeg{memory~mapping}
+
+Abbiamo già visto che quando i processi sono \textsl{correlati}, se cioè hanno
+almeno un progenitore comune, l'uso delle \textit{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.
In sez.~\ref{sec:file_memory_map} abbiamo visto come sia possibile mappare il
contenuto di un file nella memoria di un processo, e che, quando viene usato
nel \textit{memory mapping} anonimo.} Vedremo come utilizzare questa tecnica
più avanti, quando realizzeremo una nuova versione del monitor visto in
sez.~\ref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete.
+
\itindend{memory~mapping}
% TODO: fare esempio di mmap anonima
% trattarlo qui, vedi http://lwn.net/Articles/405346/
% https://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=fcf634098c00dd9cd247447368495f0b79be12d1
+% TODO: con il kernel 3.17 è stata introdotta una fuunzionalità di
+% sigillatura dei file mappati in memoria e la system call memfd
+% (capire se va messo qui o altrove) vedi: http://lwn.net/Articles/593918/
+
+
\section{L'intercomunicazione fra processi di POSIX}
\label{sec:ipc_posix}
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 dalla \acr{glibc} nella sezione che
-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.
+implementa i \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 \textit{SysV-IPC}, per passare ai
può facilmente verificare con il comando \cmd{strace}, sia per la memoria
condivisa che per le code di messaggi varie \textit{system call} utilizzate da
Linux corrispondono in realtà a quelle ordinarie dei file, essendo detti
-oggetti realizzati come tali in appositi filesystem.
+oggetti realizzati come tali usando degli specifici filesystem.
In particolare i permessi associati agli oggetti di IPC POSIX sono identici ai
permessi dei file, ed il controllo di accesso segue esattamente la stessa
La funzione apre la coda di messaggi identificata dall'argomento \param{name}
restituendo il descrittore ad essa associato, del tutto analogo ad un file
descriptor, con l'unica differenza che lo standard prevede un apposito tipo
-\type{mqd\_t}. Nel caso di Linux si tratta in effetti proprio di un normale
+\typed{mqd\_t}. Nel caso di Linux si tratta in effetti proprio di un normale
file descriptor; pertanto, anche se questo comportamento non è portabile, lo
si può tenere sotto osservazione con le funzioni dell'I/O multiplexing (vedi
sez.~\ref{sec:file_multiplexing}) come possibile alternativa all'uso
\texttt{/proc/sys/fs/mqueue}, in particolare i file che controllano i valori
dei limiti sono:
\begin{basedescript}{\desclabelwidth{1.5cm}\desclabelstyle{\nextlinelabel}}
-\item[\sysctlfile{fs/mqueue/msg\_max}] Indica il valore massimo del numero di
+\item[\sysctlfiled{fs/mqueue/msg\_max}] Indica il valore massimo del numero di
messaggi in una coda e agisce come limite superiore per il valore di
\var{attr->mq\_maxmsg} in \func{mq\_open}. Il suo valore di default è 10. Il
- valore massimo è \const{HARD\_MAX} che vale \code{(131072/sizeof(void *))},
+ valore massimo è \constd{HARD\_MAX} che vale \code{(131072/sizeof(void *))},
ed il valore minimo 1 (ma era 10 per i kernel precedenti il 2.6.28). Questo
limite viene ignorato per i processi con privilegi amministrativi (più
- precisamente con la \itindex{capability} \textit{capability}
- \const{CAP\_SYS\_RESOURCE}) ma \const{HARD\_MAX} resta comunque non
- superabile.
+ precisamente con la \textit{capability} \const{CAP\_SYS\_RESOURCE}) ma
+ \const{HARD\_MAX} resta comunque non superabile.
-\item[\sysctlfile{fs/mqueue/msgsize\_max}] Indica il valore massimo della
+\item[\sysctlfiled{fs/mqueue/msgsize\_max}] Indica il valore massimo della
dimensione in byte di un messaggio sulla coda ed agisce come limite
superiore per il valore di \var{attr->mq\_msgsize} in \func{mq\_open}. Il
suo valore di default è 8192. Il valore massimo è 1048576 ed il valore
minimo 128 (ma per i kernel precedenti il 2.6.28 detti limiti erano
rispettivamente \const{INT\_MAX} e 8192). Questo limite viene ignorato dai
- processi con privilegi amministrativi (con la \itindex{capability}
- \textit{capability} \const{CAP\_SYS\_RESOURCE}).
+ processi con privilegi amministrativi (con la \textit{capability}
+ \const{CAP\_SYS\_RESOURCE}).
-\item[\sysctlfile{fs/mqueue/queues\_max}] Indica il numero massimo di code di
+\item[\sysctlfiled{fs/mqueue/queues\_max}] Indica il numero massimo di code di
messaggi creabili in totale sul sistema, il valore di default è 256 ma si
può usare un valore qualunque fra $0$ e \const{INT\_MAX}. Il limite non
viene applicato ai processi con privilegi amministrativi (cioè con la
- \itindex{capability} \textit{capability} \const{CAP\_SYS\_RESOURCE}).
+ \textit{capability} \const{CAP\_SYS\_RESOURCE}).
\end{basedescript}
\fhead{mqueue.h}
\fhead{time.h}
\fdecl{int mq\_timedsend(mqd\_t mqdes, const char *msg\_ptr, size\_t
- msg\_len, unsigned int msg\_prio,\\
-\phantom{int mq\_timedsend(}const struct timespec *abs\_timeout)}
+ msg\_len, \\
+\phantom{int mq\_timedsend(}unsigned int msg\_prio, const struct timespec
+*abs\_timeout)}
\fdesc{Esegue l'inserimento di un messaggio su una coda entro un tempo
specificato}
}
quindi saranno riletti per primi. A parità del valore della priorità il
messaggio sarà inserito in coda a tutti quelli che hanno la stessa priorità
che quindi saranno letti con la politica di una \textit{fifo}. Il valore della
-priorità non può eccedere il limite di sistema \const{MQ\_PRIO\_MAX}, che al
+priorità non può eccedere il limite di sistema \constd{MQ\_PRIO\_MAX}, che al
momento è pari a 32768.
Qualora la coda sia piena, entrambe le funzioni si bloccano, a meno che non
registrazione chiamando nuovamente \func{mq\_notify} all'interno del gestore
del segnale di notifica. A differenza della situazione simile che si aveva con
i segnali non affidabili (l'argomento è stato affrontato in
-\ref{sec:sig_semantics}) questa caratteristica non configura una
-\itindex{race~condition} \textit{race condition} perché l'invio di un segnale
-avviene solo se la coda è vuota; pertanto se si vuole evitare di correre il
-rischio di perdere eventuali ulteriori segnali inviati nel lasso di tempo che
-occorre per ripetere la richiesta di notifica basta avere cura di eseguire
-questa operazione prima di estrarre i messaggi presenti dalla coda.
+\ref{sec:sig_semantics}) questa caratteristica non configura una \textit{race
+ condition} perché l'invio di un segnale avviene solo se la coda è vuota;
+pertanto se si vuole evitare di correre il rischio di perdere eventuali
+ulteriori segnali inviati nel lasso di tempo che occorre per ripetere la
+richiesta di notifica basta avere cura di eseguire questa operazione prima di
+estrarre i messaggi presenti dalla coda.
L'invio del segnale di notifica avvalora alcuni campi di informazione
restituiti al gestore attraverso la struttura \struct{siginfo\_t} (definita in
Il filesystem riconosce, oltre quelle mostrate, le opzioni \texttt{uid} e
\texttt{gid} che identificano rispettivamente utente e gruppo cui assegnarne
la titolarità, e \texttt{nr\_blocks} che permette di specificarne la
-dimensione in blocchi, cioè in multipli di \const{PAGECACHE\_SIZE} che in
+dimensione in blocchi, cioè in multipli di \constd{PAGECACHE\_SIZE} che in
questo caso è l'unità di allocazione elementare.
La funzione che permette di aprire un segmento di memoria condivisa POSIX, ed
impostato il flag \const{FD\_CLOEXEC}. Chiamate effettuate da diversi
processi usando lo stesso nome restituiranno file descriptor associati allo
stesso segmento, così come, nel caso di file ordinari, essi sono associati
-allo stesso \itindex{inode} inode. In questo modo è possibile effettuare una
-chiamata ad \func{mmap} sul file descriptor restituito da \func{shm\_open} ed
-i processi vedranno lo stesso segmento di memoria condivisa.
+allo stesso inode. In questo modo è possibile effettuare una chiamata ad
+\func{mmap} sul file descriptor restituito da \func{shm\_open} ed i processi
+vedranno lo stesso segmento di memoria condivisa.
Quando il nome non esiste si può creare un nuovo segmento specificando
\const{O\_CREAT}; in tal caso il segmento avrà (così come i nuovi file)
da \param{mode} (di cui vengono usati solo i 9 bit meno significativi, non si
applicano pertanto i permessi speciali di sez.~\ref{sec:file_special_perm})
filtrati dal valore dell'\textit{umask} del processo. Come gruppo ed utente
-propritario del segmento saranno presi quelli facenti parte del gruppo
+proprietario del segmento saranno presi quelli facenti parte del gruppo
\textit{effective} del processo chiamante.
Dato che un segmento di lunghezza nulla è di scarsa utilità, una vola che lo
-si è creato per impostarne la dimensione si devrà poi usare \func{ftruncate}
+si è creato per impostarne la dimensione si dovrà poi usare \func{ftruncate}
(vedi sez.~\ref{sec:file_file_size}) prima di mapparlo in memoria con
\func{mmap}. Si tenga presente che una volta chiamata \func{mmap} si può
chiudere il file descriptor ad esso associato (semplicemente con
condivisa POSIX, vediamo come è possibile riscrivere una interfaccia
semplificata analoga a quella vista in fig.~\ref{fig:ipc_sysv_shm_func} per la
memoria condivisa in stile SysV. Il codice completo, di cui si sono riportate
-le parti esseziali in fig.~\ref{fig:ipc_posix_shmmem}, è contenuto nel file
+le parti essenziali in fig.~\ref{fig:ipc_posix_shmmem}, è contenuto nel file
\file{SharedMem.c} dei sorgenti allegati.
\begin{figure}[!htb]
\label{fig:ipc_posix_shmmem}
\end{figure}
-La prima funzione (\texttt{\small 1--24}) è \func{CreateShm} che, dato un nome
+La prima funzione (\texttt{\small 1-24}) è \func{CreateShm} che, dato un nome
nell'argomento \var{name} crea un nuovo segmento di memoria condivisa,
accessibile in lettura e scrittura, e ne restituisce l'indirizzo. Anzitutto si
definiscono (\texttt{\small 8}) i flag per la successiva (\texttt{\small 9})
(creandolo se non esiste, ed uscendo in caso contrario) assegnandogli sul
filesystem i permessi specificati dall'argomento \var{perm}.
-In caso di errore (\texttt{\small 10--12}) si restituisce un puntatore nullo,
+In caso di errore (\texttt{\small 10-12}) si restituisce un puntatore nullo,
altrimenti si prosegue impostando (\texttt{\small 14}) la dimensione del
-segmento con \func{ftruncate}. Di nuovo (\texttt{\small 15--16}) si esce
+segmento con \func{ftruncate}. Di nuovo (\texttt{\small 15-16}) si esce
immediatamente restituendo un puntatore nullo in caso di errore. Poi si passa
(\texttt{\small 18}) a mappare in memoria il segmento con \func{mmap}
specificando dei diritti di accesso corrispondenti alla modalità di apertura.
-Di nuovo si restituisce (\texttt{\small 19--21}) un puntatore nullo in caso di
+Di nuovo si restituisce (\texttt{\small 19-21}) un puntatore nullo in caso di
errore, altrimenti si inizializza (\texttt{\small 22}) il contenuto del
segmento al valore specificato dall'argomento \var{fill} con \func{memset}, e
se ne restituisce (\texttt{\small 23}) l'indirizzo.
-La seconda funzione (\texttt{\small 25--40}) è \func{FindShm} che trova un
+La seconda funzione (\texttt{\small 25-40}) è \func{FindShm} che trova un
segmento di memoria condiviso esistente, restituendone l'indirizzo. In questo
caso si apre (\texttt{\small 31}) il segmento con \func{shm\_open} richiedendo
-che il segmento sia già esistente, in caso di errore (\texttt{\small 31--33})
+che il segmento sia già esistente, in caso di errore (\texttt{\small 31-33})
si ritorna immediatamente un puntatore nullo. Ottenuto il file descriptor del
segmento lo si mappa (\texttt{\small 35}) in memoria con \func{mmap},
-restituendo (\texttt{\small 36--38}) un puntatore nullo in caso di errore, o
+restituendo (\texttt{\small 36-38}) un puntatore nullo in caso di errore, o
l'indirizzo (\texttt{\small 39}) dello stesso in caso di successo.
-La terza funzione (\texttt{\small 40--45}) è \func{RemoveShm}, e serve a
+La terza funzione (\texttt{\small 40-45}) è \func{RemoveShm}, e serve a
cancellare un segmento di memoria condivisa. Dato che al contrario di quanto
avveniva con i segmenti del \textit{SysV-IPC} gli oggetti allocati nel kernel
vengono rilasciati automaticamente quando nessuna li usa più, tutto quello che
\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 \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} della \acr{glibc} (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 \textit{SysV-IPC} (mantenendo così tutti i problemi sottolineati in
+dei semafori POSIX che li realizzava solo a livello di \textit{thread} e non
+di processi,\footnote{questo significava che i semafori erano visibili solo
+ all'interno dei \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}
+della \acr{glibc} (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 \textit{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
\fdesc{Crea un semaforo o ne apre uno esistente.}
}
{La funzione ritorna l'indirizzo del semaforo in caso di successo e
- \const{SEM\_FAILED} per un errore, nel qual caso \var{errno} assumerà uno
+ \constd{SEM\_FAILED} per un errore, nel qual caso \var{errno} assumerà uno
dei valori:
\begin{errlist}
\item[\errcode{EACCES}] il semaforo esiste ma non si hanno permessi
\item[\errcode{EEXIST}] si sono specificati \const{O\_CREAT} e
\const{O\_EXCL} ma il semaforo esiste.
\item[\errcode{EINVAL}] il valore di \param{value} eccede
- \const{SEM\_VALUE\_MAX} o il nome è solo ``\texttt{/}''.
+ \constd{SEM\_VALUE\_MAX} o il nome è solo ``\texttt{/}''.
\item[\errcode{ENAMETOOLONG}] si è utilizzato un nome troppo lungo.
\item[\errcode{ENOENT}] non si è usato \const{O\_CREAT} ed il nome
specificato non esiste.
stesso semaforo. Questo deve essere specificato nella stessa forma utilizzata
per i segmenti di memoria condivisa, con un nome che inizia con ``\texttt{/}''
e senza ulteriori ``\texttt{/}'', vale a dire nella forma
-\texttt{/nomesemaforo}.
+\texttt{/nome-semaforo}.
Con Linux i file associati ai semafori sono mantenuti nel filesystem virtuale
\texttt{/dev/shm}, e gli viene assegnato automaticamente un nome nella forma
-\texttt{sem.nomesemaforo}, si ha cioè una corrispondenza per cui
-\texttt{/nomesemaforo} viene rimappato, nella creazione tramite
-\func{sem\_open}, su \texttt{/dev/shm/sem.nomesemaforo}. Per questo motivo la
+\texttt{sem.nome-semaforo}, si ha cioè una corrispondenza per cui
+\texttt{/nome-semaforo} viene rimappato, nella creazione tramite
+\func{sem\_open}, su \texttt{/dev/shm/sem.nome-semaforo}. Per questo motivo la
dimensione massima per il nome di un semaforo, a differenza di quanto avviene
-per i segmenti di memoria confivisa, è pari a \const{NAME\_MAX}$ - 4$.
+per i segmenti di memoria condivisa, è pari a \const{NAME\_MAX}$ - 4$.
L'argomento \param{oflag} è quello che controlla le modalità con cui opera la
funzione, ed è passato come maschera binaria; i bit corrispondono a quelli
semafori usano la semantica standard dei file per quanto riguarda i controlli
di accesso, questo significa che un nuovo semaforo viene sempre creato con
l'\ids{UID} ed il \ids{GID} effettivo del processo chiamante, e che i permessi
-indicati con \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.
+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.
La funzione restituisce in caso di successo un puntatore all'indirizzo del
semaforo con un valore di tipo \ctyp{sem\_t *}, è questo valore che dovrà
decrementarlo con successo e proseguire.
Si tenga presente che la funzione può sempre essere interrotta da un segnale,
-nel qual caso si avrà un errore di \const{EINTR}; inoltre questo avverrà
-comunque, anche qualora si fosse richiesta la gesione con la semantica BSD,
+nel qual caso si avrà un errore di \errval{EINTR}; inoltre questo avverrà
+comunque, anche qualora si fosse richiesta la gestione con la semantica BSD,
installando il gestore del suddetto segnale con l'opzione \const{SA\_RESTART}
(vedi sez.~\ref{sec:sig_sigaction}) per riavviare le \textit{system call}
interrotte.
essere utilizzata soltanto se viene definita la macro \macro{\_XOPEN\_SOURCE}
ad un valore di almeno 600 o la macro \macro{\_POSIX\_C\_SOURCE} ad un valore
uguale o maggiore di \texttt{200112L} prima di includere
-\headfile{semaphore.h}, la funzione è \funcd{sem\_timedwait}, ed il suo
+\headfiled{semaphore.h}, la funzione è \funcd{sem\_timedwait}, ed il suo
prototipo è:
\begin{funcproto}{
\func{sem\_wait}, ma è possibile impostare un tempo limite per l'attesa
tramite la struttura \struct{timespec} (vedi
fig.~\ref{fig:sys_timespec_struct}) puntata
-dall'argomento \param{abs\_timeout}, indicato in secondi e nonosecondi a
+dall'argomento \param{abs\_timeout}, indicato in secondi e nanosecondi a
partire dalla cosiddetta \textit{Epoch} (00:00:00, 1 January 1970
UTC). Scaduto il limite la funzione ritorna anche se non è possibile acquisire
il semaforo fallendo con un errore di \errval{ETIMEDOUT}.
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 \itindex{thread} \textit{thread})
-eventualmente bloccato in una \func{sem\_wait} sul semaforo possa essere
-svegliato e rimesso in esecuzione. Si tenga presente che la funzione è sicura
-\index{funzioni!sicure} per l'uso all'interno di un gestore di segnali (si
-ricordi quanto detto in sez.~\ref{sec:sig_signal_handler}).
+sbloccata, cosicché un altro processo (o \textit{thread}) eventualmente
+bloccato in una \func{sem\_wait} sul semaforo possa essere svegliato e rimesso
+in esecuzione. Si tenga presente che la funzione è sicura per l'uso
+all'interno di un gestore di segnali (si ricordi quanto detto in
+sez.~\ref{sec:sig_signal_handler}).
Se invece di operare su un semaforo se ne volesse semplicemente leggere il
valore, si potrà usare la funzione \funcd{sem\_getvalue}, il cui prototipo è:
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} \textit{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 \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}
-\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 \index{variabili!globali} variabile globale o una
-variabile allocata dinamicamente nello \itindex{heap} \textit{heap}.
+Qualora il semaforo debba essere condiviso dai \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
+\textit{thread}, si dovrà usare cioè una variabile globale o una variabile
+allocata dinamicamente nello \textit{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
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 \itindex{thread} \textit{thread}) in
-attesa (cioè bloccati in una \func{sem\_wait}) provoca un comportamento
-indefinito.
+semaforo su cui sono presenti processi (o \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
lettura alla stringa, in modo che questa non possa essere modificata
dall'altro programma prima di averla finita di stampare.
-La parte iniziale del programma contiene le definizioni (\texttt{\small 1--8})
+La parte iniziale del programma contiene le definizioni (\texttt{\small 1-8})
del gestore del segnale usato per liberare le risorse utilizzate, delle
-\index{variabili!globali} variabili globali contenenti i nomi di default del
-segmento di memoria condivisa e del semaforo (il default scelto è
-\texttt{messages}), e delle altre variabili utilizzate dal programma.
+variabili globali contenenti i nomi di default del segmento di memoria
+condivisa e del semaforo (il default scelto è \texttt{messages}), e delle
+altre variabili utilizzate dal programma.
Come prima istruzione (\texttt{\small 10}) si è provveduto ad installare un
gestore di segnale che consentirà di effettuare le operazioni di pulizia
(usando la funzione \func{Signal} illustrata in
-fig.~\ref{fig:sig_Signal_code}), dopo di che (\texttt{\small 12--16}) si è
+fig.~\ref{fig:sig_Signal_code}), dopo di che (\texttt{\small 12-16}) si è
creato il segmento di memoria condivisa con la funzione \func{CreateShm} che
abbiamo appena trattato in sez.~\ref{sec:ipc_posix_shm}, uscendo con un
messaggio in caso di errore.
gestione si è usata una dimensione fissa pari a 256 byte, definita tramite la
costante \texttt{MSGMAXSIZE}.
-Il passo successivo (\texttt{\small 17--21}) è quello della creazione del
+Il passo successivo (\texttt{\small 17-21}) è quello della creazione del
semaforo che regola l'accesso al segmento di memoria condivisa con
\func{sem\_open}; anche in questo caso si gestisce l'uscita con stampa di un
messaggio in caso di errore. Anche per il semaforo, avendo specificato la
A questo punto (\texttt{\small 22}) si potrà inizializzare il messaggio posto
nel segmento di memoria condivisa usando la stringa passata come argomento al
programma. Essendo il semaforo stato creato già bloccato non ci si dovrà
-preoccupare di eventuali \itindex{race~condition} \textit{race condition}
-qualora il programma di modifica del messaggio venisse lanciato proprio in
-questo momento. Una volta inizializzato il messaggio occorrerà però
-rilasciare il semaforo (\texttt{\small 24--27}) per consentirne l'uso; in
-tutte queste operazioni si provvederà ad uscire dal programma con un opportuno
-messaggio in caso di errore.
+preoccupare di eventuali \textit{race condition} qualora il programma di
+modifica del messaggio venisse lanciato proprio in questo momento. Una volta
+inizializzato il messaggio occorrerà però rilasciare il semaforo
+(\texttt{\small 24-27}) per consentirne l'uso; in tutte queste operazioni si
+provvederà ad uscire dal programma con un opportuno messaggio in caso di
+errore.
Una volta completate le inizializzazioni il ciclo principale del programma
-(\texttt{\small 29--47}) viene ripetuto indefinitamente (\texttt{\small 29})
+(\texttt{\small 29-47}) viene ripetuto indefinitamente (\texttt{\small 29})
per stampare sia il contenuto del messaggio che una serie di informazioni di
-controllo. Il primo passo (\texttt{\small 30--34}) è quello di acquisire (con
+controllo. Il primo passo (\texttt{\small 30-34}) è quello di acquisire (con
\func{sem\_getvalue}, con uscita in caso di errore) e stampare il valore del
-semaforo ad inizio del ciclo; seguito (\texttt{\small 35--36}) dal tempo
+semaforo ad inizio del ciclo; seguito (\texttt{\small 35-36}) dal tempo
corrente.
\begin{figure}[!htb]
\end{figure}
Prima della stampa del messaggio invece si deve acquisire il semaforo
-(\texttt{\small 30--33}) per evitare accessi concorrenti alla stringa da parte
+(\texttt{\small 30-33}) per evitare accessi concorrenti alla stringa da parte
del programma di modifica. Una volta eseguita la stampa (\texttt{\small 41})
-il semaforo dovrà essere rilasciato (\texttt{\small 42--45}). Il passo finale
+il semaforo dovrà essere rilasciato (\texttt{\small 42-45}). Il passo finale
(\texttt{\small 46}) è attendere per un secondo prima di eseguire da capo il
ciclo.
Una volta completata la gestione delle opzioni e degli argomenti (ne deve
essere presente uno solo, contenente la nuova stringa da usare come
-messaggio), il programma procede (\texttt{\small 10--14}) con l'acquisizione
+messaggio), il programma procede (\texttt{\small 10-14}) con l'acquisizione
del segmento di memoria condivisa usando la funzione \func{FindShm} (trattata
in sez.~\ref{sec:ipc_posix_shm}) che stavolta deve già esistere. Il passo
-successivo (\texttt{\small 16--19}) è quello di aprire il semaforo, e a
+successivo (\texttt{\small 16-19}) è quello di aprire il semaforo, e a
differenza di \file{message\_getter}, in questo caso si richiede a
\func{sem\_open} che questo esista, passando uno zero come secondo ed unico
argomento.
Una volta completate con successo le precedenti inizializzazioni, il passo
-seguente (\texttt{\small 21--24}) è quello di acquisire il semaforo, dopo di
+seguente (\texttt{\small 21-24}) è quello di acquisire il semaforo, dopo di
che sarà possibile eseguire la sostituzione del messaggio (\texttt{\small 25})
-senza incorrere in possibili \itindex{race~condition} \textit{race condition}
-con la stampa dello stesso da parte di \file{message\_getter}.
+senza incorrere in possibili \textit{race condition} con la stampa dello
+stesso da parte di \file{message\_getter}.
Una volta effettuata la modifica viene stampato (\texttt{\small 26}) il tempo
di attesa impostato con l'opzione ``\texttt{-t}'' dopo di che (\texttt{\small
27}) viene eseguita la stessa, senza rilasciare il semaforo che resterà
quindi bloccato (causando a questo punto una interruzione delle stampe
eseguite da \file{message\_getter}). Terminato il tempo di attesa si rilascerà
-(\texttt{\small 29--32}) il semaforo per poi uscire.
+(\texttt{\small 29-32}) il semaforo per poi uscire.
Per verificare il funzionamento dei programmi occorrerà lanciare per primo
\file{message\_getter}\footnote{lanciare per primo \file{message\_setter} darà
\end{Console}
%$
-E si noterà come nel momento in cui si è lanciato \file{message\_setter} le
-stampe di \file{message\_getter} si bloccheranno, come corretto, dopo aver
-registrato un valore nullo per il semaforo. Il programma infatti resterà
-bloccato nella \func{sem\_wait} (quella di riga (\texttt{\small 37}) in
+E si noterà come nel momento in cui si lancia \file{message\_setter} le stampe
+di \file{message\_getter} si bloccheranno, come corretto, dopo aver registrato
+un valore nullo per il semaforo. Il programma infatti resterà bloccato nella
+\func{sem\_wait} (quella di riga (\texttt{\small 37}) in
fig.~\ref{fig:ipc_posix_sem_shm_message_server}) fino alla scadenza
dell'attesa di \file{message\_setter} (con l'esecuzione della \func{sem\_post}
della riga (\texttt{\small 29}) di
% LocalWords: Larry Wall Escape the Hell William ipctestid Identifier segment
% LocalWords: violation dell'I SIGINT setter Fri Dec Sleeping seconds ECHILD
% LocalWords: SysV capability short RESOURCE INFO UNDEFINED EFBIG semtimedop
-% LocalWords: scan HUGETLB huge page NORESERVE copy RLIMIT MEMLOCK REMAP
-% LocalWords: readmon Hierarchy defaults queues MSGQUEUE
+% LocalWords: scan HUGETLB huge page NORESERVE copy RLIMIT MEMLOCK REMAP UTC
+% LocalWords: readmon Hierarchy defaults queues MSGQUEUE effective fstat
+% LocalWords: fchown fchmod Epoch January
%%% Local Variables: