%% 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",
%% 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",
diversi, come quelli tradizionali che coinvolgono \textit{pipe} e
\textit{fifo} e i meccanismi di intercomunicazione di System V e quelli POSIX.
Tralasceremo invece tutte le problematiche relative alla comunicazione
attraverso la rete (e le relative interfacce) che saranno affrontate in
diversi, come quelli tradizionali che coinvolgono \textit{pipe} e
\textit{fifo} e i meccanismi di intercomunicazione di System V e quelli POSIX.
Tralasceremo invece tutte le problematiche relative alla comunicazione
attraverso la rete (e le relative interfacce) che saranno affrontate in
complessi ed evoluti come le RPC (\textit{Remote Procedure Calls}) e CORBA
(\textit{Common Object Request Brocker Architecture}) che in genere sono
implementati con un ulteriore livello sopra i meccanismi elementari.
complessi ed evoluti come le RPC (\textit{Remote Procedure Calls}) e CORBA
(\textit{Common Object Request Brocker Architecture}) che in genere sono
implementati con un ulteriore livello sopra i meccanismi elementari.
caratteristiche peculiari del sistema, in particolar modo dell'interfaccia a
linea di comando. In questa sezione descriveremo le sue basi, le funzioni che
caratteristiche peculiari del sistema, in particolar modo dell'interfaccia a
linea di comando. In questa sezione descriveremo le sue basi, le funzioni che
\subsection{Le \textit{pipe} standard}
\label{sec:ipc_pipes}
Le \textit{pipe} nascono sostanzialmente con Unix, e sono il primo, e tuttora
\subsection{Le \textit{pipe} standard}
\label{sec:ipc_pipes}
Le \textit{pipe} nascono sostanzialmente con Unix, e sono il primo, e tuttora
sostanza di una coppia di file descriptor\footnote{si tenga presente che
le pipe sono oggetti creati dal kernel e non risiedono su disco.} connessi
sostanza di una coppia di file descriptor\footnote{si tenga presente che
le pipe sono oggetti creati dal kernel e non risiedono su disco.} connessi
-fra di loro in modo che se quanto scrive su di uno si può rileggere
-dall'altro. Si viene così a costituire un canale di comunicazione tramite i
+fra di loro in modo che se quanto scrive su di uno si può rileggere
+dall'altro. Si viene così a costituire un canale di comunicazione tramite i
due file descriptor, nella forma di un \textsl{tubo} (da cui il nome)
attraverso cui fluiscono i dati.
La funzione che permette di creare questa speciale coppia di file descriptor
due file descriptor, nella forma di un \textsl{tubo} (da cui il nome)
attraverso cui fluiscono i dati.
La funzione che permette di creare questa speciale coppia di file descriptor
\begin{prototype}{unistd.h}
{int pipe(int filedes[2])}
Crea una coppia di file descriptor associati ad una \textit{pipe}.
\bodydesc{La funzione restituisce zero in caso di successo e -1 per un
\begin{prototype}{unistd.h}
{int pipe(int filedes[2])}
Crea una coppia di file descriptor associati ad una \textit{pipe}.
\bodydesc{La funzione restituisce zero in caso di successo e -1 per un
-\param{filedes}; il primo è aperto in lettura ed il secondo in scrittura. Come
-accennato concetto di funzionamento di una pipe è semplice: quello che si
+\param{filedes}; il primo è aperto in lettura ed il secondo in scrittura. Come
+accennato concetto di funzionamento di una pipe è semplice: quello che si
scrive nel file descriptor aperto in scrittura viene ripresentato tale e quale
nel file descriptor aperto in lettura. I file descriptor infatti non sono
connessi a nessun file reale, ma, come accennato in
sez.~\ref{sec:file_sendfile_splice}, ad un buffer nel kernel, la cui
scrive nel file descriptor aperto in scrittura viene ripresentato tale e quale
nel file descriptor aperto in lettura. I file descriptor infatti non sono
connessi a nessun file reale, ma, come accennato in
sez.~\ref{sec:file_sendfile_splice}, ad un buffer nel kernel, la cui
-dimensione è specificata dal parametro di sistema \const{PIPE\_BUF}, (vedi
-sez.~\ref{sec:sys_file_limits}). Lo schema di funzionamento di una pipe è
+dimensione è specificata dal parametro di sistema \const{PIPE\_BUF}, (vedi
+sez.~\ref{sec:sys_file_limits}). Lo schema di funzionamento di una pipe è
illustrato in fig.~\ref{fig:ipc_pipe_singular}, in cui sono illustrati i due
capi della pipe, associati a ciascun file descriptor, con le frecce che
indicano la direzione del flusso dei dati.
illustrato in fig.~\ref{fig:ipc_pipe_singular}, in cui sono illustrati i due
capi della pipe, associati a ciascun file descriptor, con le frecce che
indicano la direzione del flusso dei dati.
-niente; se però ricordiamo quanto esposto in sez.~\ref{sec:file_sharing}
-riguardo al comportamento dei file descriptor nei processi figli, è immediato
+niente; se però ricordiamo quanto esposto in sez.~\ref{sec:file_sharing}
+riguardo al comportamento dei file descriptor nei processi figli, è immediato
capire come una pipe possa diventare un meccanismo di intercomunicazione. Un
processo figlio infatti condivide gli stessi file descriptor del padre,
compresi quelli associati ad una pipe (secondo la situazione illustrata in
fig.~\ref{fig:ipc_pipe_fork}). In questo modo se uno dei processi scrive su un
capire come una pipe possa diventare un meccanismo di intercomunicazione. Un
processo figlio infatti condivide gli stessi file descriptor del padre,
compresi quelli associati ad una pipe (secondo la situazione illustrata in
fig.~\ref{fig:ipc_pipe_fork}). In questo modo se uno dei processi scrive su un
-Tutto ciò ci mostra come sia immediato realizzare un meccanismo di
-comunicazione fra processi attraverso una pipe, utilizzando le proprietà
-ordinarie dei file, ma ci mostra anche qual è il principale\footnote{Stevens
- in \cite{APUE} riporta come limite anche il fatto che la comunicazione è
- unidirezionale, ma in realtà questo è un limite facilmente superabile usando
- una coppia di pipe.} limite nell'uso delle pipe. È necessario infatti che i
+Tutto ciò ci mostra come sia immediato realizzare un meccanismo di
+comunicazione fra processi attraverso una pipe, utilizzando le proprietà
+ordinarie dei file, ma ci mostra anche qual è il principale\footnote{Stevens
+ in \cite{APUE} riporta come limite anche il fatto che la comunicazione è
+ unidirezionale, ma in realtà questo è un limite facilmente superabile usando
+ una coppia di pipe.} limite nell'uso delle pipe. È necessario infatti che i
-devono comunque essere \textsl{parenti} (dall'inglese \textit{siblings}), cioè
-o derivare da uno stesso processo padre in cui è avvenuta la creazione della
-pipe, o, più comunemente, essere nella relazione padre/figlio.
+devono comunque essere \textsl{parenti} (dall'inglese \textit{siblings}), cioè
+o derivare da uno stesso processo padre in cui è avvenuta la creazione della
+pipe, o, più comunemente, essere nella relazione padre/figlio.
-pipe il cui capo in scrittura è stato chiuso, si avrà la ricezione di un EOF
-(vale a dire che la funzione \func{read} ritornerà restituendo 0). Se invece
-si esegue una scrittura su una pipe il cui capo in lettura non è aperto il
-processo riceverà il segnale \const{SIGPIPE}, e la funzione di scrittura
-restituirà un errore di \errcode{EPIPE} (al ritorno del gestore, o qualora il
+pipe il cui capo in scrittura è stato chiuso, si avrà la ricezione di un EOF
+(vale a dire che la funzione \func{read} ritornerà restituendo 0). Se invece
+si esegue una scrittura su una pipe il cui capo in lettura non è aperto il
+processo riceverà il segnale \const{SIGPIPE}, e la funzione di scrittura
+restituirà un errore di \errcode{EPIPE} (al ritorno del gestore, o qualora il
importante informazione riguardo il comportamento delle operazioni di lettura
e scrittura su di una pipe; esse infatti sono atomiche fintanto che la
importante informazione riguardo il comportamento delle operazioni di lettura
e scrittura su di una pipe; esse infatti sono atomiche fintanto che la
-quantità di dati da scrivere non supera questa dimensione. Qualora ad esempio
-si effettui una scrittura di una quantità di dati superiore l'operazione verrà
-effettuata in più riprese, consentendo l'intromissione di scritture effettuate
+quantità di dati da scrivere non supera questa dimensione. Qualora ad esempio
+si effettui una scrittura di una quantità di dati superiore l'operazione verrà
+effettuata in più riprese, consentendo l'intromissione di scritture effettuate
consiste nell'inviare l'output di un processo (lo standard output) sull'input
di un altro. Realizzeremo il programma di esempio nella forma di un
consiste nell'inviare l'output di un processo (lo standard output) sull'input
di un altro. Realizzeremo il programma di esempio nella forma di un
programma che permette la creazione dinamica di un oggetto da inserire
all'interno di una pagina HTML.} per Apache, che genera una immagine JPEG
di un codice a barre, specificato come argomento in ingresso.
programma che permette la creazione dinamica di un oggetto da inserire
all'interno di una pagina HTML.} per Apache, che genera una immagine JPEG
di un codice a barre, specificato come argomento in ingresso.
ed il risultato dell'elaborazione deve essere presentato (con una intestazione
che ne descrive il mime-type) sullo standard output, in modo che il web-server
possa reinviarlo al browser che ha effettuato la richiesta, che in questo modo
ed il risultato dell'elaborazione deve essere presentato (con una intestazione
che ne descrive il mime-type) sullo standard output, in modo che il web-server
possa reinviarlo al browser che ha effettuato la richiesta, che in questo modo
codici a barre corrispondenti ad una qualunque stringa, mentre il secondo
serve per poter effettuare la conversione della stessa immagine in formato
JPEG. Usando una pipe potremo inviare l'output del primo sull'input del
secondo, secondo lo schema mostrato in fig.~\ref{fig:ipc_pipe_use}, in cui la
codici a barre corrispondenti ad una qualunque stringa, mentre il secondo
serve per poter effettuare la conversione della stessa immagine in formato
JPEG. Usando una pipe potremo inviare l'output del primo sull'input del
secondo, secondo lo schema mostrato in fig.~\ref{fig:ipc_pipe_use}, in cui la
-Si potrebbe obiettare che sarebbe molto più semplice salvare il risultato
-intermedio su un file temporaneo. Questo però non tiene conto del fatto che un
-\textit{CGI} deve poter gestire più richieste in concorrenza, e si avrebbe una
+Si potrebbe obiettare che sarebbe molto più semplice salvare il risultato
+intermedio su un file temporaneo. Questo però non tiene conto del fatto che un
+\textit{CGI} deve poter gestire più richieste in concorrenza, e si avrebbe una
evidente \itindex{race~condition} \textit{race condition} in caso di accesso
simultaneo a detto file.\footnote{il problema potrebbe essere superato
determinando in anticipo un nome appropriato per il file temporaneo, che
verrebbe utilizzato dai vari sotto-processi, e cancellato alla fine della
evidente \itindex{race~condition} \textit{race condition} in caso di accesso
simultaneo a detto file.\footnote{il problema potrebbe essere superato
determinando in anticipo un nome appropriato per il file temporaneo, che
verrebbe utilizzato dai vari sotto-processi, e cancellato alla fine della
-sez.~\ref{sec:file_dup}, in particolare di \func{dup2}. È attraverso queste
-funzioni infatti che è possibile dirottare gli stream standard dei processi
+sez.~\ref{sec:file_dup}, in particolare di \func{dup2}. È attraverso queste
+funzioni infatti che è possibile dirottare gli stream standard dei processi
(che abbiamo visto in sez.~\ref{sec:file_std_descr} e
sez.~\ref{sec:file_std_stream}) sulla pipe. In
fig.~\ref{fig:ipc_barcodepage_code} abbiamo riportato il corpo del programma,
(che abbiamo visto in sez.~\ref{sec:file_std_descr} e
sez.~\ref{sec:file_std_stream}) sulla pipe. In
fig.~\ref{fig:ipc_barcodepage_code} abbiamo riportato il corpo del programma,
le due 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 dell'immagine
le due 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 dell'immagine
fig.~\ref{fig:ipc_barcodepage_code}; essa si incarica semplicemente di
formattare l'uscita alla maniera dei CGI, aggiungendo l'opportuno
\textit{mime type}, e formattando il messaggio in HTML, in modo che
quest'ultimo possa essere visualizzato correttamente da un browser.}
fig.~\ref{fig:ipc_barcodepage_code}; essa si incarica semplicemente di
formattare l'uscita alla maniera dei CGI, aggiungendo l'opportuno
\textit{mime type}, e formattando il messaggio in HTML, in modo che
quest'ultimo possa essere visualizzato correttamente da un browser.}
-Una volta create le pipe, il programma può creare (\texttt{\small 13-17}) il
-primo processo figlio, che si incaricherà (\texttt{\small 19--25}) di eseguire
+Una volta create le 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 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.
\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.
In questo modo all'esecuzione (\texttt{\small 25}) di \cmd{barcode} (cui si
passa in \var{size} la dimensione della pagina per l'immagine) quest'ultimo
In questo modo all'esecuzione (\texttt{\small 25}) di \cmd{barcode} (cui si
passa in \var{size} la dimensione della pagina per l'immagine) quest'ultimo
-leggerà dalla prima pipe la stringa da codificare che gli sarà inviata dal
-padre, e scriverà l'immagine PostScript del codice a barre sulla seconda.
+leggerà dalla prima pipe la stringa da codificare che gli sarà inviata dal
+padre, e scriverà l'immagine PostScript del codice a barre sulla seconda.
Al contempo una volta lanciato il primo figlio, il processo padre prima chiude
(\texttt{\small 26}) il capo inutilizzato della prima pipe (quello in input) e
poi scrive (\texttt{\small 27}) la stringa da convertire sul capo in output,
Al contempo una volta lanciato il primo figlio, il processo padre prima chiude
(\texttt{\small 26}) il capo inutilizzato della prima pipe (quello in input) e
poi scrive (\texttt{\small 27}) la stringa da convertire sul capo in output,
-così che \cmd{barcode} possa riceverla dallo standard input. A questo punto
-l'uso della prima pipe da parte del padre è finito ed essa può essere
+così che \cmd{barcode} possa riceverla dallo standard input. A questo punto
+l'uso della prima pipe da parte del padre è finito ed essa può essere
definitivamente chiusa (\texttt{\small 28}), si attende poi (\texttt{\small
29}) che l'esecuzione di \cmd{barcode} sia completata.
definitivamente chiusa (\texttt{\small 28}), si attende poi (\texttt{\small
29}) che l'esecuzione di \cmd{barcode} sia completata.
scrittura della seconda pipe, e se ne collega (\texttt{\small 38}) il capo in
lettura allo standard input. Per poter formattare l'output del programma in
maniera utilizzabile da un browser, si provvede anche \texttt{\small 40}) alla
scrittura dell'apposita stringa di identificazione del mime-type in testa allo
scrittura della seconda pipe, e se ne collega (\texttt{\small 38}) il capo in
lettura allo standard input. Per poter formattare l'output del programma in
maniera utilizzabile da un browser, si provvede anche \texttt{\small 40}) alla
scrittura dell'apposita stringa di identificazione del mime-type in testa allo
provvedendo gli appositi switch che consentono di leggere il file da
convertire dallo standard input e di inviare la conversione sullo standard
output.
Per completare le operazioni il processo padre chiude (\texttt{\small 44}) il
capo in scrittura della seconda pipe, e attende la conclusione del figlio
provvedendo gli appositi switch che consentono di leggere il file da
convertire dallo standard input e di inviare la conversione sullo standard
output.
Per completare le operazioni il processo padre chiude (\texttt{\small 44}) il
capo in scrittura della seconda pipe, e attende la conclusione del figlio
-(\texttt{\small 45}); a questo punto può (\texttt{\small 46}) uscire. Si tenga
-conto che l'operazione di chiudere il capo in scrittura della seconda pipe è
+(\texttt{\small 45}); a questo punto può (\texttt{\small 46}) uscire. Si tenga
+conto che l'operazione di chiudere il capo in scrittura della seconda pipe è
necessaria, infatti, se non venisse chiusa, \cmd{gs}, che legge il suo
standard input da detta pipe, resterebbe bloccato in attesa di ulteriori dati
necessaria, infatti, se non venisse chiusa, \cmd{gs}, che legge il suo
standard input da detta pipe, resterebbe bloccato in attesa di ulteriori dati
-in ingresso (l'unico modo che un programma ha per sapere che l'input è
-terminato è rilevare che lo standard input è stato chiuso), e la \func{wait}
+in ingresso (l'unico modo che un programma ha per sapere che l'input è
+terminato è rilevare che lo standard input è stato chiuso), e la \func{wait}
utilizzarla per fare da tramite fra output ed input di due programmi invocati
in sequenza; per questo motivo lo standard POSIX.2 ha introdotto due funzioni
che permettono di sintetizzare queste operazioni. La prima di esse si chiama
utilizzarla per fare da tramite fra output ed input di due programmi invocati
in sequenza; per questo motivo lo standard POSIX.2 ha introdotto due funzioni
che permettono di sintetizzare queste operazioni. La prima di esse si chiama
\begin{prototype}{stdio.h}
{FILE *popen(const char *command, const char *type)}
\begin{prototype}{stdio.h}
{FILE *popen(const char *command, const char *type)}
\bodydesc{La funzione restituisce l'indirizzo dello stream associato alla pipe
in caso di successo e \val{NULL} per un errore, nel qual caso \var{errno}
\bodydesc{La funzione restituisce l'indirizzo dello stream associato alla pipe
in caso di successo e \val{NULL} per un errore, nel qual caso \var{errno}
- potrà assumere i valori relativi alle sottostanti invocazioni di \func{pipe}
- e \func{fork} o \errcode{EINVAL} se \param{type} non è valido.}
+ potrà assumere i valori relativi alle sottostanti invocazioni di \func{pipe}
+ e \func{fork} o \errcode{EINVAL} se \param{type} non è valido.}
\end{prototype}
La funzione crea una pipe, esegue una \func{fork}, ed invoca il programma
\param{command} attraverso la shell (in sostanza esegue \file{/bin/sh} con il
flag \code{-c}); l'argomento \param{type} deve essere una delle due stringhe
\end{prototype}
La funzione crea una pipe, esegue una \func{fork}, ed invoca il programma
\param{command} attraverso la shell (in sostanza esegue \file{/bin/sh} con il
flag \code{-c}); l'argomento \param{type} deve essere una delle due stringhe
input o allo standard output del comando invocato.
La funzione restituisce il puntatore allo stream associato alla pipe creata,
input o allo standard output del comando invocato.
La funzione restituisce il puntatore allo stream associato alla pipe creata,
programma indicato) in caso si sia indicato \code{"r"}, o in sola scrittura (e
quindi associato allo standard input) in caso di \code{"w"}.
programma indicato) in caso si sia indicato \code{"r"}, o in sola scrittura (e
quindi associato allo standard input) in caso di \code{"w"}.
-Lo stream restituito da \func{popen} è identico a tutti gli effetti ai file
-stream visti in cap.~\ref{cha:files_std_interface}, anche se è collegato ad
-una pipe e non ad un file, e viene sempre aperto in modalità
+Lo stream restituito da \func{popen} è identico a tutti gli effetti ai file
+stream visti in cap.~\ref{cha:files_std_interface}, anche se è collegato ad
+una pipe e non ad un file, e viene sempre aperto in modalità
-differenza con gli usuali stream è che dovrà essere chiuso dalla seconda delle
-due nuove funzioni, \funcd{pclose}, il cui prototipo è:
+differenza con gli usuali stream è che dovrà essere chiuso dalla seconda delle
+due nuove funzioni, \funcd{pclose}, il cui prototipo è:
Per illustrare l'uso di queste due funzioni riprendiamo il problema
precedente: il programma mostrato in fig.~\ref{fig:ipc_barcodepage_code} per
Per illustrare l'uso di queste due funzioni riprendiamo il problema
precedente: il programma mostrato in fig.~\ref{fig:ipc_barcodepage_code} per
-quanto funzionante, è (volutamente) codificato in maniera piuttosto complessa,
-inoltre nella pratica sconta un problema di \cmd{gs} che non è in
+quanto funzionante, è (volutamente) codificato in maniera piuttosto complessa,
+inoltre nella pratica sconta un problema di \cmd{gs} che non è in
grado\footnote{nella versione GNU Ghostscript 6.53 (2002-02-13).} di
riconoscere correttamente l'Encapsulated PostScript, per cui deve essere usato
il PostScript e tutte le volte viene generata una pagina intera, invece che
una immagine delle dimensioni corrispondenti al codice a barre.
Se si vuole generare una immagine di dimensioni appropriate si deve usare un
grado\footnote{nella versione GNU Ghostscript 6.53 (2002-02-13).} di
riconoscere correttamente l'Encapsulated PostScript, per cui deve essere usato
il PostScript e tutte le volte viene generata una pagina intera, invece che
una immagine delle dimensioni corrispondenti al codice a barre.
Se si vuole generare una immagine di dimensioni appropriate si deve usare un
-approccio diverso. Una possibilità sarebbe quella di ricorrere ad ulteriore
-programma, \cmd{epstopsf}, per convertire in PDF un file EPS (che può essere
+approccio diverso. Una possibilità sarebbe quella di ricorrere ad ulteriore
+programma, \cmd{epstopsf}, per convertire in PDF un file EPS (che può essere
generato da \cmd{barcode} utilizzando lo switch \cmd{-E}). Utilizzando un PDF
al posto di un EPS \cmd{gs} esegue la conversione rispettando le dimensioni
originarie del codice a barre e produce un JPEG di dimensioni corrette.
generato da \cmd{barcode} utilizzando lo switch \cmd{-E}). Utilizzando un PDF
al posto di un EPS \cmd{gs} esegue la conversione rispettando le dimensioni
originarie del codice a barre e produce un JPEG di dimensioni corrette.
-Questo approccio però non funziona, per via di una delle caratteristiche
-principali delle pipe. Per poter effettuare la conversione di un PDF infatti è
+Questo approccio però non funziona, per via di una delle caratteristiche
+principali delle pipe. Per poter effettuare la conversione di un PDF infatti è
necessario, per la struttura del formato, potersi spostare (con \func{lseek})
all'interno del file da convertire; se si esegue la conversione con \cmd{gs}
necessario, per la struttura del formato, potersi spostare (con \func{lseek})
all'interno del file da convertire; se si esegue la conversione con \cmd{gs}
sequenziale, e l'uso di \func{lseek} su di essa fallisce sempre con un errore
di \errcode{ESPIPE}, rendendo impossibile la conversione. Questo ci dice che
sequenziale, e l'uso di \func{lseek} su di essa fallisce sempre con un errore
di \errcode{ESPIPE}, rendendo impossibile la conversione. Questo ci dice che
-intermedio, il PPM,\footnote{il \textit{Portable PixMap file format} è un
- formato usato spesso come formato intermedio per effettuare conversioni, è
+intermedio, il PPM,\footnote{il \textit{Portable PixMap file format} è un
+ formato usato spesso come formato intermedio per effettuare conversioni, è
- memorizzare le immagini, anche se per questo è estremamente inefficiente.}
-dal quale poi si può ottenere un'immagine di dimensioni corrette attraverso
-vari programmi di manipolazione (\cmd{pnmcrop}, \cmd{pnmmargin}) che può
+ memorizzare le immagini, anche se per questo è estremamente inefficiente.}
+dal quale poi si può ottenere un'immagine di dimensioni corrette attraverso
+vari programmi di manipolazione (\cmd{pnmcrop}, \cmd{pnmmargin}) che può
inviando l'output di ciascuno all'input del successivo, per poi ottenere il
risultato finale sullo standard output: un caso classico di utilizzazione
delle pipe, in cui l'uso di \func{popen} e \func{pclose} permette di
semplificare notevolmente la stesura del codice.
Nel nostro caso, dato che ciascun processo deve scrivere il suo output sullo
inviando l'output di ciascuno all'input del successivo, per poi ottenere il
risultato finale sullo standard output: un caso classico di utilizzazione
delle pipe, in cui l'uso di \func{popen} e \func{pclose} permette di
semplificare notevolmente la stesura del codice.
Nel nostro caso, dato che ciascun processo deve scrivere il suo output sullo
-standard input del successivo, occorrerà usare \func{popen} aprendo la pipe in
-scrittura. Il codice del nuovo programma è riportato in
-fig.~\ref{fig:ipc_barcode_code}. Come si può notare l'ordine di invocazione
-dei programmi è l'inverso di quello in cui ci si aspetta che vengano
+standard input del successivo, occorrerà usare \func{popen} aprendo la pipe in
+scrittura. Il codice del nuovo programma è riportato in
+fig.~\ref{fig:ipc_barcode_code}. Come si può notare l'ordine di invocazione
+dei programmi è l'inverso di quello in cui ci si aspetta che vengano
-lettura su una pipe è bloccante, per cui ciascun processo, per quanto lanciato
-per primo, si bloccherà in attesa di ricevere sullo standard input il
-risultato dell'elaborazione del precedente, benché quest'ultimo venga invocato
+lettura su una pipe è bloccante, per cui ciascun processo, per quanto lanciato
+per primo, si bloccherà in attesa di ricevere sullo standard input il
+risultato dell'elaborazione del precedente, benché quest'ultimo venga invocato
-Nel nostro caso il primo passo (\texttt{\small 14}) è scrivere il mime-type
-sullo standard output; a questo punto il processo padre non necessita più di
-eseguire ulteriori operazioni sullo standard output e può tranquillamente
+Nel nostro caso il primo passo (\texttt{\small 14}) è scrivere il mime-type
+sullo standard output; a questo punto il processo padre non necessita più di
+eseguire ulteriori operazioni sullo standard output e può tranquillamente
approntato un ciclo (\texttt{\small 15--19}) che esegue le operazioni in
sequenza: prima crea una pipe (\texttt{\small 17}) per la scrittura eseguendo
il programma con \func{popen}, in modo che essa sia collegata allo standard
input, e poi redirige (\texttt{\small 18}) lo standard output su detta pipe.
approntato un ciclo (\texttt{\small 15--19}) che esegue le operazioni in
sequenza: prima crea una pipe (\texttt{\small 17}) per la scrittura eseguendo
il programma con \func{popen}, in modo che essa sia collegata allo standard
input, e poi redirige (\texttt{\small 18}) lo standard output su detta pipe.
-In questo modo il primo processo ad essere invocato (che è l'ultimo della
-catena) scriverà ancora sullo standard output del processo padre, ma i
+In questo modo il primo processo ad essere invocato (che è l'ultimo della
+catena) scriverà ancora sullo standard output del processo padre, ma i
successivi, a causa di questa redirezione, scriveranno sulla pipe associata
allo standard input del processo invocato nel ciclo precedente.
successivi, a causa di questa redirezione, scriveranno sulla pipe associata
allo standard input del processo invocato nel ciclo precedente.
-Alla fine tutto quello che resta da fare è lanciare (\texttt{\small 21}) il
-primo processo della catena, che nel caso è \cmd{barcode}, e scrivere
-(\texttt{\small 23}) la stringa del codice a barre sulla pipe, che è collegata
-al suo standard input, infine si può eseguire (\texttt{\small 24--27}) un
+Alla fine tutto quello che resta da fare è lanciare (\texttt{\small 21}) il
+primo processo della catena, che nel caso è \cmd{barcode}, e scrivere
+(\texttt{\small 23}) la stringa del codice a barre sulla pipe, che è collegata
+al suo standard input, infine si può eseguire (\texttt{\small 24--27}) un
ciclo che chiuda, nell'ordine inverso rispetto a quello in cui le si sono
create, tutte le pipe create con \func{pclose}.
ciclo che chiuda, nell'ordine inverso rispetto a quello in cui le si sono
create, tutte le pipe create con \func{pclose}.
\subsection{Le \textit{pipe} con nome, o \textit{fifo}}
\label{sec:ipc_named_pipe}
\subsection{Le \textit{pipe} con nome, o \textit{fifo}}
\label{sec:ipc_named_pipe}
che esse possono essere utilizzate solo da processi con un progenitore comune
o nella relazione padre/figlio; per superare questo problema lo standard
POSIX.1 ha definito dei nuovi oggetti, le \textit{fifo}, che hanno le stesse
caratteristiche delle pipe, ma che invece di essere strutture interne del
kernel, visibili solo attraverso un file descriptor, sono accessibili
che esse possono essere utilizzate solo da processi con un progenitore comune
o nella relazione padre/figlio; per superare questo problema lo standard
POSIX.1 ha definito dei nuovi oggetti, le \textit{fifo}, che hanno le stesse
caratteristiche delle pipe, ma che invece di essere strutture interne del
kernel, visibili solo attraverso un file descriptor, sono accessibili
attraverso un apposito buffer nel kernel, senza transitare dal filesystem;
\index{inode} l'inode allocato sul filesystem serve infatti solo a fornire un
punto di riferimento per i processi, che permetta loro di accedere alla stessa
attraverso un apposito buffer nel kernel, senza transitare dal filesystem;
\index{inode} l'inode allocato sul filesystem serve infatti solo a fornire un
punto di riferimento per i processi, che permetta loro di accedere alla stessa
-processo non avrà che da aprire il relativo file speciale o in lettura o
-scrittura; nel primo caso sarà collegato al capo di uscita della fifo, e dovrà
-leggere, nel secondo al capo di ingresso, e dovrà scrivere.
+processo non avrà che da aprire il relativo file speciale o in lettura o
+scrittura; nel primo caso sarà collegato al capo di uscita della fifo, e dovrà
+leggere, nel secondo al capo di ingresso, e dovrà scrivere.
-Il kernel crea una singola pipe per ciascuna fifo che sia stata aperta, che può
-essere acceduta contemporaneamente da più processi, sia in lettura che in
+Il kernel crea una singola pipe per ciascuna fifo che sia stata aperta, che può
+essere acceduta contemporaneamente da più processi, sia in lettura che in
scrittura. Dato che per funzionare deve essere aperta in entrambe le
direzioni, per una fifo di norma la funzione \func{open} si blocca se viene
scrittura. Dato che per funzionare deve essere aperta in entrambe le
direzioni, per una fifo di norma la funzione \func{open} si blocca se viene
-Le fifo però possono essere anche aperte in modalità \textsl{non-bloccante},
-nel qual caso l'apertura del capo in lettura avrà successo solo quando anche
-l'altro capo è aperto, mentre l'apertura del capo in scrittura restituirà
-l'errore di \errcode{ENXIO} fintanto che non verrà aperto il capo in lettura.
+Le fifo però possono essere anche aperte in modalità \textsl{non-bloccante},
+nel qual caso l'apertura del capo in lettura avrà successo solo quando anche
+l'altro capo è aperto, mentre l'apertura del capo in scrittura restituirà
+l'errore di \errcode{ENXIO} fintanto che non verrà aperto il capo in lettura.
-operazione che avrà sempre successo immediato qualunque sia la modalità di
-apertura (bloccante e non bloccante); questo può essere utilizzato per aprire
+operazione che avrà sempre successo immediato qualunque sia la modalità di
+apertura (bloccante e non bloccante); questo può essere utilizzato per aprire
-lettura; è possibile anche usare la fifo all'interno di un solo processo, nel
-qual caso però occorre stare molto attenti alla possibili situazioni di
+lettura; è possibile anche usare la fifo all'interno di un solo processo, nel
+qual caso però occorre stare molto attenti alla possibili situazioni di
- avrà un \itindex{deadlock} deadlock immediato, dato che il processo si
- blocca e non potrà quindi mai eseguire le funzioni di scrittura.}
+ avrà un \itindex{deadlock} deadlock immediato, dato che il processo si
+ blocca e non potrà quindi mai eseguire le funzioni di scrittura.}
il limite delle dimensioni di \const{PIPE\_BUF} (si ricordi quanto detto in
sez.~\ref{sec:ipc_pipes}).
il limite delle dimensioni di \const{PIPE\_BUF} (si ricordi quanto detto in
sez.~\ref{sec:ipc_pipes}).
riporta in \cite{APUE} altre due casistiche principali per l'uso delle fifo:
\begin{itemize}
\item Da parte dei comandi di shell, per evitare la creazione di file
riporta in \cite{APUE} altre due casistiche principali per l'uso delle fifo:
\begin{itemize}
\item Da parte dei comandi di shell, per evitare la creazione di file
sull'input di parecchi altri (attraverso l'uso del comando \cmd{tee}).
\item Come canale di comunicazione fra client ed server (il modello
sull'input di parecchi altri (attraverso l'uso del comando \cmd{tee}).
\item Come canale di comunicazione fra client ed server (il modello
input, quanti sono i processi a cui i vogliono inviare i dati, questi ultimi
saranno stati posti in esecuzione ridirigendo lo standard input dalle fifo, si
input, quanti sono i processi a cui i vogliono inviare i dati, questi ultimi
saranno stati posti in esecuzione ridirigendo lo standard input dalle fifo, si
-client; se il primo infatti può ricevere le richieste attraverso una fifo
-``\textsl{nota}'', per le risposte non si può fare altrettanto, dato che, per
+client; se il primo infatti può ricevere le richieste attraverso una fifo
+``\textsl{nota}'', per le risposte non si può fare altrettanto, dato che, per
la struttura sequenziale delle fifo, i client dovrebbero sapere, prima di
leggerli, quando i dati inviati sono destinati a loro.
la struttura sequenziale delle fifo, i client dovrebbero sapere, prima di
leggerli, quando i dati inviati sono destinati a loro.
illustrata in fig.~\ref{fig:ipc_fifo_server_arch} in cui i client inviano le
richieste al server su una fifo nota mentre le risposte vengono reinviate dal
server a ciascuno di essi su una fifo temporanea creata per l'occasione.
illustrata in fig.~\ref{fig:ipc_fifo_server_arch} in cui i client inviano le
richieste al server su una fifo nota mentre le risposte vengono reinviate dal
server a ciascuno di essi su una fifo temporanea creata per l'occasione.
un server di \textit{fortunes}, che restituisce, alle richieste di un client,
un detto a caso estratto da un insieme di frasi; sia il numero delle frasi
dell'insieme, che i file da cui esse vengono lette all'avvio, sono importabili
un server di \textit{fortunes}, che restituisce, alle richieste di un client,
un detto a caso estratto da un insieme di frasi; sia il numero delle frasi
dell'insieme, che i file da cui esse vengono lette all'avvio, sono importabili
-da riga di comando. Il corpo principale del server è riportato in
-fig.~\ref{fig:ipc_fifo_server}, dove si è tralasciata la parte che tratta la
+da riga di comando. Il corpo principale del server è riportato in
+fig.~\ref{fig:ipc_fifo_server}, dove si è tralasciata la parte che tratta la
gestione delle opzioni a riga di comando, che effettua il settaggio delle
variabili \var{fortunefilename}, che indica il file da cui leggere le frasi,
ed \var{n}, che indica il numero di frasi tenute in memoria, ad un valore
gestione delle opzioni a riga di comando, che effettua il settaggio delle
variabili \var{fortunefilename}, che indica il file da cui leggere le frasi,
ed \var{n}, che indica il numero di frasi tenute in memoria, ad un valore
dell'insieme delle frasi non nulla, dato che l'inizializzazione del vettore
\var{fortune} avviene solo quando questa dimensione viene specificata, la
presenza di un valore nullo provoca l'uscita dal programma attraverso la
dell'insieme delle frasi non nulla, dato che l'inizializzazione del vettore
\var{fortune} avviene solo quando questa dimensione viene specificata, la
presenza di un valore nullo provoca l'uscita dal programma attraverso la
funzione \code{FortuneParse} che legge dal file specificato in
\var{fortunefilename} le prime \var{n} frasi e le memorizza (allocando
dinamicamente la memoria necessaria) nel vettore di puntatori \var{fortune}.
funzione \code{FortuneParse} che legge dal file specificato in
\var{fortunefilename} le prime \var{n} frasi e le memorizza (allocando
dinamicamente la memoria necessaria) nel vettore di puntatori \var{fortune}.
-Il passo successivo (\texttt{\small 17--22}) è quello di creare con
-\func{mkfifo} la fifo nota sulla quale il server ascolterà le richieste,
-qualora si riscontri un errore il server uscirà (escludendo ovviamente il caso
+Il passo successivo (\texttt{\small 17--22}) è quello di creare con
+\func{mkfifo} la fifo nota sulla quale il server ascolterà le richieste,
+qualora si riscontri un errore il server uscirà (escludendo ovviamente il caso
-Una volta che si è certi che la fifo di ascolto esiste la procedura di
-inizializzazione è completata. A questo punto si può chiamare (\texttt{\small
+Una volta che si è certi che la fifo di ascolto esiste la procedura di
+inizializzazione è completata. A questo punto si può chiamare (\texttt{\small
alla apertura della 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
alla apertura della 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 fifo è aperta solo
+principale il caso in cui il server è in ascolto ma non ci sono client che
+effettuano richieste. Si ricordi infatti che quando una fifo è aperta solo
-richiesta. Pertanto all'inizio non ci sono problemi, il client però, una volta
-ricevuta la risposta, uscirà, chiudendo tutti i file aperti, compresa la fifo.
+richiesta. Pertanto all'inizio non ci sono problemi, il client però, una volta
+ricevuta la risposta, uscirà, chiudendo tutti i file aperti, compresa la fifo.
A questo punto il server resta (se non ci sono altri client che stanno
effettuando richieste) con la fifo chiusa sul lato in lettura, ed in questo
A questo punto il server resta (se non ci sono altri client che stanno
effettuando richieste) con la fifo chiusa sul lato in lettura, ed in questo
-stato la funzione \func{read} non si bloccherà in attesa di input, ma
-ritornerà in continuazione, restituendo un end-of-file.\footnote{si è usata
- questa tecnica per compatibilità, Linux infatti supporta l'apertura delle
+stato la funzione \func{read} non si bloccherà in attesa di input, ma
+ritornerà in continuazione, restituendo un end-of-file.\footnote{si è usata
+ questa tecnica per compatibilità, Linux infatti supporta l'apertura delle
fifo in lettura/scrittura, per cui si sarebbe potuto effettuare una singola
apertura con \const{O\_RDWR}, la doppia apertura comunque ha il vantaggio
fifo in lettura/scrittura, per cui si sarebbe potuto effettuare una singola
apertura con \const{O\_RDWR}, la doppia apertura comunque ha il vantaggio
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
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
- una fifo in modalità non bloccante, per evitare il rischio di uno stallo: se
- infatti nessuno apre la fifo in scrittura il processo non ritornerà mai
- dalla \func{open}. Nel nostro caso questo rischio non esiste, mentre è
+ una fifo in modalità non bloccante, per evitare il rischio di uno stallo: se
+ infatti nessuno apre la 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
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 questo modo però la
-fifo resta comunque aperta anche in scrittura, cosicché le successive chiamate
+il relativo file descriptor, che non sarà mai usato, in questo modo però la
+fifo resta comunque aperta anche in scrittura, cosicché le successive chiamate
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 fifo).
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 fifo).
che contengono il nome della fifo sulla quale deve essere inviata la risposta.
Per cui prima (\texttt{\small 35--39}) si esegue la lettura dalla stringa di
che contengono il nome della fifo sulla quale deve essere inviata la risposta.
Per cui prima (\texttt{\small 35--39}) si esegue la lettura dalla stringa di
non ci sono richieste). Dopo di che, una volta terminata la stringa
(\texttt{\small 40}) e selezionato (\texttt{\small 41}) un numero casuale per
non ci sono richieste). Dopo di che, una volta terminata la stringa
(\texttt{\small 40}) e selezionato (\texttt{\small 41}) un numero casuale per
-Il codice del client è invece riportato in fig.~\ref{fig:ipc_fifo_client},
-anche in questo caso si è omessa la gestione delle opzioni e la funzione che
+Il codice del client è invece riportato in fig.~\ref{fig:ipc_fifo_client},
+anche in questo caso si è omessa la gestione delle opzioni e la funzione che
stampa a video le informazioni di utilizzo ed esce, riportando solo la sezione
principale del programma e le definizioni delle variabili. Il codice completo
stampa a video le informazioni di utilizzo ed esce, riportando solo la sezione
principale del programma e le definizioni delle variabili. Il codice completo
essere utilizzata per ricevere la risposta dal server. Si usa il \acr{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
essere utilizzata per ricevere la risposta dal server. Si usa il \acr{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
questo prima si apre la fifo nota (\texttt{\small 19--23}), e poi ci si scrive
(\texttt{\small 24}) la stringa composta in precedenza, che contiene il nome
della fifo da utilizzare per la risposta. Infine si richiude la fifo del
questo prima si apre la fifo nota (\texttt{\small 19--23}), e poi ci si scrive
(\texttt{\small 24}) la stringa composta in precedenza, che contiene il nome
della fifo da utilizzare per la risposta. Infine si richiude la fifo del
si apre (\texttt{\small 26--30}) la fifo appena creata, da cui si deve
riceverla, dopo di che si effettua una lettura (\texttt{\small 31})
si apre (\texttt{\small 26--30}) la fifo appena creata, da cui si deve
riceverla, dopo di che si effettua una lettura (\texttt{\small 31})
(\texttt{\small 32}) a video la risposta, si chiude (\texttt{\small 33}) la
fifo e si cancella (\texttt{\small 34}) il relativo file.
Si noti come la fifo per la risposta sia stata aperta solo dopo aver inviato
(\texttt{\small 32}) a video la risposta, si chiude (\texttt{\small 33}) la
fifo e si cancella (\texttt{\small 34}) il relativo file.
Si noti come la fifo per la risposta sia stata aperta solo dopo aver inviato
quanto senza la richiesta, il server non avrebbe potuto aprirne il capo in
scrittura e l'apertura si sarebbe bloccata indefinitamente.
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
quanto senza la richiesta, il server non avrebbe potuto aprirne il capo in
scrittura e l'apertura si sarebbe bloccata indefinitamente.
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
in modo che il linker dinamico possa accedervi.
In generale questa variabile indica il \itindex{pathname} \textit{pathname}
della directory contenente la libreria. Nell'ipotesi (che daremo sempre per
verificata) che si facciano le prove direttamente nella directory dei sorgenti
(dove di norma vengono creati sia i programmi che la libreria), il comando da
in modo che il linker dinamico possa accedervi.
In generale questa variabile indica il \itindex{pathname} \textit{pathname}
della directory contenente la libreria. Nell'ipotesi (che daremo sempre per
verificata) che si facciano le prove direttamente nella directory dei sorgenti
(dove di norma vengono creati sia i programmi che la libreria), il comando da
il server, facendogli leggere una decina di frasi, con:
\begin{Verbatim}
[piccardi@gont sources]$ ./fortuned -n10
il server, facendogli leggere una decina di frasi, con:
\begin{Verbatim}
[piccardi@gont sources]$ ./fortuned -n10
programma resta un esecuzione in background, e senza avere associato un
terminale di controllo (si ricordi quanto detto in sez.~\ref{sec:sess_daemon}):
\begin{Verbatim}
programma resta un esecuzione in background, e senza avere associato un
terminale di controllo (si ricordi quanto detto in sez.~\ref{sec:sess_daemon}):
\begin{Verbatim}
\begin{Verbatim}
[piccardi@gont sources]$ ./fortune
Linux ext2fs has been stable for a long time, now it's time to break it
\begin{Verbatim}
[piccardi@gont sources]$ ./fortune
Linux ext2fs has been stable for a long time, now it's time to break it
-- William E. Roadcap
[piccardi@gont sources]$ ./fortune
Linux ext2fs has been stable for a long time, now it's time to break it
-- William E. Roadcap
[piccardi@gont sources]$ ./fortune
Linux ext2fs has been stable for a long time, now it's time to break it
\end{Verbatim}
%$
e ripetendo varie volte il comando otterremo, in ordine casuale, le dieci
frasi tenute in memoria dal server.
\end{Verbatim}
%$
e ripetendo varie volte il comando otterremo, in ordine casuale, le dieci
frasi tenute in memoria dal server.
\code{killall fortuned} e potremo verificare che il gestore del segnale ha
anche correttamente cancellato la fifo di ascolto da \file{/tmp}.
\code{killall fortuned} e potremo verificare che il gestore del segnale ha
anche correttamente cancellato la fifo di ascolto da \file{/tmp}.
complessa e continua ad avere vari inconvenienti\footnote{lo stesso Stevens,
che esamina questa architettura in \cite{APUE}, nota come sia impossibile
complessa e continua ad avere vari inconvenienti\footnote{lo stesso Stevens,
che esamina questa architettura in \cite{APUE}, nota come sia impossibile
- nostro esempio non è stata fatta).}; in generale infatti l'interfaccia delle
-fifo non è adatta a risolvere questo tipo di problemi, che possono essere
-affrontati in maniera più semplice ed efficace o usando i socket (che
+ nostro esempio non è stata fatta).}; in generale infatti l'interfaccia delle
+fifo non è adatta a risolvere questo tipo di problemi, che possono essere
+affrontati in maniera più semplice ed efficace o usando i socket (che
tratteremo in dettaglio a partire da cap.~\ref{cha:socket_intro}) o ricorrendo
a meccanismi di comunicazione diversi, come quelli che esamineremo in seguito.
tratteremo in dettaglio a partire da cap.~\ref{cha:socket_intro}) o ricorrendo
a meccanismi di comunicazione diversi, come quelli che esamineremo in seguito.
\label{sec:ipc_socketpair}
Un meccanismo di comunicazione molto simile alle pipe, ma che non presenta il
\label{sec:ipc_socketpair}
Un meccanismo di comunicazione molto simile alle pipe, ma che non presenta il
\textsl{socket locali} (o \textit{Unix domain socket}). Tratteremo l'argomento
dei socket in cap.~\ref{cha:socket_intro},\footnote{si tratta comunque di
oggetti di comunicazione che, come le pipe, sono utilizzati attraverso dei
file descriptor.} nell'ambito dell'interfaccia generale che essi forniscono
per la programmazione di rete; e vedremo anche
(in~sez.~\ref{sec:sock_sa_local}) come si possono definire dei file speciali
\textsl{socket locali} (o \textit{Unix domain socket}). Tratteremo l'argomento
dei socket in cap.~\ref{cha:socket_intro},\footnote{si tratta comunque di
oggetti di comunicazione che, come le pipe, sono utilizzati attraverso dei
file descriptor.} nell'ambito dell'interfaccia generale che essi forniscono
per la programmazione di rete; e vedremo anche
(in~sez.~\ref{sec:sock_sa_local}) come si possono definire dei file speciali
-(di tipo socket, analoghi a quello associati alle fifo) cui si accede però
-attraverso quella medesima interfaccia; vale però la pena esaminare qui una
-modalità di uso dei socket locali\footnote{la funzione \func{socketpair} è
- stata introdotta in BSD4.4, ma è supportata in genere da qualunque sistema
+(di tipo socket, analoghi a quello associati alle fifo) cui si accede però
+attraverso quella medesima interfaccia; vale però la pena esaminare qui una
+modalità di uso dei socket locali\footnote{la funzione \func{socketpair} è
+ stata introdotta in BSD4.4, ma è supportata in genere da qualunque sistema
che fornisca l'interfaccia dei socket.} che li rende sostanzialmente
identici ad una pipe bidirezionale.
che fornisca l'interfaccia dei socket.} che li rende sostanzialmente
identici ad una pipe bidirezionale.
descriptor connessi fra di loro (tramite un socket, appunto), senza dover
ricorrere ad un file speciale sul filesystem, i descrittori sono del tutto
analoghi a quelli che si avrebbero con una chiamata a \func{pipe}, con la sola
descriptor connessi fra di loro (tramite un socket, appunto), senza dover
ricorrere ad un file speciale sul filesystem, i descrittori sono del tutto
analoghi a quelli che si avrebbero con una chiamata a \func{pipe}, con la sola
-differenza è che in questo caso il flusso dei dati può essere effettuato in
-entrambe le direzioni. Il prototipo della funzione è:
+differenza è che in questo caso il flusso dei dati può essere effettuato in
+entrambe le direzioni. Il prototipo della funzione è:
Crea una coppia di socket connessi fra loro.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
Crea una coppia di socket connessi fra loro.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
sull'altro e viceversa. Gli argomenti \param{domain}, \param{type} e
\param{protocol} derivano dall'interfaccia dei socket (vedi
sull'altro e viceversa. Gli argomenti \param{domain}, \param{type} e
\param{protocol} derivano dall'interfaccia dei socket (vedi
connettere i due descrittori, ma in questo caso i soli valori validi che
possono essere specificati sono rispettivamente \const{AF\_UNIX},
\const{SOCK\_STREAM} e \val{0}.
connettere i due descrittori, ma in questo caso i soli valori validi che
possono essere specificati sono rispettivamente \const{AF\_UNIX},
\const{SOCK\_STREAM} e \val{0}.
-L'utilità di chiamare questa funzione per evitare due chiamate a \func{pipe}
-può sembrare limitata; in realtà l'utilizzo di questa funzione (e dei socket
+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
altro un file descriptor, con una sorta di duplicazione dello stesso non
all'interno di uno stesso processo, ma fra processi distinti (torneremo su
altro un file descriptor, con una sorta di duplicazione dello stesso non
all'interno di uno stesso processo, ma fra processi distinti (torneremo su
-Benché le pipe e le fifo siano ancora ampiamente usate, esse scontano il
-limite fondamentale che il meccanismo di comunicazione che forniscono è
+Benché le pipe e le fifo siano ancora ampiamente usate, esse scontano il
+limite fondamentale che il meccanismo di comunicazione che forniscono è
Per questo nello sviluppo di System V vennero introdotti una serie di nuovi
oggetti per la comunicazione fra processi ed una nuova interfaccia di
Per questo nello sviluppo di System V vennero introdotti una serie di nuovi
oggetti per la comunicazione fra processi ed una nuova interfaccia di
In questa sezione esamineremo come Linux supporta quello che viene chiamato il
\textsl{Sistema di comunicazione fra processi} di System V, cui da qui in
In questa sezione esamineremo come Linux supporta quello che viene chiamato il
\textsl{Sistema di comunicazione fra processi} di System V, cui da qui in
su oggetti permanenti che risiedono nel kernel. Questi, a differenza di quanto
avviene per i file descriptor, non mantengono un contatore dei riferimenti, e
su oggetti permanenti che risiedono nel kernel. Questi, a differenza di quanto
avviene per i file descriptor, non mantengono un contatore dei riferimenti, e
file, un contatore del numero di riferimenti che ne indichi l'essere in uso,
essi possono essere cancellati anche se ci sono dei processi che li stanno
utilizzando, con tutte le conseguenze (negative) del caso.
file, un contatore del numero di riferimenti che ne indichi l'essere in uso,
essi possono essere cancellati anche se ci sono dei processi che li stanno
utilizzando, con tutte le conseguenze (negative) del caso.
progressivo (un po' come il \acr{pid} dei processi) che il kernel assegna a
ciascuno di essi quanto vengono creati (sul procedimento di assegnazione
torneremo in sez.~\ref{sec:ipc_sysv_id_use}). L'identificatore viene restituito
progressivo (un po' come il \acr{pid} dei processi) che il kernel assegna a
ciascuno di essi quanto vengono creati (sul procedimento di assegnazione
torneremo in sez.~\ref{sec:ipc_sysv_id_use}). L'identificatore viene restituito
-non è possibile prevedere quale sarà, né utilizzare un qualche valore statico,
-si pone perciò il problema di come processi diversi possono accedere allo
+non è possibile prevedere quale sarà, né utilizzare un qualche valore statico,
+si pone perciò il problema di come processi diversi possono accedere allo
stesso oggetto.
Per risolvere il problema nella struttura \struct{ipc\_perm} che il kernel
associa a ciascun oggetto, viene mantenuto anche un campo apposito che
contiene anche una \textsl{chiave}, identificata da una variabile del tipo
primitivo \type{key\_t}, da specificare in fase di creazione dell'oggetto, e
stesso oggetto.
Per risolvere il problema nella struttura \struct{ipc\_perm} che il kernel
associa a ciascun oggetto, viene mantenuto anche un campo apposito che
contiene anche una \textsl{chiave}, identificata da una variabile del tipo
primitivo \type{key\_t}, da specificare in fase di creazione dell'oggetto, e
si sposta il problema dell'accesso dalla classificazione in base
all'identificatore alla classificazione in base alla chiave, una delle tante
complicazioni inutili presenti nel \textit{SysV IPC}.} Oltre la chiave, la
si sposta il problema dell'accesso dalla classificazione in base
all'identificatore alla classificazione in base alla chiave, una delle tante
complicazioni inutili presenti nel \textit{SysV IPC}.} Oltre la chiave, la
-struttura, la cui definizione è riportata in fig.~\ref{fig:ipc_ipc_perm},
-mantiene varie proprietà ed informazioni associate all'oggetto.
+struttura, la cui definizione è riportata in fig.~\ref{fig:ipc_ipc_perm},
+mantiene varie proprietà ed informazioni associate all'oggetto.
-sono \textsl{imparentati} la soluzione è relativamente semplice, in tal caso
-infatti si può usare il valore speciale \texttt{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
+sono \textsl{imparentati} la soluzione è relativamente semplice, in tal caso
+infatti si può usare il valore speciale \texttt{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
-Però quando i processi non sono \textsl{imparentati} (come capita tutte le
-volte che si ha a che fare con un sistema client-server) tutto questo non è
+Però quando i processi non sono \textsl{imparentati} (come capita tutte le
+volte che si ha a che fare con un sistema client-server) tutto questo non è
possibile; si potrebbe comunque salvare l'identificatore su un file noto, ma
questo ovviamente comporta lo svantaggio di doverselo andare a rileggere. Una
possibile; si potrebbe comunque salvare l'identificatore su un file noto, ma
questo ovviamente comporta lo svantaggio di doverselo andare a rileggere. Una
-alternativa più efficace è quella che i programmi usino un valore comune per
-la chiave (che ad esempio può essere dichiarato in un header comune), ma c'è
-sempre il rischio che questa chiave possa essere stata già utilizzata da
+alternativa più efficace è quella che i programmi usino un valore comune per
+la chiave (che ad esempio può essere dichiarato in un header comune), ma c'è
+sempre il rischio che questa chiave possa essere stata già utilizzata da
qualcun altro. Dato che non esiste una convenzione su come assegnare queste
chiavi in maniera univoca l'interfaccia mette a disposizione una funzione
apposita, \funcd{ftok}, che permette di ottenere una chiave specificando il
qualcun altro. Dato che non esiste una convenzione su come assegnare queste
chiavi in maniera univoca l'interfaccia mette a disposizione una funzione
apposita, \funcd{ftok}, che permette di ottenere una chiave specificando il
Restituisce una chiave per identificare un oggetto del \textit{SysV IPC}.
\bodydesc{La funzione restituisce la chiave in caso di successo e -1
Restituisce una chiave per identificare un oggetto del \textit{SysV IPC}.
\bodydesc{La funzione restituisce la chiave in caso di successo e -1
effettivamente esistente e di un numero di progetto \param{proj\_id)}, che di
norma viene specificato come carattere, dato che ne vengono utilizzati solo
gli 8 bit meno significativi.\footnote{nelle libc4 e libc5, come avviene in
effettivamente esistente e di un numero di progetto \param{proj\_id)}, che di
norma viene specificato come carattere, dato che ne vengono utilizzati solo
gli 8 bit meno significativi.\footnote{nelle libc4 e libc5, come avviene in
\acr{glibc} usano il prototipo specificato da XPG4, ma vengono lo stesso
utilizzati gli 8 bit meno significativi.}
\acr{glibc} usano il prototipo specificato da XPG4, ma vengono lo stesso
utilizzati gli 8 bit meno significativi.}
-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)}
+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 \index{inode} dell'inode del file
\param{pathname} (che vengono ottenuti attraverso \func{stat}, da cui derivano
i possibili errori), e gli 8 bit meno significativi del numero del dispositivo
con i 16 bit meno significativi \index{inode} dell'inode del file
\param{pathname} (che vengono ottenuti attraverso \func{stat}, da cui derivano
i possibili errori), e gli 8 bit meno significativi del numero del dispositivo
collisioni, specie se i file sono su dispositivi con lo stesso
\itindex{minor~number} \textit{minor number}, come \file{/dev/hda1} e
\file{/dev/sda1}.
collisioni, specie se i file sono su dispositivi con lo stesso
\itindex{minor~number} \textit{minor number}, come \file{/dev/hda1} e
\file{/dev/sda1}.
devono comunicare (ad esempio un header comune, o uno dei programmi che devono
usare l'oggetto in questione), utilizzando il numero di progetto per ottenere
le chiavi che interessano. In ogni caso occorre sempre controllare, prima di
devono comunicare (ad esempio un header comune, o uno dei programmi che devono
usare l'oggetto in questione), utilizzando il numero di progetto per ottenere
le chiavi che interessano. In ogni caso occorre sempre controllare, prima di
bene in fase di creazione, le cose possono complicarsi per i programmi che
devono solo accedere, in quanto, a parte gli eventuali controlli sugli altri
bene in fase di creazione, le cose possono complicarsi per i programmi che
devono solo accedere, in quanto, a parte gli eventuali controlli sugli altri
sicuri che l'oggetto associato ad una certa chiave sia stato effettivamente
creato da chi ci si aspetta.
sicuri che l'oggetto associato ad una certa chiave sia stato effettivamente
creato da chi ci si aspetta.
effettuata una revisione completa nello standard POSIX.1b, che tratteremo in
sez.~\ref{sec:ipc_posix}.
effettuata una revisione completa nello standard POSIX.1b, che tratteremo in
sez.~\ref{sec:ipc_posix}.
\struct{ipc\_perm} ulteriori informazioni, come gli identificatori del creatore
(nei campi \var{cuid} e \var{cgid}) e del proprietario (nei campi \var{uid} e
\var{gid}) dello stesso, e un insieme di permessi (nel campo \var{mode}). In
\struct{ipc\_perm} ulteriori informazioni, come gli identificatori del creatore
(nei campi \var{cuid} e \var{cgid}) e del proprietario (nei campi \var{uid} e
\var{gid}) dello stesso, e un insieme di permessi (nel campo \var{mode}). In
-Benché questo controllo di accesso sia molto simile a quello dei file, restano
-delle importanti differenze. La prima è che il permesso di esecuzione non
-esiste (e se specificato viene ignorato), per cui si può parlare solo di
-permessi di lettura e scrittura (nel caso dei semafori poi quest'ultimo è più
+Benché questo controllo di accesso sia molto simile a quello dei file, restano
+delle importanti differenze. La prima è che il permesso di esecuzione non
+esiste (e se specificato viene ignorato), per cui si può parlare solo di
+permessi di lettura e scrittura (nel caso dei semafori poi quest'ultimo è più
propriamente un permesso di modifica). I valori di \var{mode} sono gli stessi
ed hanno lo stesso significato di quelli riportati in
propriamente un permesso di modifica). I valori di \var{mode} sono gli stessi
ed hanno lo stesso significato di quelli riportati in
-tab.~\ref{tab:file_mode_flags}\footnote{se però si vogliono usare le costanti
- simboliche ivi definite occorrerà includere il file \file{sys/stat.h},
+tab.~\ref{tab:file_mode_flags}\footnote{se però si vogliono usare le costanti
+ simboliche ivi definite occorrerà includere il file \file{sys/stat.h},
alcuni sistemi definiscono le costanti \const{MSG\_R} (\texttt{0400}) e
\const{MSG\_W} (\texttt{0200}) per indicare i permessi base di lettura e
scrittura per il proprietario, da utilizzare, con gli opportuni shift, pure
alcuni sistemi definiscono le costanti \const{MSG\_R} (\texttt{0400}) e
\const{MSG\_W} (\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
+ per il gruppo e gli altri, in Linux, visto la loro scarsa utilità, queste
costanti non sono definite.} e come per i file definiscono gli accessi per
il proprietario, il suo gruppo e tutti gli altri.
costanti non sono definite.} e come per i file definiscono gli accessi per
il proprietario, il suo gruppo e tutti gli altri.
che ha chiamato la funzione, ma, mentre i campi \var{uid} e \var{gid} possono
essere cambiati, i campi \var{cuid} e \var{cgid} restano sempre gli stessi.
che ha chiamato la funzione, ma, mentre i campi \var{uid} e \var{gid} possono
essere cambiati, i campi \var{cuid} e \var{cgid} restano sempre gli stessi.
funzioni che richiedono l'identificatore di un oggetto data la chiave. Queste
specificano tutte un argomento \param{flag}, in tal caso quando viene
effettuata la ricerca di una chiave, qualora \param{flag} specifichi dei
permessi, questi vengono controllati e l'identificatore viene restituito solo
se corrispondono a quelli dell'oggetto. Se ci sono dei permessi non presenti
funzioni che richiedono l'identificatore di un oggetto data la chiave. Queste
specificano tutte un argomento \param{flag}, in tal caso quando viene
effettuata la ricerca di una chiave, qualora \param{flag} specifichi dei
permessi, questi vengono controllati e l'identificatore viene restituito solo
se corrispondono a quelli dell'oggetto. Se ci sono dei permessi non presenti
-in \var{mode} l'accesso sarà negato. Questo controllo però è di utilità
-indicativa, dato che è sempre possibile specificare per \param{flag} un valore
-nullo, nel qual caso l'identificatore sarà restituito comunque.
+in \var{mode} l'accesso sarà negato. Questo controllo però è di utilità
+indicativa, dato che è sempre possibile specificare per \param{flag} un valore
+nullo, nel qual caso l'identificatore sarà restituito comunque.
consentito.
\item se l'user-ID effettivo del processo corrisponde o al valore del campo
\var{cuid} o a quello del campo \var{uid} ed il permesso per il proprietario
consentito.
\item se l'user-ID effettivo del processo corrisponde o al valore del campo
\var{cuid} o a quello del campo \var{uid} ed il permesso per il proprietario
\item se il group-ID effettivo del processo corrisponde o al
valore del campo \var{cgid} o a quello del campo \var{gid} ed il permesso
\item se il group-ID effettivo del processo corrisponde o al
valore del campo \var{cgid} o a quello del campo \var{gid} ed il permesso
- per il gruppo in \var{mode} è appropriato l'accesso è consentito.
-\item se il permesso per gli altri è appropriato l'accesso è consentito.
+ per il gruppo in \var{mode} è appropriato l'accesso è consentito.
+\item se il permesso per gli altri è appropriato l'accesso è consentito.
a differenza di quanto avviene per i permessi dei file, fallire in uno dei
passi elencati non comporta il fallimento dell'accesso. Un'ulteriore
a differenza di quanto avviene per i permessi dei file, fallire in uno dei
passi elencati non comporta il fallimento dell'accesso. Un'ulteriore
il valore di \itindex{umask} \textit{umask} (si ricordi quanto esposto in
sez.~\ref{sec:file_perm_management}) non ha alcun significato.
il valore di \itindex{umask} \textit{umask} (si ricordi quanto esposto in
sez.~\ref{sec:file_perm_management}) non ha alcun significato.
-L'unico campo di \struct{ipc\_perm} del quale non abbiamo ancora parlato è
-\var{seq}, che in fig.~\ref{fig:ipc_ipc_perm} è qualificato con un criptico
-``\textsl{numero di sequenza}'', ne parliamo adesso dato che esso è
-strettamente attinente alle modalità con cui il kernel assegna gli
+L'unico campo di \struct{ipc\_perm} del quale non abbiamo ancora parlato è
+\var{seq}, che in fig.~\ref{fig:ipc_ipc_perm} è qualificato con un criptico
+``\textsl{numero di sequenza}'', ne parliamo adesso dato che esso è
+strettamente attinente alle modalità con cui il kernel assegna gli
identificatori degli oggetti del sistema di IPC.
Quando il sistema si avvia, alla creazione di ogni nuovo oggetto di IPC viene
identificatori degli oggetti del sistema di IPC.
Quando il sistema si avvia, alla creazione di ogni nuovo oggetto di IPC viene
Questo va benissimo nel caso dei file descriptor, che sono locali ad un
processo, ma qui il comportamento varrebbe per tutto il sistema, e per
Questo va benissimo nel caso dei file descriptor, che sono locali ad un
processo, ma qui il comportamento varrebbe per tutto il sistema, e per
come quella in cui un server esce e cancella le sue code di messaggi, ed il
relativo identificatore viene immediatamente assegnato a quelle di un altro
come quella in cui un server esce e cancella le sue code di messaggi, ed il
relativo identificatore viene immediatamente assegnato a quelle di un altro
facciano in tempo ad accorgersi dell'avvenuto, e finiscano con l'interagire
con gli oggetti del secondo, con conseguenze imprevedibili.
Proprio per evitare questo tipo di situazioni il sistema usa il valore di
\var{seq} per provvedere un meccanismo che porti gli identificatori ad
facciano in tempo ad accorgersi dell'avvenuto, e finiscano con l'interagire
con gli oggetti del secondo, con conseguenze imprevedibili.
Proprio per evitare questo tipo di situazioni il sistema usa il valore di
\var{seq} per provvedere un meccanismo che porti gli identificatori ad
-assumere tutti i valori possibili, rendendo molto più lungo il periodo in cui
-un identificatore può venire riutilizzato.
+assumere tutti i valori possibili, rendendo molto più lungo il periodo in cui
+un identificatore può venire riutilizzato.
Il sistema dispone sempre di un numero fisso di oggetti di IPC,\footnote{fino
al kernel 2.2.x questi valori, definiti dalle costanti \const{MSGMNI},
\const{SEMMNI} e \const{SHMMNI}, potevano essere cambiati (come tutti gli
altri limiti relativi al \textit{SysV IPC}) solo con una ricompilazione del
kernel, andando a modificarne la definizione nei relativi header file. A
Il sistema dispone sempre di un numero fisso di oggetti di IPC,\footnote{fino
al kernel 2.2.x questi valori, definiti dalle costanti \const{MSGMNI},
\const{SEMMNI} e \const{SHMMNI}, potevano essere cambiati (come tutti gli
altri limiti relativi al \textit{SysV IPC}) solo con una ricompilazione del
kernel, andando a modificarne la definizione nei relativi header file. A
scrivendo sui file \procrelfile{/proc/sys/kernel}{shmmni},
\procrelfile{/proc/sys/kernel}{msgmni} e \procrelfile{/proc/sys/kernel}{sem}
di \file{/proc/sys/kernel} o con l'uso di \func{sysctl}.} e per ciascuno di
essi viene mantenuto in \var{seq} un numero di sequenza progressivo che viene
incrementato di uno ogni volta che l'oggetto viene cancellato. Quando
scrivendo sui file \procrelfile{/proc/sys/kernel}{shmmni},
\procrelfile{/proc/sys/kernel}{msgmni} e \procrelfile{/proc/sys/kernel}{sem}
di \file{/proc/sys/kernel} o con l'uso di \func{sysctl}.} e per ciascuno di
essi viene mantenuto in \var{seq} un numero di sequenza progressivo che viene
incrementato di uno ogni volta che l'oggetto viene cancellato. Quando
precedenza per restituire l'identificatore al numero di oggetti presenti viene
sommato il valore di \var{seq} moltiplicato per il numero massimo di oggetti
di quel tipo,\footnote{questo vale fino ai kernel della serie 2.2.x, dalla
precedenza per restituire l'identificatore al numero di oggetti presenti viene
sommato il valore di \var{seq} moltiplicato per il numero massimo di oggetti
di quel tipo,\footnote{questo vale fino ai kernel della serie 2.2.x, dalla
dalla costante \const{IPCMNI}, definita in \file{include/linux/ipc.h}, che
indica il limite massimo per il numero di tutti oggetti di IPC, ed il cui
dalla costante \const{IPCMNI}, definita in \file{include/linux/ipc.h}, che
indica il limite massimo per il numero di tutti oggetti di IPC, ed il cui
- valore è 32768.} si evita così il riutilizzo degli stessi numeri, e si fa
-sì che l'identificatore assuma tutti i valori possibili.
+ valore è 32768.} si evita così il riutilizzo degli stessi numeri, e si fa
+sì che l'identificatore assuma tutti i valori possibili.
programma di test che si limita a creare un oggetto (specificato a riga di
comando), stamparne il numero di identificatore e cancellarlo per un numero
programma di test che si limita a creare un oggetto (specificato a riga di
comando), stamparne il numero di identificatore e cancellarlo per un numero
delle opzioni a riga di comando, che permette di specificare quante volte
effettuare il ciclo \var{n}, e su quale tipo di oggetto eseguirlo.
delle opzioni a riga di comando, che permette di specificare quante volte
effettuare il ciclo \var{n}, e su quale tipo di oggetto eseguirlo.
inizializzare i valori delle variabili \var{type} al tipo di oggetto voluto, e
\var{n} al numero di volte che si vuole effettuare il ciclo di creazione,
stampa, cancellazione. I valori di default sono per l'uso delle code di
inizializzare i valori delle variabili \var{type} al tipo di oggetto voluto, e
\var{n} al numero di volte che si vuole effettuare il ciclo di creazione,
stampa, cancellazione. I valori di default sono per l'uso delle code di
quello di permettere a processi diversi di scambiarsi dei dati.
La funzione che permette di richiedere al sistema l'identificatore di una coda
quello di permettere a processi diversi di scambiarsi dei dati.
La funzione che permette di richiedere al sistema l'identificatore di una coda
-di messaggi esistente (o di crearne una se questa non esiste) è
-\funcd{msgget}; il suo prototipo è:
+di messaggi esistente (o di crearne una se questa non esiste) è
+\funcd{msgget}; il suo prototipo è:
Restituisce l'identificatore di una coda di messaggi.
\bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
Restituisce l'identificatore di una coda di messaggi.
\bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
- \item[\errcode{EIDRM}] la coda richiesta è marcata per essere cancellata.
- \item[\errcode{ENOENT}] si è cercato di ottenere l'identificatore di una coda
+ \item[\errcode{EIDRM}] la coda richiesta è marcata per essere cancellata.
+ \item[\errcode{ENOENT}] si è cercato di ottenere l'identificatore di una coda
Le funzione (come le analoghe che si usano per gli altri oggetti) serve sia a
ottenere l'identificatore di una coda di messaggi esistente, che a crearne una
Le funzione (come le analoghe che si usano per gli altri oggetti) serve sia a
ottenere l'identificatore di una coda di messaggi esistente, che a crearne una
associata alcuna chiave, il processo (ed i suoi eventuali figli) potranno
farvi riferimento solo attraverso l'identificatore.
Se invece si specifica un valore diverso da \const{IPC\_PRIVATE}\footnote{in
Linux questo significa un valore diverso da zero.} l'effetto della funzione
associata alcuna chiave, il processo (ed i suoi eventuali figli) potranno
farvi riferimento solo attraverso l'identificatore.
Se invece si specifica un valore diverso da \const{IPC\_PRIVATE}\footnote{in
Linux questo significa un valore diverso da zero.} l'effetto della funzione
effettuare una ricerca sugli oggetti esistenti, restituendo l'identificatore
se trova una corrispondenza, o fallendo con un errore di \errcode{ENOENT} se
non esiste o di \errcode{EACCES} se si sono specificati dei permessi non
validi.
effettuare una ricerca sugli oggetti esistenti, restituendo l'identificatore
se trova una corrispondenza, o fallendo con un errore di \errcode{ENOENT} se
non esiste o di \errcode{EACCES} se si sono specificati dei permessi non
validi.
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
significativi di \param{flag} saranno usati come permessi per il nuovo
oggetto, secondo quanto illustrato in sez.~\ref{sec:ipc_sysv_access_control}.
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
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à
-successo solo se l'oggetto non esiste già, fallendo con un errore di
+Se si imposta anche il bit corrispondente a \const{IPC\_EXCL} la funzione avrà
+successo solo se l'oggetto non esiste già, fallendo con un errore di
Le code di messaggi sono caratterizzate da tre limiti fondamentali, definiti
negli header e corrispondenti alle prime tre costanti riportate in
Le code di messaggi sono caratterizzate da tre limiti fondamentali, definiti
negli header e corrispondenti alle prime tre costanti riportate in
modificare questi limiti attraverso l'uso di \func{sysctl} o scrivendo nei
file \procrelfile{/proc/sys/kernel}{msgmax},
\procrelfile{/proc/sys/kernel}{msgmnb} e
modificare questi limiti attraverso l'uso di \func{sysctl} o scrivendo nei
file \procrelfile{/proc/sys/kernel}{msgmax},
\procrelfile{/proc/sys/kernel}{msgmnb} e
-Una coda di messaggi è costituita da una \itindex{linked~list} \textit{linked
- list};\footnote{una \itindex{linked~list} \textit{linked list} è una tipica
+Una coda di messaggi è costituita da una \itindex{linked~list} \textit{linked
+ list};\footnote{una \itindex{linked~list} \textit{linked list} è una tipica
- un puntatore al successivo. In questo modo la struttura è veloce
- nell'estrazione ed immissione dei dati dalle estremità dalla lista (basta
+ 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
aggiungere un elemento in testa o in coda ed aggiornare un puntatore), e
relativamente veloce da attraversare in ordine sequenziale (seguendo i
-A ciascuna coda è associata una struttura \struct{msgid\_ds}, la cui
-definizione, è riportata in fig.~\ref{fig:ipc_msqid_ds}. In questa struttura il
+A ciascuna coda è associata una struttura \struct{msgid\_ds}, la cui
+definizione, è riportata in fig.~\ref{fig:ipc_msqid_ds}. In questa struttura il
kernel mantiene le principali informazioni riguardo lo stato corrente della
coda.\footnote{come accennato questo vale fino ai kernel della serie 2.2.x,
kernel mantiene le principali informazioni riguardo lo stato corrente della
coda.\footnote{come accennato questo vale fino ai kernel della serie 2.2.x,
- essa viene usata nei kernel della serie 2.4.x solo per compatibilità in
- quanto è quella restituita dalle funzioni dell'interfaccia. Si noti come ci
+ essa viene usata nei kernel della serie 2.4.x solo per compatibilità in
+ quanto è quella restituita dalle funzioni dell'interfaccia. Si noti come ci
sia una differenza con i campi mostrati nello schema di
fig.~\ref{fig:ipc_mq_schema} che sono presi dalla definizione di
\file{linux/msg.h}, e fanno riferimento alla definizione della omonima
sia una differenza con i campi mostrati nello schema di
fig.~\ref{fig:ipc_mq_schema} che sono presi dalla definizione di
\file{linux/msg.h}, e fanno riferimento alla definizione della omonima
rispettivamente il \acr{pid} dell'ultimo processo che ha inviato o ricevuto
un messaggio sulla coda, sono inizializzati a 0.
\item i campi \var{msg\_stime} e \var{msg\_rtime}, che esprimono
rispettivamente il \acr{pid} dell'ultimo processo che ha inviato o ricevuto
un messaggio sulla coda, sono inizializzati a 0.
\item i campi \var{msg\_stime} e \var{msg\_rtime}, che esprimono
messaggio sulla coda, sono inizializzati a 0.
\item il campo \var{msg\_ctime}, che esprime il tempo di creazione della coda,
viene inizializzato al tempo corrente.
messaggio sulla coda, sono inizializzati a 0.
\item il campo \var{msg\_ctime}, che esprime il tempo di creazione della coda,
viene inizializzato al tempo corrente.
del sistema (\const{MSGMNB}).
\item i campi \var{msg\_first} e \var{msg\_last} che esprimono l'indirizzo del
primo e ultimo messaggio sono inizializzati a \val{NULL} e
del sistema (\const{MSGMNB}).
\item i campi \var{msg\_first} e \var{msg\_last} che esprimono l'indirizzo del
primo e ultimo messaggio sono inizializzati a \val{NULL} e
inizializzato a zero. Questi campi sono ad uso interno dell'implementazione
e non devono essere utilizzati da programmi in user space).
\end{itemize*}
Una volta creata una coda di messaggi le operazioni di controllo vengono
effettuate con la funzione \funcd{msgctl}, che (come le analoghe \func{semctl}
inizializzato a zero. Questi campi sono ad uso interno dell'implementazione
e non devono essere utilizzati da programmi in user space).
\end{itemize*}
Una volta creata una coda di messaggi le operazioni di controllo vengono
effettuate con la funzione \funcd{msgctl}, che (come le analoghe \func{semctl}
Esegue l'operazione specificata da \param{cmd} sulla coda \param{msqid}.
\bodydesc{La funzione restituisce 0 in caso di successo o $-1$ in caso di
Esegue l'operazione specificata da \param{cmd} sulla coda \param{msqid}.
\bodydesc{La funzione restituisce 0 in caso di successo o $-1$ in caso di
- \item[\errcode{EIDRM}] la coda richiesta è stata cancellata.
- \item[\errcode{EPERM}] si è richiesto \const{IPC\_SET} o \const{IPC\_RMID} ma
- il processo non ha i privilegi, o si è richiesto di aumentare il valore di
+ \item[\errcode{EIDRM}] la coda richiesta è stata cancellata.
+ \item[\errcode{EPERM}] si è richiesto \const{IPC\_SET} o \const{IPC\_RMID} ma
+ il processo non ha i privilegi, o si è richiesto di aumentare il valore di
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
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
con user-ID effettivo corrispondente al creatore o al proprietario della
coda, o all'amministratore.
\item[\const{IPC\_SET}] Permette di modificare i permessi ed il proprietario
con user-ID effettivo corrispondente al creatore o al proprietario della
coda, o all'amministratore.
\item[\const{IPC\_SET}] Permette di modificare i permessi ed il proprietario
struttura \struct{msqid\_ds} puntata da \param{buf}. Per modificare i valori
di \var{msg\_perm.mode}, \var{msg\_perm.uid} e \var{msg\_perm.gid} occorre
essere il proprietario o il creatore della coda, oppure l'amministratore; lo
struttura \struct{msqid\_ds} puntata da \param{buf}. Per modificare i valori
di \var{msg\_perm.mode}, \var{msg\_perm.uid} e \var{msg\_perm.gid} occorre
essere il proprietario o il creatore della coda, oppure l'amministratore; lo
incrementarne il valore a limiti superiori a \const{MSGMNB}.
\end{basedescript}
Una volta che si abbia a disposizione l'identificatore, per inviare un
messaggio su una coda si utilizza la funzione \funcd{msgsnd}; il suo prototipo
incrementarne il valore a limiti superiori a \const{MSGMNB}.
\end{basedescript}
Una volta che si abbia a disposizione l'identificatore, per inviare un
messaggio su una coda si utilizza la funzione \funcd{msgsnd}; il suo prototipo
Invia un messaggio sulla coda \param{msqid}.
\bodydesc{La funzione restituisce 0, e $-1$ in caso di errore, nel qual caso
Invia un messaggio sulla coda \param{msqid}.
\bodydesc{La funzione restituisce 0, e $-1$ in caso di errore, nel qual caso
- \item[\errcode{EIDRM}] la coda è stata cancellata.
- \item[\errcode{EAGAIN}] il messaggio non può essere inviato perché si è
+ \item[\errcode{EIDRM}] la coda è stata cancellata.
+ \item[\errcode{EAGAIN}] il messaggio non può essere inviato perché si è
- sulla coda, e si è richiesto \const{IPC\_NOWAIT} in \param{flag}.
- \item[\errcode{EINVAL}] si è specificato un \param{msgid} invalido, o un
+ sulla coda, e si è richiesto \const{IPC\_NOWAIT} in \param{flag}.
+ \item[\errcode{EINVAL}] si è specificato un \param{msgid} invalido, o un
valore non positivo per \param{mtype}, o un valore di \param{msgsz}
maggiore di \const{MSGMAX}.
\end{errlist}
valore non positivo per \param{mtype}, o un valore di \param{msgsz}
maggiore di \const{MSGMAX}.
\end{errlist}
l'argomento \param{msgp}. Quest'ultimo deve venire passato sempre come
puntatore ad una struttura \struct{msgbuf} analoga a quella riportata in
l'argomento \param{msgp}. Quest'ultimo deve venire passato sempre come
puntatore ad una struttura \struct{msgbuf} analoga a quella riportata in
-fig.~\ref{fig:ipc_msbuf} che è quella che deve contenere effettivamente il
-messaggio. La dimensione massima per il testo di un messaggio non può
+fig.~\ref{fig:ipc_msbuf} che è quella che deve contenere effettivamente il
+messaggio. La dimensione massima per il testo di un messaggio non può
-campo il valore \code{mtext[1]}, che non è di nessuna utilità ai fini pratici.
-La sola cosa che conta è che la struttura abbia come primo membro un campo
+campo il valore \code{mtext[1]}, che non è di nessuna utilità ai fini pratici.
+La sola cosa che conta è che la struttura abbia come primo membro un campo
\var{mtype} come nell'esempio; esso infatti serve ad identificare il tipo di
messaggio e deve essere sempre specificato come intero positivo di tipo
\var{mtype} come nell'esempio; esso infatti serve ad identificare il tipo di
messaggio e deve essere sempre specificato come intero positivo di tipo
dimensione, e serve a contenere il testo del messaggio.
In generale pertanto per inviare un messaggio con \func{msgsnd} si usa
ridefinire una struttura simile a quella di fig.~\ref{fig:ipc_msbuf}, adattando
alle proprie esigenze il campo \var{mtype}, (o ridefinendo come si vuole il
dimensione, e serve a contenere il testo del messaggio.
In generale pertanto per inviare un messaggio con \func{msgsnd} si usa
ridefinire una struttura simile a quella di fig.~\ref{fig:ipc_msbuf}, adattando
alle proprie esigenze il campo \var{mtype}, (o ridefinendo come si vuole il
-corpo del messaggio, anche con più campi o con strutture più complesse) avendo
-però la cura di mantenere nel primo campo un valore di tipo \ctyp{long} che ne
+corpo del messaggio, anche con più campi o con strutture più complesse) avendo
+però la cura di mantenere nel primo campo un valore di tipo \ctyp{long} che ne
-argomento è solo quella del messaggio, non quella di tutta la struttura, se
-cioè \var{message} è una propria struttura che si passa alla funzione,
-\param{msgsz} dovrà essere uguale a \code{sizeof(message)-sizeof(long)}, (se
+argomento è solo quella del messaggio, non quella di tutta la struttura, se
+cioè \var{message} è una propria struttura che si passa alla funzione,
+\param{msgsz} dovrà essere uguale a \code{sizeof(message)-sizeof(long)}, (se
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
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
+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
-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
+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
all'indirizzo specificato da \var{msg\_spot}.
Il valore dell'argomento \param{flag} permette di specificare il comportamento
\var{msg\_qbytes}, o il limite di sistema sul numero di messaggi, nel qual
caso si blocca mandando il processo in stato di \textit{sleep}. Se si
specifica per \param{flag} il valore \const{IPC\_NOWAIT} la funzione opera in
\var{msg\_qbytes}, o il limite di sistema sul numero di messaggi, nel qual
caso si blocca mandando il processo in stato di \textit{sleep}. Se si
specifica per \param{flag} il valore \const{IPC\_NOWAIT} la funzione opera in
una condizione di errore anche in due altri casi: quando la coda viene rimossa
(nel qual caso si ha un errore di \errcode{EIDRM}) o quando la funzione viene
interrotta da un segnale (nel qual caso si ha un errore di \errcode{EINTR}).
una condizione di errore anche in due altri casi: quando la coda viene rimossa
(nel qual caso si ha un errore di \errcode{EIDRM}) o quando la funzione viene
interrotta da un segnale (nel qual caso si ha un errore di \errcode{EINTR}).
-La funzione che viene utilizzata per estrarre un messaggio da una coda è
-\funcd{msgrcv}; il suo prototipo è:
+La funzione che viene utilizzata per estrarre un messaggio da una coda è
+\funcd{msgrcv}; il suo prototipo è:
Legge un messaggio dalla coda \param{msqid}.
\bodydesc{La funzione restituisce il numero di byte letti in caso di
Legge un messaggio dalla coda \param{msqid}.
\bodydesc{La funzione restituisce il numero di byte letti in caso di
- \item[\errcode{EIDRM}] la coda è stata cancellata.
- \item[\errcode{E2BIG}] il testo del messaggio è più lungo di \param{msgsz} e
- non si è specificato \const{MSG\_NOERROR} in \param{msgflg}.
- \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale mentre
+ \item[\errcode{EIDRM}] la coda è stata cancellata.
+ \item[\errcode{E2BIG}] il testo del messaggio è più lungo di \param{msgsz} e
+ non si è specificato \const{MSG\_NOERROR} in \param{msgflg}.
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale mentre
-struttura puntata da \param{msgp}, che dovrà avere un formato analogo a quello
-di fig.~\ref{fig:ipc_msbuf}. Una volta estratto, il messaggio sarà rimosso
+struttura puntata da \param{msgp}, che dovrà avere un 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}).
Se il testo del messaggio ha lunghezza inferiore a \param{msgsz} esso viene
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}).
Se il testo del messaggio ha lunghezza inferiore a \param{msgsz} esso viene
\const{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}.
L'argomento \param{msgtyp} permette di restringere la ricerca ad un
\const{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}.
L'argomento \param{msgtyp} permette di restringere la ricerca ad un
una scansione della struttura mostrata in fig.~\ref{fig:ipc_mq_schema},
restituendo il primo messaggio incontrato che corrisponde ai criteri
specificati (che quindi, visto come i messaggi vengono sempre inseriti dalla
una scansione della struttura mostrata in fig.~\ref{fig:ipc_mq_schema},
restituendo il primo messaggio incontrato che corrisponde ai criteri
specificati (che quindi, visto come i messaggi vengono sempre inseriti dalla
-\item se \param{msgtyp} è 0 viene estratto il messaggio in cima alla coda, cioè
- quello fra i presenti che è stato inserito per primo.
-\item se \param{msgtyp} è positivo viene estratto il primo messaggio il cui
+\item se \param{msgtyp} è 0 viene estratto il messaggio in cima alla coda, cioè
+ quello fra i presenti che è stato inserito per primo.
+\item se \param{msgtyp} è positivo viene estratto il primo messaggio il cui
-\item se \param{msgtyp} è negativo viene estratto il primo fra i messaggi con
- il valore più basso del tipo, fra tutti quelli il cui tipo ha un valore
+\item se \param{msgtyp} è negativo viene estratto il primo fra i messaggi con
+ il valore più basso del tipo, fra tutti quelli il cui tipo ha un valore
inferiore al valore assoluto di \param{msgtyp}.
\end{itemize}
Il valore di \param{msgflg} permette di controllare il comportamento della
inferiore al valore assoluto di \param{msgtyp}.
\end{itemize}
Il valore di \param{msgflg} permette di controllare il comportamento della
-valori: \const{MSG\_EXCEPT}, che permette, quando \param{msgtyp} è positivo,
+valori: \const{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.
Il comportamento usuale della funzione infatti, se non ci sono messaggi
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.
Il comportamento usuale della funzione infatti, se non ci sono messaggi
-disponibili per la lettura, è di bloccare il processo in stato di
-\textit{sleep}. Nel caso però si sia specificato \const{IPC\_NOWAIT} la
+disponibili per la lettura, è di bloccare il processo in stato di
+\textit{sleep}. Nel caso però si sia specificato \const{IPC\_NOWAIT} la
funzione ritorna immediatamente con un errore \errcode{ENOMSG}. Altrimenti la
funzione ritorna normalmente non appena viene inserito un messaggio del tipo
desiderato, oppure ritorna con errore qualora la coda sia rimossa (con
funzione ritorna immediatamente con un errore \errcode{ENOMSG}. Altrimenti la
funzione ritorna normalmente non appena viene inserito un messaggio del tipo
desiderato, oppure ritorna con errore qualora la coda sia rimossa (con
Le code di messaggi presentano il solito problema di tutti gli oggetti del
SysV IPC; essendo questi permanenti restano nel sistema occupando risorse
Le code di messaggi presentano il solito problema di tutti gli oggetti del
SysV IPC; essendo questi permanenti restano nel sistema occupando risorse
sistema, e che devono comunque essere esplicitamente previste delle funzioni
di rimozione in caso di interruzioni o uscite dal programma (come vedremo in
fig.~\ref{fig:ipc_mq_fortune_server}).
sistema, e che devono comunque essere esplicitamente previste delle funzioni
di rimozione in caso di interruzioni o uscite dal programma (come vedremo in
fig.~\ref{fig:ipc_mq_fortune_server}).
\textit{I/O multiplexing} descritte in sez.~\ref{sec:file_multiplexing} non
possono essere utilizzate, e non si ha a disposizione niente di analogo alle
\textit{I/O multiplexing} descritte in sez.~\ref{sec:file_multiplexing} non
possono essere utilizzate, e non si ha a disposizione niente di analogo alle
-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
+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
-In fig.~\ref{fig:ipc_mq_fortune_server} si è riportato un estratto delle parti
-principali del codice del nuovo server (il codice completo è nel file
-\file{MQFortuneServer.c} nei sorgenti allegati). Il programma è basato su un
+In fig.~\ref{fig:ipc_mq_fortune_server} si è riportato un estratto delle parti
+principali del codice del nuovo server (il codice completo è nel file
+\file{MQFortuneServer.c} nei sorgenti allegati). Il programma è basato su un
uso accorto della caratteristica di poter associate un ``tipo'' ai messaggi
per permettere una comunicazione indipendente fra il server ed i vari client,
uso accorto della caratteristica di poter associate un ``tipo'' ai messaggi
per permettere una comunicazione indipendente fra il server ed i vari client,
-usando il \acr{pid} di questi ultimi come identificativo. Questo è possibile
-in quanto, al contrario di una fifo, la lettura di una coda di messaggi può
+usando il \acr{pid} di questi ultimi come identificativo. Questo è possibile
+in quanto, al contrario di una fifo, la lettura di una coda di messaggi può
\var{msgbuf\_read} (\texttt{\small 8--11}) vengono passate le richieste mentre
con \var{msgbuf\_write} (\texttt{\small 12--15}) vengono restituite le frasi.
\var{msgbuf\_read} (\texttt{\small 8--11}) vengono passate le richieste mentre
con \var{msgbuf\_write} (\texttt{\small 12--15}) vengono restituite le frasi.
in \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 l'uscita dal
server, viene prima controllato (\texttt{\small 22}) il numero di frasi
in \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 l'uscita dal
server, viene prima controllato (\texttt{\small 22}) il numero di frasi
(\texttt{\small 23}) vengono lette nel vettore in memoria con la stessa
funzione \code{FortuneParse} usata anche per il server basato sulle fifo.
(\texttt{\small 23}) vengono lette nel vettore in memoria con la stessa
funzione \code{FortuneParse} usata anche per il server basato sulle fifo.
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
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
-corrisponde al \acr{pid} di \cmd{init}, che non può essere un client. L'uso
-del flag \const{MSG\_NOERROR} è solo per sicurezza, dato che i messaggi di
+\var{mtype} uguale a 1: questo è il valore usato per le richieste dato che
+corrisponde al \acr{pid} di \cmd{init}, che non può essere un client. L'uso
+del flag \const{MSG\_NOERROR} è solo per sicurezza, dato che i messaggi di
ritornando soltanto in corrispondenza dell'arrivo sulla coda di un messaggio
di richiesta da parte di un client, in tal caso il ciclo prosegue
(\texttt{\small 35}) selezionando una frase a caso, copiandola (\texttt{\small
ritornando soltanto in corrispondenza dell'arrivo sulla coda di un messaggio
di richiesta da parte di un client, in tal caso il ciclo prosegue
(\texttt{\small 35}) selezionando una frase a caso, copiandola (\texttt{\small
Per poter permettere a ciascun client di ricevere solo la risposta indirizzata
a lui il tipo del messaggio in uscita viene inizializzato (\texttt{\small 38})
al valore del \acr{pid} del client ricevuto nel messaggio di richiesta.
Per poter permettere a ciascun client di ricevere solo la risposta indirizzata
a lui il tipo del messaggio in uscita viene inizializzato (\texttt{\small 38})
al valore del \acr{pid} del client ricevuto nel messaggio di richiesta.
-L'ultimo passo del ciclo (\texttt{\small 39}) è inviare sulla coda il
-messaggio di risposta. Si tenga conto che se la coda è piena anche questa
-funzione potrà bloccarsi fintanto che non venga liberato dello spazio.
+L'ultimo passo del ciclo (\texttt{\small 39}) è inviare sulla coda il
+messaggio di risposta. Si tenga conto che se la coda è piena anche questa
+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
+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
gestore \code{HandSIGTERM}, che semplicemente si limita a cancellare la coda
(\texttt{\small 46}) ed ad uscire (\texttt{\small 47}).
gestore \code{HandSIGTERM}, che semplicemente si limita a cancellare la coda
(\texttt{\small 46}) ed ad uscire (\texttt{\small 47}).
-In fig.~\ref{fig:ipc_mq_fortune_client} si è riportato un estratto il codice
-del programma client. Al solito il codice completo è con i sorgenti allegati,
+In fig.~\ref{fig:ipc_mq_fortune_client} si è riportato un estratto il codice
+del programma client. Al solito il codice completo è con i sorgenti allegati,
nel file \file{MQFortuneClient.c}. Come sempre si sono rimosse le parti
relative alla gestione delle opzioni, ed in questo caso, anche la
dichiarazione delle variabili, che, per la parte relative alle strutture usate
per la comunicazione tramite le code, sono le stesse viste in
fig.~\ref{fig:ipc_mq_fortune_server}.
nel file \file{MQFortuneClient.c}. Come sempre si sono rimosse le parti
relative alla gestione delle opzioni, ed in questo caso, anche la
dichiarazione delle variabili, che, per la parte relative alle strutture usate
per la comunicazione tramite le code, sono le stesse viste in
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 è
+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 è
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
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
il programma termina immediatamente.
Una volta acquisito l'identificatore della coda il client compone il
il programma termina immediatamente.
Una volta acquisito l'identificatore della coda il client compone il
A questo punto non resta che (\texttt{\small 16}) rileggere dalla coda la
risposta del server richiedendo a \func{msgrcv} di selezionare i messaggi di
tipo corrispondente al valore del \acr{pid} inviato nella richiesta. L'ultimo
A questo punto non resta che (\texttt{\small 16}) rileggere dalla coda la
risposta del server richiedendo a \func{msgrcv} di selezionare i messaggi di
tipo corrispondente al valore del \acr{pid} inviato nella richiesta. L'ultimo
[piccardi@gont sources]$ ./mqfortuned -n10
\end{verbatim}%$
come nel caso precedente, avendo eseguito il server in background, il comando
[piccardi@gont sources]$ ./mqfortuned -n10
\end{verbatim}%$
come nel caso precedente, avendo eseguito il server in background, il comando
-ritornerà immediatamente; potremo però verificare con \cmd{ps} che il
-programma è effettivamente in esecuzione, e che ha creato una coda di
+ritornerà immediatamente; potremo però verificare con \cmd{ps} che il
+programma è effettivamente in esecuzione, e che ha creato una coda di
\begin{verbatim}
[piccardi@gont sources]$ ./mqfortune
Linux ext2fs has been stable for a long time, now it's time to break it
\begin{verbatim}
[piccardi@gont sources]$ ./mqfortune
Linux ext2fs has been stable for a long time, now it's time to break it
il server inviando il segnale di terminazione con il comando \code{killall
mqfortuned} verificando che effettivamente la coda di messaggi viene rimossa.
il server inviando il segnale di terminazione con il comando \code{killall
mqfortuned} verificando che effettivamente la coda di messaggi viene rimossa.
visto anche nel caso del precedente server basato sulle fifo; se il client
viene interrotto dopo l'invio del messaggio di richiesta e prima della lettura
visto anche nel caso del precedente server basato sulle fifo; se il client
viene interrotto dopo l'invio del messaggio di richiesta e prima della lettura
-della risposta, quest'ultima resta nella coda (così come per le fifo si aveva
-il problema delle fifo che restavano nel filesystem). In questo caso però il
-problemi sono maggiori, sia perché è molto più facile esaurire la memoria
+della risposta, quest'ultima resta nella coda (così come per le fifo si aveva
+il problema delle fifo che restavano nel filesystem). In questo caso però il
+problemi sono maggiori, sia perché è molto più facile esaurire la memoria
di protezione per le \index{sezione~critica} \textsl{sezioni critiche} del
codice (si ricordi quanto detto in sez.~\ref{sec:proc_race_cond}).
di protezione per le \index{sezione~critica} \textsl{sezioni critiche} del
codice (si ricordi quanto detto in sez.~\ref{sec:proc_race_cond}).
-Un semaforo è uno speciale contatore, mantenuto nel kernel, che permette, a
+Un semaforo è uno speciale contatore, mantenuto nel kernel, che permette, a
-di un programma. In questo modo l'accesso ad una risorsa condivisa da più
-processi può essere controllato, associando ad essa un semaforo che consente
-di assicurare che non più di un processo alla volta possa usarla.
-
-Il concetto di semaforo è uno dei concetti base nella programmazione ed è
-assolutamente generico, così come del tutto generali sono modalità con cui lo
-si utilizza. Un processo che deve accedere ad una risorsa eseguirà un
-controllo del semaforo: se questo è positivo il suo valore sarà decrementato,
-indicando che si è consumato una unità della risorsa, ed il processo potrà
+di un programma. In questo modo l'accesso ad una risorsa condivisa da più
+processi può essere controllato, associando ad essa un semaforo che consente
+di assicurare che non più di un processo alla volta possa usarla.
+
+Il concetto di semaforo è uno dei concetti base nella programmazione ed è
+assolutamente generico, così come del tutto generali sono modalità con cui lo
+si utilizza. Un processo che deve accedere ad una risorsa eseguirà un
+controllo del semaforo: se questo è positivo il suo valore sarà decrementato,
+indicando che si è consumato una unità della risorsa, ed il processo potrà
proseguire nell'utilizzo di quest'ultima, provvedendo a rilasciarla, una volta
completate le operazioni volute, reincrementando il semaforo.
proseguire nell'utilizzo di quest'ultima, provvedendo a rilasciarla, una volta
completate le operazioni volute, reincrementando il semaforo.
-Se al momento del controllo il valore del semaforo è nullo, siamo invece in
-una situazione in cui la risorsa non è disponibile, ed il processo si
-bloccherà in stato di \textit{sleep} fin quando chi la sta utilizzando non la
-rilascerà, incrementando il valore del semaforo. Non appena il semaforo torna
-positivo, indicando che la risorsa è disponibile, il processo sarà svegliato,
-e si potrà operare come nel caso precedente (decremento del semaforo, accesso
+Se al momento del controllo il valore del semaforo è nullo, siamo invece in
+una situazione in cui la risorsa non è disponibile, ed il processo si
+bloccherà in stato di \textit{sleep} fin quando chi la sta utilizzando non la
+rilascerà, incrementando il valore del semaforo. Non appena il semaforo torna
+positivo, indicando che la risorsa è disponibile, il processo sarà svegliato,
+e si potrà operare come nel caso precedente (decremento del semaforo, accesso
alla risorsa, incremento del semaforo).
Per poter implementare questo tipo di logica le operazioni di controllo e
decremento del contatore associato al semaforo devono essere atomiche,
alla risorsa, incremento del semaforo).
Per poter implementare questo tipo di logica le operazioni di controllo e
decremento del contatore associato al semaforo devono essere atomiche,
-pertanto una realizzazione di un oggetto di questo tipo è necessariamente
-demandata al kernel. La forma più semplice di semaforo è quella del
+pertanto una realizzazione di un oggetto di questo tipo è necessariamente
+demandata al kernel. La forma più semplice di semaforo è quella del
-(normalmente 1) indica la libertà di accesso, e un valore nullo l'occupazione
-della risorsa. In generale però si possono usare semafori con valori interi,
+(normalmente 1) indica la libertà di accesso, e un valore nullo l'occupazione
+della risorsa. In generale però si possono usare semafori con valori interi,
utilizzando il valore del contatore come indicatore del ``numero di risorse''
ancora disponibili.
Il sistema di comunicazione inter-processo di \textit{SysV IPC} prevede anche i
semafori, ma gli oggetti utilizzati non sono semafori singoli, ma gruppi di
semafori detti \textsl{insiemi} (o \textit{semaphore set}); la funzione che
utilizzando il valore del contatore come indicatore del ``numero di risorse''
ancora disponibili.
Il sistema di comunicazione inter-processo di \textit{SysV IPC} prevede anche i
semafori, ma gli oggetti utilizzati non sono semafori singoli, ma gruppi di
semafori detti \textsl{insiemi} (o \textit{semaphore set}); la funzione che
-permette di creare o ottenere l'identificatore di un insieme di semafori è
-\funcd{semget}, ed il suo prototipo è:
+permette di creare o ottenere l'identificatore di un insieme di semafori è
+\funcd{semget}, ed il suo prototipo è:
Restituisce l'identificatore di un insieme di semafori.
\bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
Restituisce l'identificatore di un insieme di semafori.
\bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
- \item[\errcode{ENOSPC}] si è cercato di creare una insieme di semafori
- quando è stato superato o il limite per il numero totale di semafori
+ \item[\errcode{ENOSPC}] si è cercato di creare una insieme di semafori
+ quando è stato superato o il limite per il numero totale di semafori
semafori che contiene.
\item[\errcode{ENOMEM}] il sistema non ha abbastanza memoria per poter
contenere le strutture per un nuovo insieme di semafori.
semafori che contiene.
\item[\errcode{ENOMEM}] il sistema non ha abbastanza memoria per poter
contenere le strutture per un nuovo insieme di semafori.
-La funzione è del tutto analoga a \func{msgget}, solo che in questo caso
-restituisce l'identificatore di un insieme di semafori, in particolare è
+La funzione è del tutto analoga a \func{msgget}, solo che in questo caso
+restituisce l'identificatore di un insieme di semafori, in particolare è
identico l'uso degli argomenti \param{key} e \param{flag}, per cui non
ripeteremo quanto detto al proposito in sez.~\ref{sec:ipc_sysv_mq}. L'argomento
\param{nsems} permette di specificare quanti semafori deve contenere l'insieme
quando se ne richieda la creazione, e deve essere nullo quando si effettua una
identico l'uso degli argomenti \param{key} e \param{flag}, per cui non
ripeteremo quanto detto al proposito in sez.~\ref{sec:ipc_sysv_mq}. L'argomento
\param{nsems} permette di specificare quanti semafori deve contenere l'insieme
quando se ne richieda la creazione, e deve essere nullo quando si effettua una
-abbiamo descritto, dato che non è possibile definire un singolo semaforo, ma
-se ne deve creare per forza un insieme. Ma questa in definitiva è solo una
-complicazione inutile, il problema è che i semafori del \textit{SysV IPC}
-soffrono di altri due, ben più gravi, difetti.
+abbiamo descritto, dato che non è possibile definire un singolo semaforo, ma
+se ne deve creare per forza un insieme. Ma questa in definitiva è solo una
+complicazione inutile, il problema è che i semafori del \textit{SysV IPC}
+soffrono di altri due, ben più gravi, difetti.
inizializzare un semaforo in un'unica chiamata; occorre prima creare l'insieme
dei semafori con \func{semget} e poi inizializzarlo con \func{semctl}, si
inizializzare un semaforo in un'unica chiamata; occorre prima creare l'insieme
dei semafori con \func{semget} e poi inizializzarlo con \func{semctl}, si
Il secondo difetto deriva dalla caratteristica generale degli oggetti del
\textit{SysV IPC} di essere risorse globali di sistema, che non vengono
Il secondo difetto deriva dalla caratteristica generale degli oggetti del
\textit{SysV IPC} di essere risorse globali di sistema, che non vengono
-lasciando un semaforo occupato, che resterà tale fino al successivo riavvio
-del sistema. Come vedremo esistono delle modalità per evitare tutto ciò, ma
+lasciando un semaforo occupato, che resterà tale fino al successivo riavvio
+del sistema. Come vedremo esistono delle modalità per evitare tutto ciò, ma
diventa necessario indicare esplicitamente che si vuole il ripristino del
semaforo all'uscita del processo.
diventa necessario indicare esplicitamente che si vuole il ripristino del
semaforo all'uscita del processo.
riportata in fig.~\ref{fig:ipc_semid_ds}.\footnote{non si sono riportati i
campi ad uso interno del kernel, che vedremo in
fig.~\ref{fig:ipc_sem_schema}, che dipendono dall'implementazione.} Come nel
riportata in fig.~\ref{fig:ipc_semid_ds}.\footnote{non si sono riportati i
campi ad uso interno del kernel, che vedremo in
fig.~\ref{fig:ipc_sem_schema}, che dipendono dall'implementazione.} Come nel
\func{semget} questa struttura viene inizializzata, in particolare il campo
\var{sem\_perm} viene inizializzato come illustrato in
sez.~\ref{sec:ipc_sysv_access_control} (si ricordi che in questo caso il
\func{semget} questa struttura viene inizializzata, in particolare il campo
\var{sem\_perm} viene inizializzato come illustrato in
sez.~\ref{sec:ipc_sysv_access_control} (si ricordi che in questo caso il
quanto riguarda gli altri campi invece:
\begin{itemize*}
\item il campo \var{sem\_nsems}, che esprime il numero di semafori
quanto riguarda gli altri campi invece:
\begin{itemize*}
\item il campo \var{sem\_nsems}, che esprime il numero di semafori
- è riportata la definizione originaria del kernel 1.0, che contiene la prima
- realizzazione del \textit{SysV IPC} in Linux. In realtà questa struttura
- ormai è ridotta ai soli due primi membri, e gli altri vengono calcolati
- dinamicamente. La si è utilizzata a scopo di esempio, perché indica tutti i
+ è riportata la definizione originaria del kernel 1.0, che contiene la prima
+ realizzazione del \textit{SysV IPC} in Linux. In realtà questa struttura
+ ormai è ridotta ai soli due primi membri, e gli altri vengono calcolati
+ dinamicamente. La si è utilizzata a scopo di esempio, perché indica tutti i
- citati dalle pagine di manuale.} è riportata in fig.~\ref{fig:ipc_sem}.
-Questa struttura, non è accessibile in user space, ma i valori in essa
+ citati dalle pagine di manuale.} è riportata in fig.~\ref{fig:ipc_sem}.
+Questa struttura, non è accessibile in user space, ma i valori in essa
direttamente nel file \procfile{/proc/sys/kernel/sem}.
La funzione che permette di effettuare le varie operazioni di controllo sui
direttamente nel file \procfile{/proc/sys/kernel/sem}.
La funzione che permette di effettuare le varie operazioni di controllo sui
-semafori (fra le quali, come accennato, è impropriamente compresa anche la
-loro inizializzazione) è \funcd{semctl}; il suo prototipo è:
+semafori (fra le quali, come accennato, è impropriamente compresa anche la
+loro inizializzazione) è \funcd{semctl}; il suo prototipo è:
\bodydesc{La funzione restituisce in caso di successo un valore positivo
quanto usata con tre argomenti ed un valore nullo quando usata con
\bodydesc{La funzione restituisce in caso di successo un valore positivo
quanto usata con tre argomenti ed un valore nullo quando usata con
- \item[\errcode{EIDRM}] l'insieme di semafori è stato cancellato.
- \item[\errcode{EPERM}] si è richiesto \const{IPC\_SET} o \const{IPC\_RMID}
+ \item[\errcode{EIDRM}] l'insieme di semafori è stato cancellato.
+ \item[\errcode{EPERM}] si è richiesto \const{IPC\_SET} o \const{IPC\_RMID}
- \item[\errcode{ERANGE}] si è richiesto \const{SETALL} \const{SETVAL} ma il
- valore a cui si vuole impostare il semaforo è minore di zero o maggiore
+ \item[\errcode{ERANGE}] si è richiesto \const{SETALL} \const{SETVAL} ma il
+ valore a cui si vuole impostare il semaforo è minore di zero o maggiore
specificata con \param{cmd}, ed opera o sull'intero insieme specificato da
\param{semid} o sul singolo semaforo di un insieme, specificato da
\param{semnum}.
specificata con \param{cmd}, ed opera o sull'intero insieme specificato da
\param{semid} o sul singolo semaforo di un insieme, specificato da
\param{semnum}.
-Qualora la funzione operi con quattro argomenti \param{arg} è un argomento
-generico, che conterrà un dato diverso a seconda dell'azione richiesta; per
+Qualora la funzione operi con quattro argomenti \param{arg} è un argomento
+generico, che conterrà un dato diverso a seconda dell'azione richiesta; per
argomenti con cui deve essere invocata dipendono dal valore dell'argomento
\param{cmd}, che specifica l'azione da intraprendere; i valori validi (che
argomenti con cui deve essere invocata dipendono dal valore dell'argomento
\param{cmd}, che specifica l'azione da intraprendere; i valori validi (che
seguenti:
\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
\item[\const{IPC\_STAT}] Legge i dati dell'insieme di semafori, copiando il
seguenti:
\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
\item[\const{IPC\_STAT}] Legge i dati dell'insieme di semafori, copiando il
Il valore di ritorno della funzione in caso di successo dipende
dall'operazione richiesta; per tutte le operazioni che richiedono quattro
Il valore di ritorno della funzione in caso di successo dipende
dall'operazione richiesta; per tutte le operazioni che richiedono quattro
tab.~\ref{tab:ipc_semctl_returns} viene invece restituito il valore richiesto,
corrispondente al campo della struttura \struct{sem} indicato nella seconda
colonna della tabella.
Le operazioni ordinarie sui semafori, come l'acquisizione o il rilascio degli
stessi (in sostanza tutte quelle non comprese nell'uso di \func{semctl})
tab.~\ref{tab:ipc_semctl_returns} viene invece restituito il valore richiesto,
corrispondente al campo della struttura \struct{sem} indicato nella seconda
colonna della tabella.
Le operazioni ordinarie sui semafori, come l'acquisizione o il rilascio degli
stessi (in sostanza tutte quelle non comprese nell'uso di \func{semctl})
Esegue le operazioni ordinarie su un semaforo o un insieme di semafori.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
Esegue le operazioni ordinarie su un semaforo o un insieme di semafori.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
- \item[\errcode{EIDRM}] l'insieme di semafori è stato cancellato.
- \item[\errcode{ENOMEM}] si è richiesto un \const{SEM\_UNDO} ma il sistema
+ \item[\errcode{EIDRM}] l'insieme di semafori è stato cancellato.
+ \item[\errcode{ENOMEM}] si è richiesto un \const{SEM\_UNDO} ma il sistema
non ha le risorse per allocare la struttura di ripristino.
\item[\errcode{EAGAIN}] un'operazione comporterebbe il blocco del processo,
non ha le risorse per allocare la struttura di ripristino.
\item[\errcode{EAGAIN}] un'operazione comporterebbe il blocco del processo,
\item[\errcode{EINTR}] la funzione, bloccata in attesa dell'esecuzione
dell'operazione, viene interrotta da un segnale.
\item[\errcode{EINTR}] la funzione, bloccata in attesa dell'esecuzione
dell'operazione, viene interrotta da un segnale.
massimo di operazioni \const{SEMOPM}.
\item[\errcode{ERANGE}] per alcune operazioni il valore risultante del
semaforo viene a superare il limite massimo \const{SEMVMX}.
massimo di operazioni \const{SEMOPM}.
\item[\errcode{ERANGE}] per alcune operazioni il valore risultante del
semaforo viene a superare il limite massimo \const{SEMVMX}.
effettuare viene specificato con l'argomento \param{nsop}, mentre il loro
contenuto viene passato con un puntatore ad un vettore di strutture
\struct{sembuf} nell'argomento \param{sops}. Le operazioni richieste vengono
effettuare viene specificato con l'argomento \param{nsop}, mentre il loro
contenuto viene passato con un puntatore ad un vettore di strutture
\struct{sembuf} nell'argomento \param{sops}. Le operazioni richieste vengono
fig.~\ref{fig:ipc_sembuf}) che il programma chiamante deve avere cura di
allocare in un opportuno vettore. La struttura permette di indicare il
semaforo su cui operare, il tipo di operazione, ed un flag di controllo.
fig.~\ref{fig:ipc_sembuf}) che il programma chiamante deve avere cura di
allocare in un opportuno vettore. La struttura permette di indicare il
semaforo su cui operare, il tipo di operazione, ed un flag di controllo.
quale possono essere impostati i due valori \const{IPC\_NOWAIT} e
\const{SEM\_UNDO}. Impostando \const{IPC\_NOWAIT} si fa si che, invece di
bloccarsi (in tutti quei casi in cui l'esecuzione di una operazione richiede
quale possono essere impostati i due valori \const{IPC\_NOWAIT} e
\const{SEM\_UNDO}. Impostando \const{IPC\_NOWAIT} si fa si che, invece di
bloccarsi (in tutti quei casi in cui l'esecuzione di una operazione richiede
si richiede invece che l'operazione venga registrata in modo che il valore del
semaforo possa essere ripristinato all'uscita del processo.
si richiede invece che l'operazione venga registrata in modo che il valore del
semaforo possa essere ripristinato all'uscita del processo.
e determina il comportamento della chiamata a \func{semop}; tre sono i casi
possibili:
\begin{basedescript}{\desclabelwidth{2.0cm}}
e determina il comportamento della chiamata a \func{semop}; tre sono i casi
possibili:
\begin{basedescript}{\desclabelwidth{2.0cm}}
immediatamente (con un errore di \errcode{ERANGE} qualora si sia superato il
limite \const{SEMVMX}) ed il processo non viene bloccato in nessun caso.
Specificando \const{SEM\_UNDO} si aggiorna il contatore per il ripristino
immediatamente (con un errore di \errcode{ERANGE} qualora si sia superato il
limite \const{SEMVMX}) ed il processo non viene bloccato in nessun caso.
Specificando \const{SEM\_UNDO} si aggiorna il contatore per il ripristino
alterazione (scrittura) sull'insieme di semafori.
\item[\var{sem\_op}$=0$] Nel caso \var{semval} sia zero l'esecuzione procede
alterazione (scrittura) sull'insieme di semafori.
\item[\var{sem\_op}$=0$] Nel caso \var{semval} sia zero l'esecuzione procede
- immediatamente. Se \var{semval} è diverso da zero il comportamento è
- controllato da \var{sem\_flg}, se è stato impostato \const{IPC\_NOWAIT} la
+ immediatamente. Se \var{semval} è diverso da zero il comportamento è
+ controllato da \var{sem\_flg}, se è stato impostato \const{IPC\_NOWAIT} la
funzione ritorna con un errore di \errcode{EAGAIN}, altrimenti viene
incrementato \var{semzcnt} di uno ed il processo resta in stato di
\textit{sleep} fintanto che non si ha una delle condizioni seguenti:
funzione ritorna con un errore di \errcode{EAGAIN}, altrimenti viene
incrementato \var{semzcnt} di uno ed il processo resta in stato di
\textit{sleep} fintanto che non si ha una delle condizioni seguenti:
-\item[\var{sem\_op}$<0$] Nel caso in cui \var{semval} è maggiore o uguale del
- valore assoluto di \var{sem\_op} (se cioè la somma dei due valori resta
+\item[\var{sem\_op}$<0$] Nel caso in cui \var{semval} è maggiore o uguale del
+ valore assoluto di \var{sem\_op} (se cioè la somma dei due valori resta
positiva o nulla) i valori vengono sommati e la funzione ritorna
immediatamente; qualora si sia impostato \const{SEM\_UNDO} viene anche
aggiornato il contatore per il ripristino del valore del semaforo. In caso
positiva o nulla) i valori vengono sommati e la funzione ritorna
immediatamente; qualora si sia impostato \const{SEM\_UNDO} viene anche
aggiornato il contatore per il ripristino del valore del semaforo. In caso
- contrario (quando cioè la somma darebbe luogo ad un valore di \var{semval}
- negativo) se si è impostato \const{IPC\_NOWAIT} la funzione ritorna con un
+ contrario (quando cioè la somma darebbe luogo ad un valore di \var{semval}
+ negativo) se si è impostato \const{IPC\_NOWAIT} la funzione ritorna con un
errore di \errcode{EAGAIN}, altrimenti viene incrementato di uno
\var{semncnt} ed il processo resta in stato di \textit{sleep} fintanto che
non si ha una delle condizioni seguenti:
errore di \errcode{EAGAIN}, altrimenti viene incrementato di uno
\var{semncnt} ed il processo resta in stato di \textit{sleep} fintanto che
non si ha una delle condizioni seguenti:
semafori possono restare occupati, abbiamo visto come \func{semop} permetta di
attivare un meccanismo di ripristino attraverso l'uso del flag
semafori possono restare occupati, abbiamo visto come \func{semop} permetta di
attivare un meccanismo di ripristino attraverso l'uso del flag
\struct{sem\_undo}, associata ad ogni processo per ciascun semaforo che esso
ha modificato; all'uscita i semafori modificati vengono ripristinati, e le
strutture disallocate. Per mantenere coerente il comportamento queste
\struct{sem\_undo}, associata ad ogni processo per ciascun semaforo che esso
ha modificato; all'uscita i semafori modificati vengono ripristinati, e le
strutture disallocate. Per mantenere coerente il comportamento queste
avrebbe un doppio ripristino), mentre passano inalterate nell'esecuzione di
una \func{exec} (altrimenti non si avrebbe ripristino).
avrebbe un doppio ripristino), mentre passano inalterate nell'esecuzione di
una \func{exec} (altrimenti non si avrebbe ripristino).
-Tutto questo però ha un problema di fondo. Per capire di cosa si tratta
-occorre fare riferimento all'implementazione usata in Linux, che è riportata
-in maniera semplificata nello schema di fig.~\ref{fig:ipc_sem_schema}. Si è
-presa come riferimento l'architettura usata fino al kernel 2.2.x che è più
+Tutto questo però ha un problema di fondo. Per capire di cosa si tratta
+occorre fare riferimento all'implementazione usata in Linux, che è riportata
+in maniera semplificata nello schema di fig.~\ref{fig:ipc_sem_schema}. Si è
+presa come riferimento l'architettura usata fino al kernel 2.2.x che è più
-struttura del \textit{SysV IPC} è stata modificata, ma le definizioni relative
-a queste strutture restano per compatibilità.\footnote{in particolare con le
+struttura del \textit{SysV IPC} è stata modificata, ma le definizioni relative
+a queste strutture restano per compatibilità.\footnote{in particolare con le
al processo corrente (nel campo \var{sleeper}) poi quest'ultimo viene messo
stato di attesa e viene invocato lo \itindex{scheduler} scheduler per passare
all'esecuzione di un altro processo.
al processo corrente (nel campo \var{sleeper}) poi quest'ultimo viene messo
stato di attesa e viene invocato lo \itindex{scheduler} scheduler per passare
all'esecuzione di un altro processo.
Se invece tutte le operazioni possono avere successo queste vengono eseguite
immediatamente, dopo di che il kernel esegue una scansione della coda di
attesa (a partire da \var{sem\_pending}) per verificare se qualcuna delle
Se invece tutte le operazioni possono avere successo queste vengono eseguite
immediatamente, dopo di che il kernel esegue una scansione della coda di
attesa (a partire da \var{sem\_pending}) per verificare se qualcuna delle
struttura \struct{sem\_queue} viene rimossa e lo stato del processo associato
all'operazione (\var{sleeper}) viene riportato a \textit{running}; il tutto
struttura \struct{sem\_queue} viene rimossa e lo stato del processo associato
all'operazione (\var{sleeper}) viene riportato a \textit{running}; il tutto
per ciascun insieme di semafori una apposita struttura \struct{sem\_undo} che
contiene (nel vettore puntato dal campo \var{semadj}) un valore di
aggiustamento per ogni semaforo cui viene sommato l'opposto del valore usato
per ciascun insieme di semafori una apposita struttura \struct{sem\_undo} che
contiene (nel vettore puntato dal campo \var{semadj}) un valore di
aggiustamento per ogni semaforo cui viene sommato l'opposto del valore usato
Queste strutture sono mantenute in due liste,\footnote{rispettivamente
attraverso i due campi \var{id\_next} e \var{proc\_next}.} una associata
all'insieme di cui fa parte il semaforo, che viene usata per invalidare le
Queste strutture sono mantenute in due liste,\footnote{rispettivamente
attraverso i due campi \var{id\_next} e \var{proc\_next}.} una associata
all'insieme di cui fa parte il semaforo, che viene usata per invalidare le
operazione con \func{semctl}; l'altra associata al processo che ha eseguito
l'operazione;\footnote{attraverso il campo \var{semundo} di
\struct{task\_struct}, come mostrato in \ref{fig:ipc_sem_schema}.} quando un
processo termina, la lista ad esso associata viene scandita e le operazioni
operazione con \func{semctl}; l'altra associata al processo che ha eseguito
l'operazione;\footnote{attraverso il campo \var{semundo} di
\struct{task\_struct}, come mostrato in \ref{fig:ipc_sem_schema}.} quando un
processo termina, la lista ad esso associata viene scandita e le operazioni
ripristino per semafori differenti chiamate attraverso diverse chiamate a
\func{semop}, si pone il problema di come eseguire il ripristino dei semafori
ripristino per semafori differenti chiamate attraverso diverse chiamate a
\func{semop}, si pone il problema di come eseguire il ripristino dei semafori
-Il punto è cosa succede quando una delle operazioni previste per il ripristino
-non può essere eseguita immediatamente perché ad esempio il semaforo è
+Il punto è cosa succede quando una delle operazioni previste per il ripristino
+non può essere eseguita immediatamente perché ad esempio il semaforo è
-\textit{sleep} aspettando la disponibilità del semaforo (come faceva
-l'implementazione originaria) si perde l'atomicità dell'operazione. La scelta
-fatta dal kernel è pertanto quella di effettuare subito le operazioni che non
+\textit{sleep} aspettando la disponibilità del semaforo (come faceva
+l'implementazione originaria) si perde l'atomicità dell'operazione. La scelta
+fatta dal kernel è pertanto quella di effettuare subito le operazioni che non
-con essa dei semplici \textit{mutex} (cioè semafori binari), tutto il codice
-in questione, contenuto nel file \file{Mutex.c} allegato ai sorgenti, è
+con essa dei semplici \textit{mutex} (cioè semafori binari), tutto il codice
+in questione, contenuto nel file \file{Mutex.c} allegato ai sorgenti, è
riportato in fig.~\ref{fig:ipc_mutex_create}. Utilizzeremo l'interfaccia per
creare un insieme contenente un singolo semaforo, per il quale poi useremo un
riportato in fig.~\ref{fig:ipc_mutex_create}. Utilizzeremo l'interfaccia per
creare un insieme contenente un singolo semaforo, per il quale poi useremo un
-valore unitario per segnalare la disponibilità della risorsa, ed un valore
-nullo per segnalarne l'indisponibilità.
+valore unitario per segnalare la disponibilità della risorsa, ed un valore
+nullo per segnalarne l'indisponibilità.
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},
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})
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},
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})
11--13}) si restituisce il valore di ritorno di \func{semctl}, altrimenti
(\texttt{\small 14}) si ritorna l'identificatore del semaforo.
11--13}) si restituisce il valore di ritorno di \func{semctl}, altrimenti
(\texttt{\small 14}) si ritorna l'identificatore del semaforo.
-comprensione del suo funzionamento è immediata in quanto essa è soltanto un
-\textit{wrapper}\footnote{si chiama così una funzione usata per fare da
+comprensione del suo funzionamento è immediata in quanto essa è soltanto un
+\textit{wrapper}\footnote{si chiama così una funzione usata per fare da
\textsl{involucro} alla chiamata di un altra, usata in genere per
semplificare un'interfaccia (come in questo caso) o per utilizzare con la
stessa funzione diversi substrati (librerie, ecc.) che possono fornire le
\textsl{involucro} alla chiamata di un altra, usata in genere per
semplificare un'interfaccia (come in questo caso) o per utilizzare con la
stessa funzione diversi substrati (librerie, ecc.) che possono fornire le
l'identificatore associato alla chiave, il valore di ritorno di quest'ultima
viene passato all'indietro al chiamante.
l'identificatore associato alla chiave, il valore di ritorno di quest'ultima
viene passato all'indietro al chiamante.
dell'opzione \const{SEM\_UNDO} per evitare che il semaforo resti bloccato in
caso di terminazione imprevista del processo.
dell'opzione \const{SEM\_UNDO} per evitare che il semaforo resti bloccato in
caso di terminazione imprevista del processo.
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.
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.
-Chiamare \func{MutexLock} decrementa il valore del semaforo: se questo è
-libero (ha già valore 1) sarà bloccato (valore nullo), se è bloccato la
-chiamata a \func{semop} si bloccherà fintanto che la risorsa non venga
-rilasciata. Chiamando \func{MutexUnlock} il valore del semaforo sarà
+Chiamare \func{MutexLock} decrementa il valore del semaforo: se questo è
+libero (ha già valore 1) sarà bloccato (valore nullo), se è bloccato la
+chiamata a \func{semop} si bloccherà fintanto che la risorsa non venga
+rilasciata. Chiamando \func{MutexUnlock} il valore del semaforo sarà
incrementato di uno, sbloccandolo qualora fosse bloccato.
Si noti che occorre eseguire sempre prima \func{MutexLock} e poi
incrementato di uno, sbloccandolo qualora fosse bloccato.
Si noti che occorre eseguire sempre prima \func{MutexLock} e poi
considerata libera). Infine si tenga presente che usare \func{MutexRead} per
controllare il valore dei mutex prima di proseguire in una operazione di
sblocco non servirebbe comunque, dato che l'operazione non sarebbe atomica.
considerata libera). Infine si tenga presente che usare \func{MutexRead} per
controllare il valore dei mutex prima di proseguire in una operazione di
sblocco non servirebbe comunque, dato che l'operazione non sarebbe atomica.
-Il terzo oggetto introdotto dal \textit{SysV IPC} è quello dei segmenti di
-memoria condivisa. La funzione che permette di ottenerne uno è \funcd{shmget},
-ed il suo prototipo è:
+Il terzo oggetto introdotto dal \textit{SysV IPC} è quello dei segmenti di
+memoria condivisa. La funzione che permette di ottenerne uno è \funcd{shmget},
+ed il suo prototipo è:
Restituisce l'identificatore di una memoria condivisa.
\bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
Restituisce l'identificatore di una memoria condivisa.
\bodydesc{La funzione restituisce l'identificatore (un intero positivo) o -1
di segmenti di memoria nel sistema, o cercato di allocare un segmento le
cui dimensioni fanno superare il limite di sistema (\const{SHMALL}) per
la memoria ad essi riservata.
di segmenti di memoria nel sistema, o cercato di allocare un segmento le
cui dimensioni fanno superare il limite di sistema (\const{SHMALL}) per
la memoria ad essi riservata.
\item[\errcode{ENOMEM}] il sistema non ha abbastanza memoria per poter
contenere le strutture per un nuovo segmento di memoria condivisa.
\end{errlist}
\item[\errcode{ENOMEM}] il sistema non ha abbastanza memoria per poter
contenere le strutture per un nuovo segmento di memoria condivisa.
\end{errlist}
-La funzione, come \func{semget}, è del tutto analoga a \func{msgget}, ed
-identico è l'uso degli argomenti \param{key} e \param{flag} per cui non
+La funzione, come \func{semget}, è del tutto analoga a \func{msgget}, ed
+identico è l'uso degli argomenti \param{key} e \param{flag} per cui non
ripeteremo quanto detto al proposito in sez.~\ref{sec:ipc_sysv_mq}. L'argomento
\param{size} specifica invece la dimensione, in byte, del segmento, che viene
comunque arrotondata al multiplo superiore di \const{PAGE\_SIZE}.
ripeteremo quanto detto al proposito in sez.~\ref{sec:ipc_sysv_mq}. L'argomento
\param{size} specifica invece la dimensione, in byte, del segmento, che viene
comunque arrotondata al multiplo superiore di \const{PAGE\_SIZE}.
-stessa sezione di memoria. Pertanto non è necessaria nessuna operazione di
-copia per trasmettere i dati da un processo all'altro, in quanto ciascuno può
+stessa sezione di memoria. Pertanto non è necessaria nessuna operazione di
+copia per trasmettere i dati da un processo all'altro, in quanto ciascuno può
accedervi direttamente con le normali operazioni di lettura e scrittura dei
dati in memoria.
Ovviamente tutto questo ha un prezzo, ed il problema fondamentale della
accedervi direttamente con le normali operazioni di lettura e scrittura dei
dati in memoria.
Ovviamente tutto questo ha un prezzo, ed il problema fondamentale della
se un processo deve scambiare dei dati con un altro, si deve essere sicuri che
quest'ultimo non acceda al segmento di memoria condivisa prima che il primo
non abbia completato le operazioni di scrittura, inoltre nel corso di una
se un processo deve scambiare dei dati con un altro, si deve essere sicuri che
quest'ultimo non acceda al segmento di memoria condivisa prima che il primo
non abbia completato le operazioni di scrittura, inoltre nel corso di una
\struct{shmid\_ds}, riportata in fig.~\ref{fig:ipc_shmid_ds}. Come nel caso
delle code di messaggi quando si crea un nuovo segmento di memoria condivisa
con \func{shmget} questa struttura viene inizializzata, in particolare il
\struct{shmid\_ds}, riportata in fig.~\ref{fig:ipc_shmid_ds}. Come nel caso
delle code di messaggi quando si crea un nuovo segmento di memoria condivisa
con \func{shmget} questa struttura viene inizializzata, in particolare il
\item il campo \var{shm\_ctime}, che esprime il tempo di creazione del
segmento, viene inizializzato al tempo corrente.
\item i campi \var{shm\_atime} e \var{shm\_dtime}, che esprimono
\item il campo \var{shm\_ctime}, che esprime il tempo di creazione del
segmento, viene inizializzato al tempo corrente.
\item i campi \var{shm\_atime} e \var{shm\_dtime}, che esprimono
agganciato o sganciato da un processo, vengono inizializzati a zero.
\item il campo \var{shm\_lpid}, che esprime il \acr{pid} del processo che ha
eseguito l'ultima operazione, viene inizializzato a zero.
agganciato o sganciato da un processo, vengono inizializzati a zero.
\item il campo \var{shm\_lpid}, che esprime il \acr{pid} del processo che ha
eseguito l'ultima operazione, viene inizializzato a zero.
Esegue le operazioni di controllo su un segmento di memoria condivisa.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
Esegue le operazioni di controllo su un segmento di memoria condivisa.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
- \item[\errcode{EINVAL}] o \param{shmid} non è un identificatore valido o
- \param{cmd} non è un comando valido.
+ \item[\errcode{EINVAL}] o \param{shmid} non è un identificatore valido o
+ \param{cmd} non è un comando valido.
- segmento che è stato cancellato.
- \item[\errcode{EPERM}] si è specificato un comando con \const{IPC\_SET} o
+ segmento che è stato cancellato.
+ \item[\errcode{EPERM}] si è specificato un comando con \const{IPC\_SET} o
- \item[\errcode{EOVERFLOW}] si è tentato il comando \const{IPC\_STAT} ma il
- valore del group-ID o dell'user-ID è troppo grande per essere
+ \item[\errcode{EOVERFLOW}] si è tentato il comando \const{IPC\_STAT} ma il
+ valore del group-ID o dell'user-ID è troppo grande per essere
corrispondente comportamento della funzione, sono i seguenti:
\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
corrispondente comportamento della funzione, sono i seguenti:
\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
condivisa nella struttura \struct{shmid\_ds} puntata da \param{buf}. Occorre
che il processo chiamante abbia il permesso di lettura sulla segmento.
\item[\const{IPC\_RMID}] Marca il segmento di memoria condivisa per la
condivisa nella struttura \struct{shmid\_ds} puntata da \param{buf}. Occorre
che il processo chiamante abbia il permesso di lettura sulla segmento.
\item[\const{IPC\_RMID}] Marca il segmento di memoria condivisa per la
- rimozione, questo verrà cancellato effettivamente solo quando l'ultimo
- processo ad esso agganciato si sarà staccato. Questo comando può essere
+ rimozione, questo verrà cancellato effettivamente solo quando l'ultimo
+ processo ad esso agganciato si sarà staccato. Questo comando può essere
eseguito solo da un processo con user-ID effettivo corrispondente o al
creatore del segmento, o al proprietario del segmento, o all'amministratore.
\item[\const{IPC\_SET}] Permette di modificare i permessi ed il proprietario
eseguito solo da un processo con user-ID effettivo corrispondente o al
creatore del segmento, o al proprietario del segmento, o all'amministratore.
\item[\const{IPC\_SET}] Permette di modificare i permessi ed il proprietario
il creatore del segmento, oppure l'amministratore. Compiuta l'operazione
aggiorna anche il valore del campo \var{shm\_ctime}.
\item[\const{SHM\_LOCK}] Abilita il \itindex{memory~locking} \textit{memory
il creatore del segmento, oppure l'amministratore. Compiuta l'operazione
aggiorna anche il valore del campo \var{shm\_ctime}.
\item[\const{SHM\_LOCK}] Abilita il \itindex{memory~locking} \textit{memory
venga salvata su disco dal meccanismo della \index{memoria~virtuale}
memoria virtuale; si ricordi quanto trattato in
sez.~\ref{sec:proc_mem_lock}.} sul segmento di memoria condivisa. Solo
venga salvata su disco dal meccanismo della \index{memoria~virtuale}
memoria virtuale; si ricordi quanto trattato in
sez.~\ref{sec:proc_mem_lock}.} sul segmento di memoria condivisa. Solo
\item[\const{SHM\_UNLOCK}] Disabilita il \itindex{memory~locking}
\textit{memory locking} sul segmento di memoria condivisa. Solo
\item[\const{SHM\_UNLOCK}] Disabilita il \itindex{memory~locking}
\textit{memory locking} sul segmento di memoria condivisa. Solo
gli insiemi di semafori, gli ultimi due sono delle estensioni specifiche
previste da Linux, che permettono di abilitare e disabilitare il meccanismo
della \index{memoria~virtuale} memoria virtuale per il segmento.
L'argomento \param{buf} viene utilizzato solo con i comandi \const{IPC\_STAT}
gli insiemi di semafori, gli ultimi due sono delle estensioni specifiche
previste da Linux, che permettono di abilitare e disabilitare il meccanismo
della \index{memoria~virtuale} memoria virtuale per il segmento.
L'argomento \param{buf} viene utilizzato solo con i comandi \const{IPC\_STAT}
\struct{shmid\_ds} precedentemente allocata, in cui nel primo caso saranno
scritti i dati del segmento di memoria restituiti dalla funzione e da cui, nel
secondo caso, verranno letti i dati da impostare sul segmento.
\struct{shmid\_ds} precedentemente allocata, in cui nel primo caso saranno
scritti i dati del segmento di memoria restituiti dalla funzione e da cui, nel
secondo caso, verranno letti i dati da impostare sul segmento.
l'interfaccia prevede due funzioni, \funcd{shmat} e \func{shmdt}. La prima di
queste serve ad agganciare un segmento al processo chiamante, in modo che
quest'ultimo possa inserirlo nel suo spazio di indirizzi per potervi accedere;
l'interfaccia prevede due funzioni, \funcd{shmat} e \func{shmdt}. La prima di
queste serve ad agganciare un segmento al processo chiamante, in modo che
quest'ultimo possa inserirlo nel suo spazio di indirizzi per potervi accedere;
Aggancia al processo un segmento di memoria condivisa.
\bodydesc{La funzione restituisce l'indirizzo del segmento in caso di
Aggancia al processo un segmento di memoria condivisa.
\bodydesc{La funzione restituisce l'indirizzo del segmento in caso di
- segmento nella modalità richiesta.
- \item[\errcode{EINVAL}] si è specificato un identificatore invalido per
+ segmento nella modalità richiesta.
+ \item[\errcode{EINVAL}] si è specificato un identificatore invalido per
La funzione inserisce un segmento di memoria condivisa all'interno dello
spazio di indirizzi del processo, in modo che questo possa accedervi
La funzione inserisce un segmento di memoria condivisa all'interno dello
spazio di indirizzi del processo, in modo che questo possa accedervi
fig.~\ref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si
ricordi quanto illustrato al proposito in sez.~\ref{sec:proc_mem_layout}). In
particolare l'indirizzo finale del segmento dati (quello impostato da
\func{brk}, vedi sez.~\ref{sec:proc_mem_alloc}) non viene influenzato.
fig.~\ref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si
ricordi quanto illustrato al proposito in sez.~\ref{sec:proc_mem_layout}). In
particolare l'indirizzo finale del segmento dati (quello impostato da
\func{brk}, vedi sez.~\ref{sec:proc_mem_alloc}) non viene influenzato.
agganciato un segmento di memoria condivisa.}
\label{fig:ipc_shmem_layout}
\end{figure}
L'argomento \param{shmaddr} specifica a quale indirizzo\footnote{lo standard
agganciato un segmento di memoria condivisa.}
\label{fig:ipc_shmem_layout}
\end{figure}
L'argomento \param{shmaddr} specifica a quale indirizzo\footnote{lo standard
- SVID prevede che l'argomento \param{shmaddr} sia di tipo \ctyp{char *}, così
- come il valore di ritorno della funzione; in Linux è stato così con le
+ SVID prevede che l'argomento \param{shmaddr} sia di tipo \ctyp{char *}, così
+ come il valore di ritorno della funzione; in Linux è stato così con le
-specificato è \val{NULL} è il sistema a scegliere opportunamente un'area di
-memoria libera (questo è il modo più portabile e sicuro di usare la funzione).
+specificato è \val{NULL} è il sistema a scegliere opportunamente un'area di
+memoria libera (questo è il modo più portabile e sicuro di usare la funzione).
-\param{shmaddr}; questo però può avvenire solo se l'indirizzo coincide con il
-limite di una pagina, cioè se è un multiplo esatto del parametro di sistema
-\const{SHMLBA}, che in Linux è sempre uguale \const{PAGE\_SIZE}.
+\param{shmaddr}; questo però può avvenire solo se l'indirizzo coincide con il
+limite di una pagina, cioè se è un multiplo esatto del parametro di sistema
+\const{SHMLBA}, che in Linux è sempre uguale \const{PAGE\_SIZE}.
-Si tenga presente però che quando si usa \val{NULL} come valore di
-\param{shmaddr}, l'indirizzo restituito da \func{shmat} può cambiare da
+Si tenga presente però che quando si usa \val{NULL} come valore di
+\param{shmaddr}, l'indirizzo restituito da \func{shmat} può cambiare da
processo a processo; pertanto se nell'area di memoria condivisa si salvano
anche degli indirizzi, si deve avere cura di usare valori relativi (in genere
riferiti all'indirizzo di partenza del segmento).
processo a processo; pertanto se nell'area di memoria condivisa si salvano
anche degli indirizzi, si deve avere cura di usare valori relativi (in genere
riferiti all'indirizzo di partenza del segmento).
solo due e sono identificati dalle costanti \const{SHM\_RND} e
\const{SHM\_RDONLY}, che vanno combinate con un OR aritmetico. Specificando
\const{SHM\_RND} si evita che \func{shmat} ritorni un errore quando
solo due e sono identificati dalle costanti \const{SHM\_RND} e
\const{SHM\_RDONLY}, che vanno combinate con un OR aritmetico. Specificando
\const{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
+\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
L'uso di \const{SHM\_RDONLY} permette di agganciare il segmento in sola
lettura (si ricordi che anche le pagine di memoria hanno dei permessi), in tal
L'uso di \const{SHM\_RDONLY} permette di agganciare il segmento in sola
lettura (si ricordi che anche le pagine di memoria hanno dei permessi), in tal
di agganciare un segmento in sola scrittura.
In caso di successo la funzione aggiorna anche i seguenti campi di
di agganciare un segmento in sola scrittura.
In caso di successo la funzione aggiorna anche i seguenti campi di
Sgancia dal processo un segmento di memoria condivisa.
\bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
Sgancia dal processo un segmento di memoria condivisa.
\bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
Come esempio di uso di queste funzioni vediamo come implementare una serie di
funzioni di libreria che ne semplifichino l'uso, automatizzando le operazioni
Come esempio di uso di queste funzioni vediamo come implementare una serie di
funzioni di libreria che ne semplifichino l'uso, automatizzando le operazioni
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
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
segmento al valore costante specificato dall'argomento \var{fill}, e poi si
ritorna il puntatore al segmento stesso.
segmento al valore costante specificato dall'argomento \var{fill}, e poi si
ritorna il puntatore al segmento stesso.
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
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
puntatore nullo in caso di errore, se invece non ci sono errori si restituisce
il puntatore ottenuto da \func{shmat}.
puntatore nullo in caso di errore, se invece non ci sono errori si restituisce
il puntatore ottenuto da \func{shmat}.
la chiamata a \func{shmdt} per sganciare il segmento, restituendo
(\texttt{\small 38--39}) un valore -1 in caso di errore. Il passo successivo
la chiamata a \func{shmdt} per sganciare il segmento, restituendo
(\texttt{\small 38--39}) un valore -1 in caso di errore. Il passo successivo
associato al segmento data la chiave \var{key}. Al solito si restituisce un
valore di -1 (\texttt{\small 42--45}) in caso di errore, mentre se tutto va
bene si conclude restituendo un valore nullo.
associato al segmento data la chiave \var{key}. Al solito si restituisce un
valore di -1 (\texttt{\small 42--45}) in caso di errore, mentre se tutto va
bene si conclude restituendo un valore nullo.
-Benché la memoria condivisa costituisca il meccanismo di intercomunicazione
-fra processi più veloce, essa non è sempre il più appropriato, dato che, come
-abbiamo visto, si avrà comunque la necessità di una sincronizzazione degli
-accessi. Per questo motivo, quando la comunicazione fra processi è
+Benché la memoria condivisa costituisca il meccanismo di intercomunicazione
+fra processi più veloce, essa non è sempre il più appropriato, dato che, come
+abbiamo visto, si avrà comunque la necessità di una sincronizzazione degli
+accessi. Per questo motivo, quando la comunicazione fra processi è
sequenziale, altri meccanismi come le pipe, le fifo o i socket, che non
necessitano di sincronizzazione esplicita, sono da preferire. Essa diventa
sequenziale, altri meccanismi come le pipe, le fifo o i socket, che non
necessitano di sincronizzazione esplicita, sono da preferire. Essa diventa
sequenziale\footnote{come accennato in sez.~\ref{sec:ipc_sysv_mq} per la
comunicazione non sequenziale si possono usare le code di messaggi,
sequenziale\footnote{come accennato in sez.~\ref{sec:ipc_sysv_mq} per la
comunicazione non sequenziale si possono usare le code di messaggi,
- attraverso l'uso del campo \var{mtype}, ma solo se quest'ultima può essere
- effettuata in forma di messaggio.} o quando non può avvenire secondo una
-modalità predefinita.
+ attraverso l'uso del campo \var{mtype}, ma solo se quest'ultima può essere
+ effettuata in forma di messaggio.} o quando non può avvenire secondo una
+modalità predefinita.
``\textit{monitor}'', in cui viene per scambiare informazioni fra un processo
server, che vi scrive dei dati di interesse generale che ha ottenuto, e i
``\textit{monitor}'', in cui viene per scambiare informazioni fra un processo
server, che vi scrive dei dati di interesse generale che ha ottenuto, e i
maniera completamente asincrona. Con questo schema di funzionamento da una
parte si evita che ciascun processo client debba compiere l'operazione,
potenzialmente onerosa, di ricavare e trattare i dati, e dall'altra si evita
maniera completamente asincrona. Con questo schema di funzionamento da una
parte si evita che ciascun processo client debba compiere l'operazione,
potenzialmente onerosa, di ricavare e trattare i dati, e dall'altra si evita
una directory (il numero dei file contenuti, la dimensione totale, quante
directory, link simbolici, file normali, ecc.) che saranno salvati in un
segmento di memoria condivisa cui altri processi potranno accedere per
ricavare la parte di informazione che interessa.
una directory (il numero dei file contenuti, la dimensione totale, quante
directory, link simbolici, file normali, ecc.) che saranno salvati in un
segmento di memoria condivisa cui altri processi potranno accedere per
ricavare la parte di informazione che interessa.
corpo del programma server, insieme alle definizioni delle altre funzioni
usate nel programma e delle variabili globali, omettendo tutto quello che
riguarda la gestione delle opzioni e la stampa delle istruzioni di uso a
corpo del programma server, insieme alle definizioni delle altre funzioni
usate nel programma e delle variabili globali, omettendo tutto quello che
riguarda la gestione delle opzioni e la stampa delle istruzioni di uso a
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
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
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.
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.
immediatamente in caso di errore. Questa funzione serve anche per impostare
la directory di lavoro del programma nella directory da tenere sotto
controllo, in vista del successivo uso della funzione
immediatamente in caso di errore. Questa funzione serve anche per impostare
la directory di lavoro del programma nella directory da tenere sotto
controllo, in vista del successivo uso della funzione
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
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
programma che deve essere eseguito come server, sono il solo strumento
disponibile per concluderne l'esecuzione.
programma che deve essere eseguito come server, sono il solo strumento
disponibile per concluderne l'esecuzione.
usato un riferimento relativo alla home dell'utente, supposto che i sorgenti
di GaPiL siano stati installati direttamente in essa. Qualora si effettui
usato un riferimento relativo alla home dell'utente, supposto che i sorgenti
di GaPiL siano stati installati direttamente in essa. Qualora si effettui
richiede (\texttt{\small 31}) la creazione di un segmento di memoria condivisa
con usando la funzione \func{ShmCreate} illustrata in precedenza (una pagina
richiede (\texttt{\small 31}) la creazione di un segmento di memoria condivisa
con usando la funzione \func{ShmCreate} illustrata in precedenza (una pagina
accedere alla memoria condivisa, che, per come abbiamo lo abbiamo definito,
accedere alla memoria condivisa, che, per come abbiamo lo abbiamo definito,
Completata l'inizializzazione e la creazione degli oggetti di
intercomunicazione il programma entra nel ciclo principale (\texttt{\small
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.
-Il primo passo (\texttt{\small 41}) è eseguire \func{daemon} per proseguire
+ 40--49}) dove vengono eseguite indefinitamente le attività di monitoraggio.
+Il primo passo (\texttt{\small 41}) è eseguire \func{daemon} per proseguire
-noti che si è mantenuta, usando un valore non nullo del primo argomento, la
-directory di lavoro corrente. Una volta che il programma è andato in
+noti che si è mantenuta, usando un valore non nullo del primo argomento, la
+directory di lavoro corrente. Una volta che il programma è andato in
background l'esecuzione prosegue (\texttt{\small 42--48}) all'interno di un
ciclo infinito: si inizia (\texttt{\small 43}) bloccando il mutex con
\func{MutexLock} per poter accedere alla memoria condivisa (la funzione si
background l'esecuzione prosegue (\texttt{\small 42--48}) all'interno di un
ciclo infinito: si inizia (\texttt{\small 43}) bloccando il mutex con
\func{MutexLock} per poter accedere alla memoria condivisa (la funzione si
44}) si cancellano i valori precedentemente immagazzinati nella memoria
condivisa con \func{memset}, e si esegue (\texttt{\small 45}) un nuovo calcolo
degli stessi utilizzando la funzione \func{DirScan}; infine (\texttt{\small
44}) si cancellano i valori precedentemente immagazzinati nella memoria
condivisa con \func{memset}, e si esegue (\texttt{\small 45}) un nuovo calcolo
degli stessi utilizzando la funzione \func{DirScan}; infine (\texttt{\small
l'opzione \code{-p} con una \func{sleep}.
Si noti come per il calcolo dei valori da mantenere nella memoria condivisa si
l'opzione \code{-p} con una \func{sleep}.
Si noti come per il calcolo dei valori da mantenere nella memoria condivisa si
descritta in dettaglio) in sez.~\ref{sec:file_dir_read}, che ci permette di
effettuare la scansione delle voci della directory, chiamando per ciascuna di
esse la funzione \func{ComputeValues}, che esegue tutti i calcoli necessari.
descritta in dettaglio) in sez.~\ref{sec:file_dir_read}, che ci permette di
effettuare la scansione delle voci della directory, chiamando per ciascuna di
esse la funzione \func{ComputeValues}, che esegue tutti i calcoli necessari.
-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
+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
ciascuna voce, per ottenerne i dati, che poi utilizza per incrementare i vari
contatori nella memoria condivisa, cui accede grazie alla variabile globale
\var{shmptr}.
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 variabile globale
\var{shmptr}.
-Dato che la funzione è chiamata da \func{DirScan}, 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
+Dato che la funzione è chiamata da \func{DirScan}, 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
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
ne sono per ciascun tipo.
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
ne sono per ciascun tipo.
(\texttt{\small 17--23}) del gestore dei segnali di terminazione, usato per
chiudere il programma. Esso, oltre a provocare l'uscita del programma, si
(\texttt{\small 17--23}) del gestore dei segnali di terminazione, usato per
chiudere il programma. Esso, oltre a provocare l'uscita del programma, si
necessari. Per questo anzitutto (\texttt{\small 19}) acquisisce il mutex con
\func{MutexLock}, per evitare di operare mentre un client sta ancora leggendo
i dati, dopo di che (\texttt{\small 20}) distacca e rimuove il segmento di
necessari. Per questo anzitutto (\texttt{\small 19}) acquisisce il mutex con
\func{MutexLock}, per evitare di operare mentre un client sta ancora leggendo
i dati, dopo di che (\texttt{\small 20}) distacca e rimuove il segmento di
directory, \file{ReadMonitor.c}.}
\label{fig:ipc_dirmonitor_client}
\end{figure}
Il codice del client usato per leggere le informazioni mantenute nella memoria
directory, \file{ReadMonitor.c}.}
\label{fig:ipc_dirmonitor_client}
\end{figure}
Il codice del client usato per leggere le informazioni mantenute nella memoria
di intercomunicazione necessari viene eseguito il corpo principale del
programma (\texttt{\small 21--33}); si comincia (\texttt{\small 22})
acquisendo il mutex con \func{MutexLock}; qui avviene il blocco del processo
di intercomunicazione necessari viene eseguito il corpo principale del
programma (\texttt{\small 21--33}); si comincia (\texttt{\small 22})
acquisendo il mutex con \func{MutexLock}; qui avviene il blocco del processo
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.
Verifichiamo allora il funzionamento dei nostri programmi; al solito, usando
le funzioni di libreria occorre definire opportunamente
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.
Verifichiamo allora il funzionamento dei nostri programmi; al solito, usando
le funzioni di libreria occorre definire opportunamente
-ed avendo usato \func{daemon} il comando ritornerà immediatamente. Una volta
-che il server è in esecuzione, possiamo passare ad invocare il client per
+ed avendo usato \func{daemon} il comando ritornerà immediatamente. Una volta
+che il server è in esecuzione, possiamo passare ad invocare il client per
verificarne i risultati, in tal caso otterremo:
\begin{Verbatim}
[piccardi@gont sources]$ ./readmon
verificarne i risultati, in tal caso otterremo:
\begin{Verbatim}
[piccardi@gont sources]$ ./readmon
\cmd{ipcs} ci permette inoltre di verificare la presenza di un segmento di
memoria condivisa e di un semaforo:
\begin{Verbatim}
\cmd{ipcs} ci permette inoltre di verificare la presenza di un segmento di
memoria condivisa e di un semaforo:
\begin{Verbatim}
%% Per capire meglio il funzionamento delle funzioni facciamo ancora una volta
%% riferimento alle strutture con cui il kernel implementa i segmenti di memoria
%% Per capire meglio il funzionamento delle funzioni facciamo ancora una volta
%% riferimento alle strutture con cui il kernel implementa i segmenti di memoria
descrizione dei singoli oggetti che ne fan parte, il \textit{SysV IPC}
presenta numerosi problemi; in \cite{APUE}\footnote{in particolare nel
capitolo 14.} Stevens ne effettua una accurata analisi (alcuni dei concetti
descrizione dei singoli oggetti che ne fan parte, il \textit{SysV IPC}
presenta numerosi problemi; in \cite{APUE}\footnote{in particolare nel
capitolo 14.} Stevens ne effettua una accurata analisi (alcuni dei concetti
Le code di messaggi sono probabilmente il meno usato degli oggetti del
\textit{SysV IPC}; esse infatti nacquero principalmente come meccanismo di
comunicazione bidirezionale quando ancora le pipe erano unidirezionali; con la
Le code di messaggi sono probabilmente il meno usato degli oggetti del
\textit{SysV IPC}; esse infatti nacquero principalmente come meccanismo di
comunicazione bidirezionale quando ancora le pipe erano unidirezionali; con la
-disponibilità di \func{socketpair} (vedi sez.~\ref{sec:ipc_socketpair}) o
-utilizzando una coppia di pipe, si può ottenere questo risultato senza
+disponibilità di \func{socketpair} (vedi sez.~\ref{sec:ipc_socketpair}) o
+utilizzando una coppia di pipe, si può ottenere questo risultato senza
hanno delle caratteristiche ulteriori, consentendo una classificazione dei
messaggi ed un accesso non rigidamente sequenziale; due caratteristiche che
sono impossibili da ottenere con le pipe e i socket di \func{socketpair}. A
hanno delle caratteristiche ulteriori, consentendo una classificazione dei
messaggi ed un accesso non rigidamente sequenziale; due caratteristiche che
sono impossibili da ottenere con le pipe e i socket di \func{socketpair}. A
presentano una interfaccia inutilmente complessa e con alcuni difetti
strutturali, per questo quando si ha una semplice esigenza di sincronizzazione
per la quale basterebbe un semaforo binario (quello che abbiamo definito come
presentano una interfaccia inutilmente complessa e con alcuni difetti
strutturali, per questo quando si ha una semplice esigenza di sincronizzazione
per la quale basterebbe un semaforo binario (quello che abbiamo definito come
-\textit{mutex}), per indicare la disponibilità o meno di una risorsa, senza la
-necessità di un contatore come i semafori, si possono utilizzare metodi
+\textit{mutex}), per indicare la disponibilità o meno di una risorsa, senza la
+necessità di un contatore come i semafori, si possono utilizzare metodi
dei \textsl{file di lock} (per i quali esiste anche una opportuna directory,
\file{/var/lock}, nel filesystem standard). Per questo si usa la
caratteristica della funzione \func{open} (illustrata in
dei \textsl{file di lock} (per i quali esiste anche una opportuna directory,
\file{/var/lock}, nel filesystem standard). Per questo si usa la
caratteristica della funzione \func{open} (illustrata in
-sez.~\ref{sec:file_open}) che prevede\footnote{questo è quanto dettato dallo
- standard POSIX.1, ciò non toglie che in alcune implementazioni questa
+sez.~\ref{sec:file_open}) che prevede\footnote{questo è quanto dettato dallo
+ standard POSIX.1, ciò non toglie che in alcune implementazioni questa
\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
\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
+\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
\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
\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
-Uno dei limiti di questa tecnica è che, come abbiamo già accennato in
-sez.~\ref{sec:file_open}, questo comportamento di \func{open} può non
-funzionare (la funzione viene eseguita, ma non è garantita l'atomicità
-dell'operazione) se il filesystem su cui si va ad operare è su NFS; in tal
-caso si può adottare una tecnica alternativa che prevede l'uso della
+Uno dei limiti di questa tecnica è che, come abbiamo già accennato in
+sez.~\ref{sec:file_open}, questo comportamento di \func{open} può non
+funzionare (la funzione viene eseguita, ma non è garantita l'atomicità
+dell'operazione) se il filesystem su cui si va ad operare è su NFS; in tal
+caso si può adottare una tecnica alternativa che prevede l'uso della
-esistente; se il link esiste già e la funzione fallisce, significa che la
-risorsa è bloccata e potrà essere sbloccata solo con un \func{unlink},
-altrimenti il link è creato ed il lock acquisito; il controllo e l'eventuale
+esistente; se il link esiste già e la funzione fallisce, significa che la
+risorsa è bloccata e potrà essere sbloccata solo con un \func{unlink},
+altrimenti il link è creato ed il lock acquisito; il controllo e l'eventuale
stesso filesystem.
In generale comunque l'uso di un \textsl{file di lock} presenta parecchi
problemi che non lo rendono una alternativa praticabile per la
sincronizzazione: anzitutto in caso di terminazione imprevista del processo,
si lascia allocata la risorsa (il \textsl{file di lock}) e questa deve essere
stesso filesystem.
In generale comunque l'uso di un \textsl{file di lock} presenta parecchi
problemi che non lo rendono una alternativa praticabile per la
sincronizzazione: anzitutto in caso di terminazione imprevista del processo,
si lascia allocata la risorsa (il \textsl{file di lock}) e questa deve essere
-sempre cancellata esplicitamente. Inoltre il controllo della disponibilità
-può essere eseguito solo con una tecnica di \itindex{polling}
-\textit{polling}, ed è quindi molto inefficiente.
+sempre cancellata esplicitamente. Inoltre il controllo della disponibilità
+può essere eseguito solo con una tecnica di \itindex{polling}
+\textit{polling}, ed è quindi molto inefficiente.
-La tecnica dei file di lock ha comunque una sua utilità, e può essere usata
-con successo quando l'esigenza è solo quella di segnalare l'occupazione di una
-risorsa, senza necessità di attendere che questa si liberi; ad esempio la si
+La tecnica dei file di lock ha comunque una sua utilità, e può essere usata
+con successo quando l'esigenza è solo quella di segnalare l'occupazione di una
+risorsa, senza necessità di attendere che questa si liberi; ad esempio la si
-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.
+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.
-illustrati in precedenza, la tecnica alternativa di sincronizzazione più
-comune è quella di fare ricorso al \index{file!locking} \textit{file locking}
+illustrati in precedenza, la tecnica alternativa di sincronizzazione più
+comune è quella di fare ricorso al \index{file!locking} \textit{file locking}
(trattato in sez.~\ref{sec:file_locking}) usando \func{fcntl} su un file
creato per l'occasione per ottenere un write lock. In questo modo potremo
(trattato in sez.~\ref{sec:file_locking}) usando \func{fcntl} su un file
creato per l'occasione per ottenere un write lock. In questo modo potremo
-usare il lock come un \textit{mutex}: per bloccare la risorsa basterà
-acquisire il lock, per sbloccarla basterà rilasciare il lock. Una richiesta
-fatta con un write lock metterà automaticamente il processo in stato di
-attesa, senza necessità di ricorrere al \itindex{polling} \textit{polling} per
-determinare la disponibilità della risorsa, e al rilascio della stessa da
-parte del processo che la occupava si otterrà il nuovo lock atomicamente.
+usare il lock come un \textit{mutex}: per bloccare la risorsa basterà
+acquisire il lock, per sbloccarla basterà rilasciare il lock. Una richiesta
+fatta con un write lock metterà automaticamente il processo in stato di
+attesa, senza necessità di ricorrere al \itindex{polling} \textit{polling} per
+determinare la disponibilità della risorsa, e al rilascio della stessa da
+parte del processo che la occupava si otterrà il nuovo lock atomicamente.
Questo approccio presenta il notevole vantaggio che alla terminazione di un
processo tutti i lock acquisiti vengono rilasciati automaticamente (alla
chiusura dei relativi file) e non ci si deve preoccupare di niente; inoltre
Questo approccio presenta il notevole vantaggio che alla terminazione di un
processo tutti i lock acquisiti vengono rilasciati automaticamente (alla
chiusura dei relativi file) e non ci si deve preoccupare di niente; inoltre
-non consuma risorse permanentemente allocate nel sistema. Lo svantaggio è che,
-dovendo fare ricorso a delle operazioni sul filesystem, esso è in genere
-leggermente più lento.
+non consuma risorse permanentemente allocate nel sistema. Lo svantaggio è che,
+dovendo fare ricorso a delle operazioni sul filesystem, esso è in genere
+leggermente più lento.
-\textit{file locking} \index{file!locking} è riportato in
-fig.~\ref{fig:ipc_flock_mutex}; si è mantenuta volutamente una struttura
+\textit{file locking} \index{file!locking} è riportato in
+fig.~\ref{fig:ipc_flock_mutex}; si è mantenuta volutamente una struttura
analoga alle precedenti funzioni che usano i semafori, anche se le due
interfacce non possono essere completamente equivalenti, specie per quanto
riguarda la rimozione del mutex.
analoga alle precedenti funzioni che usano i semafori, anche se le due
interfacce non possono essere completamente equivalenti, specie per quanto
riguarda la rimozione del mutex.
-La prima funzione (\texttt{\small 1--5}) è \func{CreateMutex}, e serve a
-creare il mutex; la funzione è estremamente semplice, e si limita
+La prima funzione (\texttt{\small 1--5}) è \func{CreateMutex}, e serve a
+creare il mutex; la funzione è estremamente semplice, e si limita
-file che sarà usato per il successivo \textit{file locking}, assicurandosi che
-non esista già (nel qual caso segnala un errore); poi restituisce il file
-descriptor che sarà usato dalle altre funzioni per acquisire e rilasciare il
+file che sarà usato per il successivo \textit{file locking}, assicurandosi che
+non esista già (nel qual caso segnala un errore); poi restituisce il file
+descriptor che sarà usato dalle altre funzioni per acquisire e rilasciare il
-La seconda funzione (\texttt{\small 6--10}) è \func{FindMutex}, che, come la
-precedente, è stata definita per mantenere una analogia con la corrispondente
+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 \index{file!locking} \textit{file locking},
solo che in questo caso le opzioni di \func{open} sono tali che il file in
funzione basata sui semafori. Anch'essa si limita (\texttt{\small 9}) ad
aprire il file da usare per il \index{file!locking} \textit{file locking},
solo che in questo caso le opzioni di \func{open} sono tali che il file in
acquisire il mutex. La funzione definisce (\texttt{\small 14}) e inizializza
(\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
acquisire il mutex. La funzione definisce (\texttt{\small 14}) e inizializza
(\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
-La quarta funzione (\texttt{\small 24--34}) è \func{UnlockMutex} e serve a
-rilasciare il mutex. La funzione è analoga alla precedente, solo che in questo
+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
rilascio del lock, che viene effettuato (\texttt{\small 33}) con la opportuna
chiamata a \func{fcntl}. Avendo usato il \index{file!locking} \textit{file
locking} in semantica POSIX (si riveda quanto detto
sez.~\ref{sec:file_posix_lock}) solo il processo che ha precedentemente
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 \index{file!locking} \textit{file
locking} in semantica POSIX (si riveda quanto detto
sez.~\ref{sec:file_posix_lock}) solo il processo che ha precedentemente
-La quinta funzione (\texttt{\small 36--39}) è \func{RemoveMutex} e serve a
-cancellare il mutex. Anche questa funzione è stata definita per mantenere una
+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
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
chiamate a \func{FindMutex} o \func{CreateMutex}, che continueranno ad essere
disponibili fintanto che i relativi file descriptor restano aperti. Pertanto
chiamate a \func{FindMutex} o \func{CreateMutex}, che continueranno ad essere
disponibili fintanto che i relativi file descriptor restano aperti. Pertanto
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
(\texttt{\small 52}) il valore di ritorno in caso di errore, ed il valore del
campo \var{l\_type} (che descrive lo stato del lock) altrimenti
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
(\texttt{\small 52}) il valore di ritorno in caso di errore, ed il valore del
campo \var{l\_type} (che descrive lo stato del lock) altrimenti
errore e uno dei due valori \const{F\_UNLCK} o \const{F\_WRLCK}\footnote{non
si dovrebbe mai avere il terzo valore possibile, \const{F\_RDLCK}, dato che
errore e uno dei due valori \const{F\_UNLCK} o \const{F\_WRLCK}\footnote{non
si dovrebbe mai avere il terzo valore possibile, \const{F\_RDLCK}, dato che
siano richiesti altri lock sul file al di fuori dell'interfaccia, nel qual
caso si potranno avere, ovviamente, interferenze indesiderate.} in caso di
siano richiesti altri lock sul file al di fuori dell'interfaccia, nel qual
caso si potranno avere, ovviamente, interferenze indesiderate.} in caso di
-successo, ad indicare che il mutex è, rispettivamente, libero o occupato.
+successo, ad indicare che il mutex è, rispettivamente, libero o occupato.
Basandosi sulla semantica dei file lock POSIX valgono tutte le considerazioni
relative al comportamento di questi ultimi fatte in
sez.~\ref{sec:file_posix_lock}; questo significa ad esempio che, al contrario
di quanto avveniva con l'interfaccia basata sui semafori, chiamate multiple a
Basandosi sulla semantica dei file lock POSIX valgono tutte le considerazioni
relative al comportamento di questi ultimi fatte in
sez.~\ref{sec:file_posix_lock}; questo significa ad esempio che, al contrario
di quanto avveniva con l'interfaccia basata sui semafori, chiamate multiple a
-Abbiamo già visto che quando i processi sono \textsl{correlati}\footnote{se
- cioè hanno almeno un progenitore comune.} l'uso delle pipe può costituire
-una valida alternativa alle code di messaggi; nella stessa situazione si può
+Abbiamo già visto che quando i processi sono \textsl{correlati}\footnote{se
+ cioè hanno almeno un progenitore comune.} l'uso delle pipe può costituire
+una valida alternativa alle code di messaggi; nella stessa situazione si può
evitare l'uso di una memoria condivisa facendo ricorso al cosiddetto
\textit{memory mapping} anonimo.
evitare l'uso di una memoria condivisa facendo ricorso al cosiddetto
\textit{memory mapping} anonimo.
contenuto di un file nella memoria di un processo, e che, quando viene usato
il flag \const{MAP\_SHARED}, le modifiche effettuate al contenuto del file
vengono viste da tutti i processi che lo hanno mappato. Utilizzare questa
contenuto di un file nella memoria di un processo, e che, quando viene usato
il flag \const{MAP\_SHARED}, le modifiche effettuate al contenuto del file
vengono viste da tutti i processi che lo hanno mappato. Utilizzare questa
-tecnica per creare una memoria condivisa fra processi diversi è estremamente
-inefficiente, in quanto occorre passare attraverso il disco. Però abbiamo
+tecnica per creare una memoria condivisa fra processi diversi è estremamente
+inefficiente, in quanto occorre passare attraverso il disco. Però abbiamo
visto anche che se si esegue la mappatura con il flag \const{MAP\_ANONYMOUS}
la regione mappata non viene associata a nessun file, anche se quanto scritto
visto anche che se si esegue la mappatura con il flag \const{MAP\_ANONYMOUS}
la regione mappata non viene associata a nessun file, anche se quanto scritto
-rimane in memoria e può essere riletto; allora, dato che un processo figlio
-mantiene nel suo spazio degli indirizzi anche le regioni mappate, esso sarà
-anche in grado di accedere a quanto in esse è contenuto.
+rimane in memoria e può essere riletto; allora, dato che un processo figlio
+mantiene nel suo spazio degli indirizzi anche le regioni mappate, esso sarà
+anche in grado di accedere a quanto in esse è contenuto.
\file{/dev/zero}. In tal caso i valori scritti nella regione mappata non
vengono ignorati (come accade qualora si scriva direttamente sul file), ma
\file{/dev/zero}. In tal caso i valori scritti nella regione mappata non
vengono ignorati (come accade qualora si scriva direttamente sul file), ma
\label{sec:ipc_posix_generic}
Oggi Linux supporta tutti gli oggetti definito nello standard POSIX per l'IPC,
\label{sec:ipc_posix_generic}
Oggi Linux supporta tutti gli oggetti definito nello standard POSIX per l'IPC,
kernel 2.4.x, i semafori sono forniti dalle \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.
kernel 2.4.x, i semafori sono forniti dalle \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.
degli identificatori e delle chiavi visti nel SysV IPC, per passare ai
\itindex{POSIX~IPC~names} \textit{POSIX IPC names}, che sono sostanzialmente
equivalenti ai nomi dei file. Tutte le funzioni che creano un oggetto di IPC
POSIX prendono come primo argomento una stringa che indica uno di questi nomi;
degli identificatori e delle chiavi visti nel SysV IPC, per passare ai
\itindex{POSIX~IPC~names} \textit{POSIX IPC names}, che sono sostanzialmente
equivalenti ai nomi dei file. Tutte le funzioni che creano un oggetto di IPC
POSIX prendono come primo argomento una stringa che indica uno di questi nomi;
-lo standard è molto generico riguardo l'implementazione, ed i nomi stessi
-possono avere o meno una corrispondenza sul filesystem; tutto quello che è
-richiesto è che:
+lo standard è molto generico riguardo l'implementazione, ed i nomi stessi
+possono avere o meno una corrispondenza sul filesystem; tutto quello che è
+richiesto è che:
\const{PATH\_MAX} byte e terminati da un carattere nullo.
\item se il nome inizia per una \texttt{/} chiamate differenti allo stesso
nome fanno riferimento allo stesso oggetto, altrimenti l'interpretazione del
\const{PATH\_MAX} byte e terminati da un carattere nullo.
\item se il nome inizia per una \texttt{/} chiamate differenti allo stesso
nome fanno riferimento allo stesso oggetto, altrimenti l'interpretazione del
-Data la assoluta genericità delle specifiche, il comportamento delle funzioni
-è subordinato in maniera quasi completa alla relativa
+Data la assoluta genericità delle specifiche, il comportamento delle funzioni
+è subordinato in maniera quasi completa alla relativa
implementazione.\footnote{tanto che Stevens in \cite{UNP2} cita questo caso
come un esempio della maniera standard usata dallo standard POSIX per
consentire implementazioni non standardizzabili.} Nel caso di Linux, sia per
implementazione.\footnote{tanto che Stevens in \cite{UNP2} cita questo caso
come un esempio della maniera standard usata dallo standard POSIX per
consentire implementazioni non standardizzabili.} Nel caso di Linux, sia per
\itindsub{pathname}{assoluto} \textit{pathname} assoluto (comprendente
eventuali sottodirectory) rispetto a queste radici.
\itindsub{pathname}{assoluto} \textit{pathname} assoluto (comprendente
eventuali sottodirectory) rispetto a queste radici.
-comandi di accesso ai file,\footnote{questo è vero nel caso di Linux, che usa
- una implementazione che lo consente, non è detto che altrettanto valga per
- altri kernel; in particolare, come si può facilmente verificare con uno
+comandi di accesso ai file,\footnote{questo è vero nel caso di Linux, che usa
+ una implementazione che lo consente, non è detto che altrettanto valga per
+ altri kernel; in particolare, come si può facilmente verificare con uno
\cmd{strace}, sia per la memoria condivisa che per le code di messaggi le
system call utilizzate da Linux sono le stesse di quelle dei file, essendo
detti oggetti realizzati come tali in appositi filesystem.} che funzionano
\cmd{strace}, sia per la memoria condivisa che per le code di messaggi le
system call utilizzate da Linux sono le stesse di quelle dei file, essendo
detti oggetti realizzati come tali in appositi filesystem.} che funzionano
sez.~\ref{sec:ipc_sysv_access_control}) che viene usata per gli oggetti del
SysV IPC. Per quanto riguarda l'attribuzione dell'utente e del gruppo
proprietari dell'oggetto alla creazione di quest'ultimo essa viene effettuata
sez.~\ref{sec:ipc_sysv_access_control}) che viene usata per gli oggetti del
SysV IPC. Per quanto riguarda l'attribuzione dell'utente e del gruppo
proprietari dell'oggetto alla creazione di quest'ultimo essa viene effettuata
Krzysztof Benedyczak, e le relative informazioni si possono trovare su
\href{http://www.geocities.com/wronski12/posix_ipc/index.html}
{\textsf{http://www.geocities.com/wronski12/posix\_ipc/index.html}}.} In
generale, come le corrispettive del SysV IPC, le code di messaggi sono poco
Krzysztof Benedyczak, e le relative informazioni si possono trovare su
\href{http://www.geocities.com/wronski12/posix_ipc/index.html}
{\textsf{http://www.geocities.com/wronski12/posix\_ipc/index.html}}.} In
generale, come le corrispettive del SysV IPC, le code di messaggi sono poco
-usate, dato che i socket, nei casi in cui sono sufficienti, sono più comodi, e
-che in casi più complessi la comunicazione può essere gestita direttamente con
-mutex (o semafori) e memoria condivisa con tutta la flessibilità che occorre.
+usate, dato che i socket, nei casi in cui sono sufficienti, sono più comodi, e
+che in casi più complessi la comunicazione può essere gestita direttamente con
+mutex (o semafori) e memoria condivisa con tutta la flessibilità che occorre.
Per poter utilizzare le code di messaggi, oltre ad utilizzare un kernel
superiore al 2.6.6 (o precedente, se sono stati opportunamente applicati i
relativi patch) occorre utilizzare la libreria \file{libmqueue}\footnote{i
Per poter utilizzare le code di messaggi, oltre ad utilizzare un kernel
superiore al 2.6.6 (o precedente, se sono stati opportunamente applicati i
relativi patch) occorre utilizzare la libreria \file{libmqueue}\footnote{i
aggiungendo l'opzione \code{-lmqueue} al comando \cmd{gcc}; in
corrispondenza all'inclusione del supporto nel kernel ufficiale anche
aggiungendo l'opzione \code{-lmqueue} al comando \cmd{gcc}; in
corrispondenza all'inclusione del supporto nel kernel ufficiale anche
opportune chiamate ad \func{ioctl} sui file del filesystem speciale su cui
vengono mantenuti questi oggetti di IPC.}
La libreria inoltre richiede la presenza dell'apposito filesystem di tipo
opportune chiamate ad \func{ioctl} sui file del filesystem speciale su cui
vengono mantenuti questi oggetti di IPC.}
La libreria inoltre richiede la presenza dell'apposito filesystem di tipo
code di messaggi che iniziano con una ``\texttt{/}''. Le opzioni di mount
accettate sono \texttt{uid}, \texttt{gid} e \texttt{mode} che permettono
rispettivamente di impostare l'utente, il gruppo ed i permessi associati al
code di messaggi che iniziano con una ``\texttt{/}''. Le opzioni di mount
accettate sono \texttt{uid}, \texttt{gid} e \texttt{mode} che permettono
rispettivamente di impostare l'utente, il gruppo ed i permessi associati al
Apre una coda di messaggi POSIX impostandone le caratteristiche.
\bodydesc{La funzione restituisce il descrittore associato alla coda in caso
Apre una coda di messaggi POSIX impostandone le caratteristiche.
\bodydesc{La funzione restituisce il descrittore associato alla coda in caso
valori:
\begin{errlist}
\item[\errcode{EACCES}] il processo non ha i privilegi per accedere al
alla memoria secondo quanto specificato da \param{oflag}.
valori:
\begin{errlist}
\item[\errcode{EACCES}] il processo non ha i privilegi per accedere al
alla memoria secondo quanto specificato da \param{oflag}.
- \item[\errcode{EEXIST}] si è specificato \const{O\_CREAT} e
- \const{O\_EXCL} ma la coda già esiste.
- \item[\errcode{EINVAL}] il file non supporta la funzione, o si è
+ \item[\errcode{EEXIST}] si è specificato \const{O\_CREAT} e
+ \const{O\_EXCL} ma la coda già esiste.
+ \item[\errcode{EINVAL}] il file non supporta la funzione, o si è
specificato \const{O\_CREAT} con una valore non nullo di \param{attr} e
valori non validi di \var{mq\_maxmsg} e \var{mq\_msgsize}.
specificato \const{O\_CREAT} con una valore non nullo di \param{attr} e
valori non validi di \var{mq\_maxmsg} e \var{mq\_msgsize}.
non esiste.
\end{errlist}
ed inoltre \errval{ENOMEM}, \errval{ENOSPC}, \errval{EFAULT},
non esiste.
\end{errlist}
ed inoltre \errval{ENOMEM}, \errval{ENOSPC}, \errval{EFAULT},
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}.\footnote{nel caso di Linux si tratta in effetti proprio di un
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}.\footnote{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
+ 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 dell'interfaccia di notifica di \func{mq\_notify} (che
multiplexing (vedi sez.~\ref{sec:file_multiplexing}) come possibile
alternativa all'uso dell'interfaccia di notifica di \func{mq\_notify} (che
- vedremo a breve).} Se la coda esiste già il descrittore farà riferimento
-allo stesso oggetto, consentendo così la comunicazione fra due processi
+ vedremo a breve).} Se la coda esiste già il descrittore farà riferimento
+allo stesso oggetto, consentendo così la comunicazione fra due processi
possono essere specificati per \param{oflag}, che deve essere specificato come
maschera binaria; i valori possibili per i vari bit sono quelli visti in
possono essere specificati per \param{oflag}, che deve essere specificato come
maschera binaria; i valori possibili per i vari bit sono quelli visti in
seguenti:
\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
\item[\const{O\_RDONLY}] Apre la coda solo per la ricezione di messaggi. Il
seguenti:
\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
\item[\const{O\_RDONLY}] Apre la coda solo per la ricezione di messaggi. Il
presenza di questo bit richiede la presenza degli ulteriori argomenti
\param{mode} e \param{attr}.
\item[\const{O\_EXCL}] Se usato insieme a \const{O\_CREAT} fa fallire la
presenza di questo bit richiede la presenza degli ulteriori argomenti
\param{mode} e \param{attr}.
\item[\const{O\_EXCL}] Se usato insieme a \const{O\_CREAT} fa fallire la
- chiamata se la coda esiste già, altrimenti esegue la creazione atomicamente.
-\item[\const{O\_NONBLOCK}] Imposta la coda in modalità non bloccante, le
+ chiamata se la coda esiste già, altrimenti esegue la creazione atomicamente.
+\item[\const{O\_NONBLOCK}] Imposta la coda in modalità non bloccante, le
funzioni di ricezione e trasmissione non si bloccano quando non ci sono le
risorse richieste, ma ritornano immediatamente con un errore di
\errcode{EAGAIN}.
\end{basedescript}
funzioni di ricezione e trasmissione non si bloccano quando non ci sono le
risorse richieste, ma ritornano immediatamente con un errore di
\errcode{EAGAIN}.
\end{basedescript}
-I primi tre bit specificano la modalità di apertura della coda, e sono fra
-loro esclusivi. Ma qualunque sia la modalità in cui si è aperta una coda,
-questa potrà essere riaperta più volte in una modalità diversa, e vi si potrà
-sempre accedere attraverso descrittori diversi, esattamente come si può fare
+I primi tre bit specificano la modalità di apertura della coda, e sono fra
+loro esclusivi. Ma qualunque sia la modalità in cui si è aperta una coda,
+questa potrà essere riaperta più volte in una modalità diversa, e vi si potrà
+sempre accedere attraverso descrittori diversi, esattamente come si può fare
\func{open}, anche se per le code di messaggi han senso solo i permessi di
lettura e scrittura. Oltre ai permessi di creazione possono essere specificati
anche gli attributi specifici della coda tramite l'argomento \param{attr};
\func{open}, anche se per le code di messaggi han senso solo i permessi di
lettura e scrittura. Oltre ai permessi di creazione possono essere specificati
anche gli attributi specifici della coda tramite l'argomento \param{attr};
-quest'ultimo è un puntatore ad una apposita struttura \struct{mq\_attr}, la
-cui definizione è riportata in fig.~\ref{fig:ipc_mq_attr}.
+quest'ultimo è un puntatore ad una apposita struttura \struct{mq\_attr}, la
+cui definizione è riportata in fig.~\ref{fig:ipc_mq_attr}.
Per la creazione della coda i campi della struttura che devono essere
specificati sono \var{mq\_maxmsg} e \var{mq\_msgsize}, che indicano
Per la creazione della coda i campi della struttura che devono essere
specificati sono \var{mq\_maxmsg} e \var{mq\_msgsize}, che indicano
-rispettivamente il numero massimo di messaggi che può contenere e la
-dimensione massima di un messaggio. Il valore dovrà essere positivo e minore
+rispettivamente il numero massimo di messaggi che può contenere e la
+dimensione massima di un messaggio. Il valore dovrà essere positivo e minore
-altrimenti la funzione fallirà con un errore di \errcode{EINVAL}.
-Se \param{attr} è un puntatore nullo gli attributi della coda saranno
+altrimenti la funzione fallirà con un errore di \errcode{EINVAL}.
+Se \param{attr} è un puntatore nullo gli attributi della coda saranno
-Quando l'accesso alla coda non è più necessario si può chiudere il relativo
-descrittore con la funzione \funcd{mq\_close}, il cui prototipo è:
+Quando l'accesso alla coda non è più necessario si può chiudere il relativo
+descrittore con la funzione \funcd{mq\_close}, il cui prototipo è:
\begin{prototype}{mqueue.h}
{int mq\_close(mqd\_t mqdes)}
Chiude la coda \param{mqdes}.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 per un errore;
\begin{prototype}{mqueue.h}
{int mq\_close(mqd\_t mqdes)}
Chiude la coda \param{mqdes}.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 per un errore;
-La funzione è analoga a \func{close},\footnote{in Linux, dove le code sono
- implementate come file su un filesystem dedicato, è esattamente la stessa
- funzione.} dopo la sua esecuzione il processo non sarà più in grado di usare
-il descrittore della coda, ma quest'ultima continuerà ad esistere nel sistema
-e potrà essere acceduta con un'altra chiamata a \func{mq\_open}. All'uscita di
-un processo tutte le code aperte, così come i file, vengono chiuse
+La funzione è analoga a \func{close},\footnote{in Linux, dove le code sono
+ implementate come file su un filesystem dedicato, è esattamente la stessa
+ funzione.} dopo la sua esecuzione il processo non sarà più in grado di usare
+il descrittore della coda, ma quest'ultima continuerà ad esistere nel sistema
+e potrà essere acceduta con un'altra chiamata a \func{mq\_open}. All'uscita di
+un processo tutte le code aperte, così come i file, vengono chiuse
essere richiesta da qualche altro processo.
Quando si vuole effettivamente rimuovere una coda dal sistema occorre usare la
essere richiesta da qualche altro processo.
Quando si vuole effettivamente rimuovere una coda dal sistema occorre usare la
\begin{prototype}{mqueue.h}
{int mq\_unlink(const char *name)}
Rimuove una coda di messaggi.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
\begin{prototype}{mqueue.h}
{int mq\_unlink(const char *name)}
Rimuove una coda di messaggi.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
che una successiva chiamata a \func{mq\_open} fallisce o crea una coda
diversa.
Come per i file ogni coda di messaggi ha un contatore di riferimenti, per cui
la coda non viene effettivamente rimossa dal sistema fin quando questo non si
annulla. Pertanto anche dopo aver eseguito con successo \func{mq\_unlink} la
che una successiva chiamata a \func{mq\_open} fallisce o crea una coda
diversa.
Come per i file ogni coda di messaggi ha un contatore di riferimenti, per cui
la coda non viene effettivamente rimossa dal sistema fin quando questo non si
annulla. Pertanto anche dopo aver eseguito con successo \func{mq\_unlink} la
-all'interno del sistema anche quando quest'ultima non è aperta da nessun
-processo (questa è una delle differenze più rilevanti nei confronti di pipe e
-fifo). La sola differenza fra code di messaggi POSIX e file normali è che,
+all'interno del sistema anche quando quest'ultima non è aperta da nessun
+processo (questa è una delle differenze più rilevanti nei confronti di pipe e
+fifo). La sola differenza fra code di messaggi POSIX e file normali è che,
essendo il filesystem delle code di messaggi virtuale e basato su oggetti
interni al kernel, il suo contenuto viene perduto con il riavvio del sistema.
essendo il filesystem delle code di messaggi virtuale e basato su oggetti
interni al kernel, il suo contenuto viene perduto con il riavvio del sistema.
-Come accennato ad ogni coda di messaggi è associata una struttura
-\struct{mq\_attr}, che può essere letta e modificata attraverso le due
+Come accennato ad ogni coda di messaggi è associata una struttura
+\struct{mq\_attr}, che può essere letta e modificata attraverso le due
Modifica gli attributi di una coda di messaggi POSIX.
\bodydesc{Entrambe le funzioni restituiscono 0 in caso di successo e -1 in
Modifica gli attributi di una coda di messaggi POSIX.
\bodydesc{Entrambe le funzioni restituiscono 0 in caso di successo e -1 in
o \errval{EINVAL}.}
\end{functions}
La funzione \func{mq\_getattr} legge i valori correnti degli attributi della
coda nella struttura puntata da \param{mqstat}; di questi l'unico relativo
o \errval{EINVAL}.}
\end{functions}
La funzione \func{mq\_getattr} legge i valori correnti degli attributi della
coda nella struttura puntata da \param{mqstat}; di questi l'unico relativo
messaggi da essa contenuti, gli altri indicano le caratteristiche generali
della stessa.
La funzione \func{mq\_setattr} permette di modificare gli attributi di una
coda tramite i valori contenuti nella struttura puntata da \param{mqstat}, ma
messaggi da essa contenuti, gli altri indicano le caratteristiche generali
della stessa.
La funzione \func{mq\_setattr} permette di modificare gli attributi di una
coda tramite i valori contenuti nella struttura puntata da \param{mqstat}, ma
ignorati. In particolare i valori di \var{mq\_maxmsg} e \var{mq\_msgsize}
possono essere specificati solo in fase ci creazione della coda. Inoltre i
soli valori possibili per \var{mq\_flags} sono 0 e \const{O\_NONBLOCK}, per
ignorati. In particolare i valori di \var{mq\_maxmsg} e \var{mq\_msgsize}
possono essere specificati solo in fase ci creazione della coda. Inoltre i
soli valori possibili per \var{mq\_flags} sono 0 e \const{O\_NONBLOCK}, per
-cui alla fine la funzione può essere utilizzata solo per abilitare o
-disabilitare la modalità non bloccante. L'argomento \param{omqstat} viene
+cui alla fine la funzione può essere utilizzata solo per abilitare o
+disabilitare la modalità non bloccante. L'argomento \param{omqstat} viene
usato, quando diverso da \val{NULL}, per specificare l'indirizzo di una
struttura su cui salvare i valori degli attributi precedenti alla chiamata
della funzione.
usato, quando diverso da \val{NULL}, per specificare l'indirizzo di una
struttura su cui salvare i valori degli attributi precedenti alla chiamata
della funzione.
\item[\errcode{EMSGSIZE}] la lunghezza del messaggio \param{msg\_len}
eccede il limite impostato per la coda.
\item[\errcode{EMSGSIZE}] la lunghezza del messaggio \param{msg\_len}
eccede il limite impostato per la coda.
\param{msg\_len}, o un valore di \param{msg\_prio} fuori dai limiti, o
un valore non valido per \param{abs\_timeout}.
\param{msg\_len}, o un valore di \param{msg\_prio} fuori dai limiti, o
un valore non valido per \param{abs\_timeout}.
effettuato entro il tempo stabilito.
\end{errlist}
ed inoltre \errval{EBADF}, \errval{ENOMEM} ed \errval{EINTR}.}
effettuato entro il tempo stabilito.
\end{errlist}
ed inoltre \errval{EBADF}, \errval{ENOMEM} ed \errval{EINTR}.}
Se quest'ultima eccede la dimensione massima specificata da \var{mq\_msgsize}
le funzioni ritornano immediatamente con un errore di \errcode{EMSGSIZE}.
Se quest'ultima eccede la dimensione massima specificata da \var{mq\_msgsize}
le funzioni ritornano immediatamente con un errore di \errcode{EMSGSIZE}.
-L'argomento \param{msg\_prio} indica la priorità dell'argomento; i messaggi di
-priorità maggiore vengono inseriti davanti a quelli di priorità inferiore (e
-quindi saranno riletti per primi). A parità del valore della priorità il
-messaggio sarà inserito in coda a tutti quelli con la stessa priorità. Il
-valore della priorità non può eccedere il limite di sistema
-\const{MQ\_PRIO\_MAX}, che nel caso è pari a 32768.
+L'argomento \param{msg\_prio} indica la priorità dell'argomento; i messaggi di
+priorità maggiore vengono inseriti davanti a quelli di priorità inferiore (e
+quindi saranno riletti per primi). A parità del valore della priorità il
+messaggio sarà inserito in coda a tutti quelli con la stessa priorità. Il
+valore della priorità non può eccedere il limite di sistema
+\const{MQ\_PRIO\_MAX}, che nel caso è pari a 32768.
bloccante,\footnote{o si sia impostato il flag \const{O\_NONBLOCK} sul file
descriptor della coda.} nel qual caso entrambe ritornano \errcode{EAGAIN}.
bloccante,\footnote{o si sia impostato il flag \const{O\_NONBLOCK} sul file
descriptor della coda.} nel qual caso entrambe ritornano \errcode{EAGAIN}.
massimo impostato con l'argomento \param{abs\_timeout},\footnote{deve essere
specificato un tempo assoluto tramite una struttura \struct{timespec} (vedi
fig.~\ref{fig:sys_timespec_struct}) indicato in numero di secondi e
nanosecondi a partire dal 1 gennaio 1970.} ritorna comunque con un errore di
massimo impostato con l'argomento \param{abs\_timeout},\footnote{deve essere
specificato un tempo assoluto tramite una struttura \struct{timespec} (vedi
fig.~\ref{fig:sys_timespec_struct}) indicato in numero di secondi e
nanosecondi a partire dal 1 gennaio 1970.} ritorna comunque con un errore di
-\errcode{ETIMEDOUT}, se invece il tempo è già scaduto al momento della
-chiamata e la coda è vuota la funzione ritorna immediatamente.
+\errcode{ETIMEDOUT}, se invece il tempo è già scaduto al momento della
+chiamata e la coda è vuota la funzione ritorna immediatamente.
Come per l'inserimento, anche per l'estrazione dei messaggi da una coda sono
previste due funzioni, \funcd{mq\_receive} e \funcd{mq\_timedreceive}, i cui
Come per l'inserimento, anche per l'estrazione dei messaggi da una coda sono
previste due funzioni, \funcd{mq\_receive} e \funcd{mq\_timedreceive}, i cui
\item[\errcode{EMSGSIZE}] la lunghezza del messaggio sulla coda eccede il
valore \param{msg\_len} specificato per la ricezione.
\item[\errcode{EMSGSIZE}] la lunghezza del messaggio sulla coda eccede il
valore \param{msg\_len} specificato per la ricezione.
effettuata entro il tempo stabilito.
\end{errlist}
ed inoltre \errval{EBADF}, \errval{EINTR}, \errval{ENOMEM}, o
\errval{EINVAL}.}
\end{functions}
effettuata entro il tempo stabilito.
\end{errlist}
ed inoltre \errval{EBADF}, \errval{EINTR}, \errval{ENOMEM}, o
\errval{EINVAL}.}
\end{functions}
-La funzione estrae dalla coda il messaggio a priorità più alta, o il più
-vecchio fra quelli della stessa priorità. Una volta ricevuto il messaggio
+La funzione estrae dalla coda il messaggio a priorità più alta, o il più
+vecchio fra quelli della stessa priorità. Una volta ricevuto il messaggio
-ritorno.\footnote{si tenga presente che 0 è una dimensione valida e che la
- condizione di errore è restituita dal valore -1; Stevens in \cite{UNP2} fa
- notare che questo è uno dei casi in cui vale ciò che lo standard
+ritorno.\footnote{si tenga presente che 0 è una dimensione valida e che la
+ condizione di errore è restituita dal valore -1; Stevens in \cite{UNP2} fa
+ notare che questo è uno dei casi in cui vale ciò che lo standard
\textsl{non} dice, una dimensione nulla infatti, pur non essendo citata, non
viene proibita.}
\textsl{non} dice, una dimensione nulla infatti, pur non essendo citata, non
viene proibita.}
il messaggio, entrambe le funzioni, al contrario di quanto avveniva nelle code
di messaggi di SysV, ritornano un errore di \errcode{EMSGSIZE} senza estrarre
il messaggio, entrambe le funzioni, al contrario di quanto avveniva nelle code
di messaggi di SysV, ritornano un errore di \errcode{EMSGSIZE} senza estrarre
\func{mq\_getaddr} prima di eseguire una ricezione, in modo da ottenere la
dimensione massima dei messaggi sulla coda, per poter essere in grado di
allocare dei buffer sufficientemente ampi per la lettura.
Se si specifica un puntatore per l'argomento \param{msg\_prio} il valore della
\func{mq\_getaddr} prima di eseguire una ricezione, in modo da ottenere la
dimensione massima dei messaggi sulla coda, per poter essere in grado di
allocare dei buffer sufficientemente ampi per la lettura.
Se si specifica un puntatore per l'argomento \param{msg\_prio} il valore della
-priorità del messaggio viene memorizzato all'indirizzo da esso indicato.
-Qualora non interessi usare la priorità dei messaggi si può specificare
-\var{NULL}, ed usare un valore nullo della priorità nelle chiamate a
+priorità del messaggio viene memorizzato all'indirizzo da esso indicato.
+Qualora non interessi usare la priorità dei messaggi si può specificare
+\var{NULL}, ed usare un valore nullo della priorità nelle chiamate a
-Si noti che con le code di messaggi POSIX non si ha la possibilità di
-selezionare quale messaggio estrarre con delle condizioni sulla priorità, a
+Si noti che con le code di messaggi POSIX non si ha la possibilità di
+selezionare quale messaggio estrarre con delle condizioni sulla priorità, a
differenza di quanto avveniva con le code di messaggi di SysV che permettono
invece la selezione in base al valore del campo \var{mtype}.
% TODO inserire i dati di /proc/sys/fs/mqueue
Qualora la coda sia vuota entrambe le funzioni si bloccano, a meno che non si
differenza di quanto avveniva con le code di messaggi di SysV che permettono
invece la selezione in base al valore del campo \var{mtype}.
% TODO inserire i dati di /proc/sys/fs/mqueue
Qualora la coda sia vuota entrambe le funzioni si bloccano, a meno che non si
passato il tempo massimo \param{abs\_timeout} ritorna comunque con un errore
di \errcode{ETIMEDOUT}.
Uno dei problemi sottolineati da Stevens in \cite{UNP2}, comuni ad entrambe le
passato il tempo massimo \param{abs\_timeout} ritorna comunque con un errore
di \errcode{ETIMEDOUT}.
Uno dei problemi sottolineati da Stevens in \cite{UNP2}, comuni ad entrambe le
-tipologie di code messaggi, è che non è possibile per chi riceve identificare
-chi è che ha inviato il messaggio, in particolare non è possibile sapere da
+tipologie di code messaggi, è che non è possibile per chi riceve identificare
+chi è che ha inviato il messaggio, in particolare non è possibile sapere da
quale utente esso provenga. Infatti, in mancanza di un meccanismo interno al
kernel, anche se si possono inserire delle informazioni nel messaggio, queste
non possono essere credute, essendo completamente dipendenti da chi lo invia.
quale utente esso provenga. Infatti, in mancanza di un meccanismo interno al
kernel, anche se si possono inserire delle informazioni nel messaggio, queste
non possono essere credute, essendo completamente dipendenti da chi lo invia.
-Una caratteristica specifica delle code di messaggi POSIX è la possibilità di
-usufruire di un meccanismo di notifica asincrono; questo può essere attivato
-usando la funzione \funcd{mq\_notify}, il cui prototipo è:
+Una caratteristica specifica delle code di messaggi POSIX è la possibilità di
+usufruire di un meccanismo di notifica asincrono; questo può essere attivato
+usando la funzione \funcd{mq\_notify}, il cui prototipo è:
\begin{prototype}{mqueue.h}
{int mq\_notify(mqd\_t mqdes, const struct sigevent *notification)}
Attiva il meccanismo di notifica per la coda \param{mqdes}.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
\begin{prototype}{mqueue.h}
{int mq\_notify(mqd\_t mqdes, const struct sigevent *notification)}
Attiva il meccanismo di notifica per la coda \param{mqdes}.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
\item[\errcode{EBADF}] il descrittore non fa riferimento ad una coda di
messaggi.
\end{errlist}}
\end{prototype}
Il meccanismo di notifica permette di segnalare in maniera asincrona ad un
\item[\errcode{EBADF}] il descrittore non fa riferimento ad una coda di
messaggi.
\end{errlist}}
\end{prototype}
Il meccanismo di notifica permette di segnalare in maniera asincrona ad un
processo alla volta per ciascuna coda.
Il comportamento di \func{mq\_notify} dipende dal valore dell'argomento
processo alla volta per ciascuna coda.
Il comportamento di \func{mq\_notify} dipende dal valore dell'argomento
\struct{sigevent}, (definita in fig.~\ref{fig:struct_sigevent}) introdotta
dallo standard POSIX.1b per gestire la notifica di eventi; per altri dettagli
\struct{sigevent}, (definita in fig.~\ref{fig:struct_sigevent}) introdotta
dallo standard POSIX.1b per gestire la notifica di eventi; per altri dettagli
-Attraverso questa struttura si possono impostare le modalità con cui viene
-effettuata la notifica nel campo \var{sigev\_notify}, che può assumere i
+Attraverso questa struttura si possono impostare le modalità con cui viene
+effettuata la notifica nel campo \var{sigev\_notify}, che può assumere i
valori di tab.~\ref{tab:sigevent_sigev_notify}.\footnote{la pagina di manuale
riporta soltanto i primi tre (inizialmente era possibile solo
valori di tab.~\ref{tab:sigevent_sigev_notify}.\footnote{la pagina di manuale
riporta soltanto i primi tre (inizialmente era possibile solo
un puntatore ad una struttura \struct{sigval\_t} (definita in
fig.~\ref{fig:sig_sigval}) che permette di restituire al gestore del segnale
un valore numerico o un indirizzo,\footnote{per il suo uso si riveda la
un puntatore ad una struttura \struct{sigval\_t} (definita in
fig.~\ref{fig:sig_sigval}) che permette di restituire al gestore del segnale
un valore numerico o un indirizzo,\footnote{per il suo uso si riveda la
La funzione registra il processo chiamante per la notifica se
\param{notification} punta ad una struttura \struct{sigevent} opportunamente
La funzione registra il processo chiamante per la notifica se
\param{notification} punta ad una struttura \struct{sigevent} opportunamente
-inizializzata, o cancella una precedente registrazione se è \val{NULL}. Dato
-che un solo processo alla volta può essere registrato, la funzione fallisce
-con \errcode{EBUSY} se c'è un altro processo già registrato.\footnote{questo
+inizializzata, o cancella una precedente registrazione se è \val{NULL}. Dato
+che un solo processo alla volta può essere registrato, la funzione fallisce
+con \errcode{EBUSY} se c'è un altro processo già registrato.\footnote{questo
per poterlo fare.} Si tenga presente inoltre che alla chiusura del
descrittore associato alla coda (e quindi anche all'uscita del processo) ogni
eventuale registrazione di notifica presente viene cancellata.
La notifica del segnale avviene all'arrivo di un messaggio in una coda vuota
per poterlo fare.} Si tenga presente inoltre che alla chiusura del
descrittore associato alla coda (e quindi anche all'uscita del processo) ogni
eventuale registrazione di notifica presente viene cancellata.
La notifica del segnale avviene all'arrivo di un messaggio in una coda vuota
bloccato in una chiamata a \func{mq\_receive}, in questo caso infatti il
processo bloccato ha la precedenza ed il messaggio gli viene immediatamente
inviato, mentre per il meccanismo di notifica tutto funziona come se la coda
bloccato in una chiamata a \func{mq\_receive}, in questo caso infatti il
processo bloccato ha la precedenza ed il messaggio gli viene immediatamente
inviato, mentre per il meccanismo di notifica tutto funziona come se la coda
che se si vuole mantenere il meccanismo di notifica occorre ripetere la
registrazione chiamando nuovamente \func{mq\_notify} all'interno del gestore
del segnale di notifica. A differenza della situazione simile che si aveva con
che se si vuole mantenere il meccanismo di notifica occorre ripetere la
registrazione chiamando nuovamente \func{mq\_notify} all'interno del gestore
del segnale di notifica. A differenza della situazione simile che si aveva con
-\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
+\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.
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.
valore del \acr{pid} del processo che ha emesso il segnale, \var{si\_uid}
all'userid effettivo, \var{si\_code} a \const{SI\_MESGQ}, e \var{si\_errno} a
0. Questo ci dice che, se si effettua la ricezione dei messaggi usando
valore del \acr{pid} del processo che ha emesso il segnale, \var{si\_uid}
all'userid effettivo, \var{si\_code} a \const{SI\_MESGQ}, e \var{si\_errno} a
0. Questo ci dice che, se si effettua la ricezione dei messaggi usando
sul processo che ha inserito un messaggio usando un gestore per il segnale in
forma estesa.\footnote{di nuovo si faccia riferimento a quanto detto al
proposito in sez.~\ref{sec:sig_sigaction} e sez.~\ref{sec:sig_real_time}.}
sul processo che ha inserito un messaggio usando un gestore per il segnale in
forma estesa.\footnote{di nuovo si faccia riferimento a quanto detto al
proposito in sez.~\ref{sec:sig_sigaction} e sez.~\ref{sec:sig_real_time}.}
-La memoria condivisa è stato il primo degli oggetti di IPC POSIX inserito nel
-kernel ufficiale; il supporto a questo tipo di oggetti è realizzato attraverso
+La memoria condivisa è stato il primo degli oggetti di IPC POSIX inserito nel
+kernel ufficiale; il supporto a questo tipo di oggetti è realizzato attraverso
il filesystem \texttt{tmpfs}, uno speciale filesystem che mantiene tutti i
suoi contenuti in memoria, che viene attivato abilitando l'opzione
\texttt{CONFIG\_TMPFS} in fase di compilazione del kernel.
Per potere utilizzare l'interfaccia POSIX per la memoria condivisa le
\acr{glibc}\footnote{le funzioni sono state introdotte con le glibc-2.2.}
il filesystem \texttt{tmpfs}, uno speciale filesystem che mantiene tutti i
suoi contenuti in memoria, che viene attivato abilitando l'opzione
\texttt{CONFIG\_TMPFS} in fase di compilazione del kernel.
Per potere utilizzare l'interfaccia POSIX per la memoria condivisa le
\acr{glibc}\footnote{le funzioni sono state introdotte con le glibc-2.2.}
necessario che in \file{/dev/shm} sia montato un filesystem \texttt{tmpfs};
questo di norma viene fatto aggiungendo una riga del tipo di:
\begin{verbatim}
tmpfs /dev/shm tmpfs defaults 0 0
\end{verbatim}
necessario che in \file{/dev/shm} sia montato un filesystem \texttt{tmpfs};
questo di norma viene fatto aggiungendo una riga del tipo di:
\begin{verbatim}
tmpfs /dev/shm tmpfs defaults 0 0
\end{verbatim}
dove si vuole, per usarlo come RAM disk, con un comando del tipo:
\begin{verbatim}
mount -t tmpfs -o size=128M,nr_inodes=10k,mode=700 tmpfs /mytmpfs
dove si vuole, per usarlo come RAM disk, con un comando del tipo:
\begin{verbatim}
mount -t tmpfs -o size=128M,nr_inodes=10k,mode=700 tmpfs /mytmpfs
Il filesystem riconosce, oltre quelle mostrate, le opzioni \texttt{uid} e
\texttt{gid} che identificano rispettivamente utente e gruppo cui assegnarne
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
-questo caso è l'unità di allocazione elementare.
+la titolarità, e \texttt{nr\_blocks} che permette di specificarne la
+dimensione in blocchi, cioè in multipli di \const{PAGECACHE\_SIZE} che in
+questo caso è l'unità di allocazione elementare.
Apre un segmento di memoria condivisa.
\bodydesc{La funzione restituisce un file descriptor positivo in caso di
Apre un segmento di memoria condivisa.
\bodydesc{La funzione restituisce un file descriptor positivo in caso di
stessi valori riportati da \func{open}.}
\end{functions}
La funzione apre un segmento di memoria condivisa identificato dal nome
stessi valori riportati da \func{open}.}
\end{functions}
La funzione apre un segmento di memoria condivisa identificato dal nome
-\param{name}. Come già spiegato in sez.~\ref{sec:ipc_posix_generic} questo
-nome può essere specificato in forma standard solo facendolo iniziare per
+\param{name}. Come già spiegato in sez.~\ref{sec:ipc_posix_generic} questo
+nome può essere specificato in forma standard solo facendolo iniziare per
``\file{/}'' e senza ulteriori ``\file{/}''. Linux supporta comunque nomi
generici, che verranno interpretati prendendo come radice
\file{/dev/shm}.\footnote{occorre pertanto evitare di specificare qualcosa del
``\file{/}'' e senza ulteriori ``\file{/}''. Linux supporta comunque nomi
generici, che verranno interpretati prendendo come radice
\file{/dev/shm}.\footnote{occorre pertanto evitare di specificare qualcosa del
comporta, da parte delle funzioni di libreria, il tentativo di accedere a
\file{/dev/shm/dev/shm/nome}.}
comporta, da parte delle funzioni di libreria, il tentativo di accedere a
\file{/dev/shm/dev/shm/nome}.}
possono essere specificati per \param{oflag}, che deve essere specificato come
maschera binaria comprendente almeno uno dei due valori \const{O\_RDONLY} e
\const{O\_RDWR}; i valori possibili per i vari bit sono quelli visti in
possono essere specificati per \param{oflag}, che deve essere specificato come
maschera binaria comprendente almeno uno dei due valori \const{O\_RDONLY} e
\const{O\_RDWR}; i valori possibili per i vari bit sono quelli visti in
i seguenti:
\begin{basedescript}{\desclabelwidth{2.0cm}\desclabelstyle{\nextlinelabel}}
\item[\const{O\_RDONLY}] Apre il file descriptor associato al segmento di
i seguenti:
\begin{basedescript}{\desclabelwidth{2.0cm}\desclabelstyle{\nextlinelabel}}
\item[\const{O\_RDONLY}] Apre il file descriptor associato al segmento di
\item[\const{O\_CREAT}] Necessario qualora si debba creare il segmento di
memoria condivisa se esso non esiste; in questo caso viene usato il valore
di \param{mode} per impostare i permessi, che devono essere compatibili con
\item[\const{O\_CREAT}] Necessario qualora si debba creare il segmento di
memoria condivisa se esso non esiste; in questo caso viene usato il valore
di \param{mode} per impostare i permessi, che devono essere compatibili con
tronca le dimensioni a 0 byte.
\end{basedescript}
In caso di successo la funzione restituisce un file descriptor associato al
tronca le dimensioni a 0 byte.
\end{basedescript}
In caso di successo la funzione restituisce un file descriptor associato al
-segmento di memoria condiviso con le stesse modalità di
-\func{open}\footnote{in realtà, come accennato, \func{shm\_open} è un semplice
+segmento di memoria condiviso con le stesse modalità di
+\func{open}\footnote{in realtà, come accennato, \func{shm\_open} è un semplice
wrapper per \func{open}, usare direttamente quest'ultima avrebbe lo stesso
effetto.} viste in sez.~\ref{sec:file_open}; in particolare viene impostato
il flag \const{FD\_CLOEXEC}. Chiamate effettuate da diversi processi usando
lo stesso nome, restituiranno file descriptor associati allo stesso segmento
wrapper per \func{open}, usare direttamente quest'ultima avrebbe lo stesso
effetto.} viste in sez.~\ref{sec:file_open}; in particolare viene 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 di dati, essi sono associati allo stesso
-\index{inode} inode). In questo modo è possibile effettuare una chiamata ad
+(così come, nel caso di file di dati, essi sono associati allo stesso
+\index{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.
\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 il segmento può essere creato specificando
-\const{O\_CREAT}; in tal caso il segmento avrà (così come i nuovi file)
-lunghezza nulla. Dato che un segmento di lunghezza nulla è di scarsa utilità,
+Quando il nome non esiste il segmento può essere creato specificando
+\const{O\_CREAT}; in tal caso il segmento avrà (così come i nuovi file)
+lunghezza nulla. Dato che un segmento di lunghezza nulla è di scarsa utilità,
per impostarne la dimensione si deve usare \func{ftruncate} (vedi
sez.~\ref{sec:file_file_size}), prima di mapparlo in memoria con \func{mmap}.
per impostarne la dimensione si deve usare \func{ftruncate} (vedi
sez.~\ref{sec:file_file_size}), prima di mapparlo in memoria con \func{mmap}.
descriptor (con \func{close}), senza che la mappatura ne risenta.
Come per i file, quando si vuole effettivamente rimuovere segmento di memoria
descriptor (con \func{close}), senza che la mappatura ne risenta.
Come per i file, quando si vuole effettivamente rimuovere segmento di memoria
\begin{prototype}{sys/mman.h}
{int shm\_unlink(const char *name)}
Rimuove un segmento di memoria condivisa.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
\begin{prototype}{sys/mman.h}
{int shm\_unlink(const char *name)}
Rimuove un segmento di memoria condivisa.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
-La funzione è del tutto analoga ad \func{unlink}, e si limita a cancellare il
-nome del segmento da \file{/dev/shm}, senza nessun effetto né sui file
-descriptor precedentemente aperti con \func{shm\_open}, né sui segmenti già
+La funzione è del tutto analoga ad \func{unlink}, e si limita a cancellare il
+nome del segmento da \file{/dev/shm}, senza nessun effetto né sui file
+descriptor precedentemente aperti con \func{shm\_open}, né sui segmenti già
mappati in memoria; questi verranno cancellati automaticamente dal sistema
solo con le rispettive chiamate a \func{close} e \func{munmap}. Una volta
mappati in memoria; questi verranno cancellati automaticamente dal sistema
solo con le rispettive chiamate a \func{close} e \func{munmap}. Una volta
-eseguita questa funzione però, qualora si richieda l'apertura di un segmento
-con lo stesso nome, la chiamata a \func{shm\_open} fallirà, a meno di non aver
-usato \const{O\_CREAT}, in quest'ultimo caso comunque si otterrà un file
+eseguita questa funzione però, qualora si richieda l'apertura di un segmento
+con lo stesso nome, la chiamata a \func{shm\_open} fallirà, a meno di non aver
+usato \const{O\_CREAT}, in quest'ultimo caso comunque si otterrà un file
una interfaccia semplificata analoga a quella vista in
fig.~\ref{fig:ipc_sysv_shm_func} per la memoria condivisa in stile SysV. Il
una interfaccia semplificata analoga a quella vista in
fig.~\ref{fig:ipc_sysv_shm_func} per la memoria condivisa in stile SysV. Il
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})
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})
\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
\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
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.
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
-segmento di memoria condiviso già esistente, restituendone l'indirizzo. In
+La seconda funzione (\texttt{\small 25--40}) è \func{FindShm} che trova un
+segmento di memoria condiviso già esistente, restituendone l'indirizzo. In
(\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 l'indirizzo (\texttt{\small 39}) dello stesso in
caso di successo.
(\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 l'indirizzo (\texttt{\small 39}) dello stesso in
caso di successo.
cancellare un segmento di memoria condivisa. Dato che al contrario di quanto
avveniva con i segmenti del SysV IPC gli oggetti allocati nel kernel vengono
cancellare un segmento di memoria condivisa. Dato che al contrario di quanto
avveniva con i segmenti del SysV IPC gli oggetti allocati nel kernel vengono
-rilasciati automaticamente quando nessuna li usa più, tutto quello che c'è da
-fare (\texttt{\small 44}) in questo caso è chiamare \func{shm\_unlink},
+rilasciati automaticamente quando nessuna li usa più, tutto quello che c'è da
+fare (\texttt{\small 44}) in questo caso è chiamare \func{shm\_unlink},
estensioni \textit{real-time} delle \acr{glibc}.\footnote{quelle che si
accedono collegandosi alla libreria \texttt{librt}.} Esisteva inoltre una
libreria che realizzava (parzialmente) l'interfaccia POSIX usando le funzioni
estensioni \textit{real-time} delle \acr{glibc}.\footnote{quelle che si
accedono collegandosi alla libreria \texttt{librt}.} Esisteva inoltre una
libreria che realizzava (parzialmente) l'interfaccia POSIX usando le funzioni
sincronizzazione completamente nuovo, basato sui cosiddetti
\textit{futex},\footnote{la sigla sta per \textit{fast user mode mutex}.} con
sincronizzazione completamente nuovo, basato sui cosiddetti
\textit{futex},\footnote{la sigla sta per \textit{fast user mode mutex}.} con
POSIX. Grazie a questo con i kernel della serie 2.6 e le nuove versioni delle
\acr{glibc} che usano questa nuova infrastruttura per quella che viene quella
che viene chiamata \textit{New Posix Thread Library}, sono state implementate
anche tutte le funzioni dell'interfaccia dei semafori POSIX.
POSIX. Grazie a questo con i kernel della serie 2.6 e le nuove versioni delle
\acr{glibc} che usano questa nuova infrastruttura per quella che viene quella
che viene chiamata \textit{New Posix Thread Library}, sono state implementate
anche tutte le funzioni dell'interfaccia dei semafori POSIX.
\textit{real-time} \texttt{librt}, questo significa che se si vuole utilizzare
questa interfaccia, oltre ad utilizzare gli opportuni file di definizione,
\textit{real-time} \texttt{librt}, questo significa che se si vuole utilizzare
questa interfaccia, oltre ad utilizzare gli opportuni file di definizione,
-relativo file, o di accedere ad uno esistente, è \funcd{sem\_open}, questa
+relativo file, o di accedere ad uno esistente, è \funcd{sem\_open}, questa
prevede due forme diverse a seconda che sia utilizzata per aprire un semaforo
esistente o per crearne uno nuovi, i relativi prototipi sono:
\begin{functions}
prevede due forme diverse a seconda che sia utilizzata per aprire un semaforo
esistente o per crearne uno nuovi, i relativi prototipi sono:
\begin{functions}
\bodydesc{La funzione restituisce l'indirizzo del semaforo in caso di
successo e \const{SEM\_FAILED} in caso di errore; nel quel caso
\bodydesc{La funzione restituisce l'indirizzo del semaforo in caso di
successo e \const{SEM\_FAILED} in caso di errore; nel quel caso
- \item[\errcode{ENAMETOOLONG}] si è utilizzato un nome troppo lungo.
- \item[\errcode{ENOENT}] non si è usato \const{O\_CREAT} ed il nome
+ \item[\errcode{ENAMETOOLONG}] si è utilizzato un nome troppo lungo.
+ \item[\errcode{ENOENT}] non si è usato \const{O\_CREAT} ed il nome
specificato non esiste.
\end{errlist}
ed inoltre \errval{ENFILE} ed \errval{ENOMEM}.}
\end{functions}
L'argomento \param{name} definisce il nome del semaforo che si vuole
specificato non esiste.
\end{errlist}
ed inoltre \errval{ENFILE} ed \errval{ENOMEM}.}
\end{functions}
L'argomento \param{name} definisce il nome del semaforo che si vuole
stesso semaforo. Questo deve essere specificato con un pathname nella forma
\texttt{/qualchenome}, che non ha una corrispondenza diretta con un pathname
reale; con Linux infatti i file associati ai semafori sono mantenuti nel
filesystem virtuale \texttt{/dev/shm}, e gli viene assegnato automaticamente
stesso semaforo. Questo deve essere specificato con un pathname nella forma
\texttt{/qualchenome}, che non ha una corrispondenza diretta con un pathname
reale; con Linux infatti i file associati ai semafori sono mantenuti nel
filesystem virtuale \texttt{/dev/shm}, e gli viene assegnato automaticamente
corrispondenza per cui \texttt{/qualchenome} viene rimappato, nella
creazione tramite \func{sem\_open}, su \texttt{/dev/shm/sem.qualchenome}.}
corrispondenza per cui \texttt{/qualchenome} viene rimappato, nella
creazione tramite \func{sem\_open}, su \texttt{/dev/shm/sem.qualchenome}.}
-L'argomento \param{oflag} è quello che controlla le modalità con cui opera la
-funzione, ed è passato come maschera binaria; i bit corrispondono a quelli
+L'argomento \param{oflag} è quello che controlla le modalità con cui opera la
+funzione, ed è passato come maschera binaria; i bit corrispondono a quelli
utilizzati per l'analogo argomento di \func{open}, anche se dei possibili
valori visti in sez.~\ref{sec:file_open} sono utilizzati soltanto
\const{O\_CREAT} e \const{O\_EXCL}.
utilizzati per l'analogo argomento di \func{open}, anche se dei possibili
valori visti in sez.~\ref{sec:file_open} sono utilizzati soltanto
\const{O\_CREAT} e \const{O\_EXCL}.
Se si usa \const{O\_CREAT} si richiede la creazione del semaforo qualora
questo non esista, ed in tal caso occorre utilizzare la seconda forma della
funzione, in cui si devono specificare sia un valore iniziale con l'argomento
Se si usa \const{O\_CREAT} si richiede la creazione del semaforo qualora
questo non esista, ed in tal caso occorre utilizzare la seconda forma della
funzione, in cui si devono specificare sia un valore iniziale con l'argomento
quanto avviene per i semafori del \textit{SysV IPC}, effettuare in maniera
atomica creazione ed inizializzazione di un semaforo usando una unica
funzione.} che una maschera dei permessi con l'argomento
\param{mode};\footnote{anche questo argomento prende gli stessi valori
utilizzati per l'analogo di \func{open}, che si sono illustrati in dettaglio
sez.~\ref{sec:file_perm_overview}.} questi verranno assegnati al semaforo
quanto avviene per i semafori del \textit{SysV IPC}, effettuare in maniera
atomica creazione ed inizializzazione di un semaforo usando una unica
funzione.} che una maschera dei permessi con l'argomento
\param{mode};\footnote{anche questo argomento prende gli stessi valori
utilizzati per l'analogo di \func{open}, che si sono illustrati in dettaglio
sez.~\ref{sec:file_perm_overview}.} questi verranno assegnati al semaforo
ignorati. Usando il flag \const{O\_EXCL} si richiede invece la verifica che il
semaforo non esiste, usandolo insieme ad \const{O\_CREAT} la funzione fallisce
ignorati. Usando il flag \const{O\_EXCL} si richiede invece la verifica che il
semaforo non esiste, usandolo insieme ad \const{O\_CREAT} la funzione fallisce
essere passato alle altre funzioni per operare sul semaforo stesso. Si tenga
presente che, come accennato in sez.~\ref{sec:ipc_posix_generic}, i semafori
usano la semantica standard dei file per quanto riguarda i controlli di
essere passato alle altre funzioni per operare sul semaforo stesso. Si tenga
presente che, come accennato in sez.~\ref{sec:ipc_posix_generic}, i semafori
usano la semantica standard dei file per quanto riguarda i controlli di
Questo significa che un nuovo semaforo viene sempre creato con l'user-ID ed il
group-ID effettivo del processo chiamante, e che i permessi indicati con
\param{mode} vengono filtrati dal valore della \itindex{umask} \textit{umask}
Questo significa che un nuovo semaforo viene sempre creato con l'user-ID ed il
group-ID effettivo del processo chiamante, e che i permessi indicati con
\param{mode} vengono filtrati dal valore della \itindex{umask} \textit{umask}
utilizzarlo; se si ricorda quanto detto all'inizio di
sez.~\ref{sec:ipc_sysv_sem}, dove si sono introdotti i concetti generali
relativi ai semafori, le operazioni principali sono due, quella che richiede
l'uso di una risorsa bloccando il semaforo e quella che rilascia la risorsa
utilizzarlo; se si ricorda quanto detto all'inizio di
sez.~\ref{sec:ipc_sysv_sem}, dove si sono introdotti i concetti generali
relativi ai semafori, le operazioni principali sono due, quella che richiede
l'uso di una risorsa bloccando il semaforo e quella che rilascia la risorsa
-liberando il semaforo. La prima operazione è effettuata dalla funzione
-\funcd{sem\_wait}, il cui prototipo è:
+liberando il semaforo. La prima operazione è effettuata dalla funzione
+\funcd{sem\_wait}, il cui prototipo è:
Blocca il semaforo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
Blocca il semaforo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
La funzione cerca di decrementare il valore del semaforo indicato dal
puntatore \param{sem}, se questo ha un valore positivo, cosa che significa che
La funzione cerca di decrementare il valore del semaforo indicato dal
puntatore \param{sem}, se questo ha un valore positivo, cosa che significa che
-la risorsa è disponibile, la funzione ha successo, il valore del semaforo
-viene diminuito di 1 ed essa ritorna immediatamente; se il valore è nullo la
+la risorsa è disponibile, la funzione ha successo, il valore del semaforo
+viene diminuito di 1 ed essa ritorna immediatamente; se il valore è nullo la
funzione si blocca fintanto che il valore del semaforo non torni
positivo\footnote{ovviamente per opera di altro processo che lo rilascia
funzione si blocca fintanto che il valore del semaforo non torni
positivo\footnote{ovviamente per opera di altro processo che lo rilascia
-Si tenga presente che la funzione può sempre essere interrotta da un segnale
-(nel qual caso si avrà un errore di \const{EINTR}) e che questo avverrà
-comunque, anche se si è richiesta la semantica BSD installando il relativo
+Si tenga presente che la funzione può sempre essere interrotta da un segnale
+(nel qual caso si avrà un errore di \const{EINTR}) e che questo avverrà
+comunque, anche se si è richiesta la semantica BSD installando il relativo
gestore con \const{SA\_RESTART} (vedi sez.~\ref{sec:sig_sigaction}) per
riavviare le system call interrotte.
Della funzione \func{sem\_wait} esistono due varianti che consentono di
gestore con \const{SA\_RESTART} (vedi sez.~\ref{sec:sig_sigaction}) per
riavviare le system call interrotte.
Della funzione \func{sem\_wait} esistono due varianti che consentono di
-gestire diversamente le modalità di attesa in caso di risorsa occupata, la
-prima di queste è \funcd{sem\_trywait}, che serve ad effettuare un tentativo
-di acquisizione senza bloccarsi; il suo prototipo è:
+gestire diversamente le modalità di attesa in caso di risorsa occupata, la
+prima di queste è \funcd{sem\_trywait}, che serve ad effettuare un tentativo
+di acquisizione senza bloccarsi; il suo prototipo è:
Tenta di bloccare il semaforo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
Tenta di bloccare il semaforo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
-funzione lo decrementa e ritorna immediatamente; la differenza è che nel caso
-in cui il semaforo è occupato essa non si blocca e di nuovo ritorna
-immediatamente, restituendo però un errore di \errval{EAGAIN}, così che il
+funzione lo decrementa e ritorna immediatamente; la differenza è che nel caso
+in cui il semaforo è occupato essa non si blocca e di nuovo ritorna
+immediatamente, restituendo però un errore di \errval{EAGAIN}, così che il
-ad un valore di 600 prima di includere \texttt{semaphore.h}, la funzione è
-\func{sem\_timedwait}, ed il suo prototipo è:
+ad un valore di 600 prima di includere \texttt{semaphore.h}, la funzione è
+\func{sem\_timedwait}, ed il suo prototipo è:
Blocca il semaforo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
Blocca il semaforo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
-anche se non è possibile acquisire il semaforo. In tal caso la funzione
-fallirà, riportando un errore di \errval{ETIMEDOUT}.
+anche se non è possibile acquisire il semaforo. In tal caso la funzione
+fallirà, riportando un errore di \errval{ETIMEDOUT}.
Rilascia il semaforo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
Rilascia il semaforo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
-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 potrà essere
-svegliato e rimesso in esecuzione. Si tenga presente che la funzione è sicura
+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 potrà essere
+svegliato e rimesso in esecuzione. Si tenga presente che la funzione è sicura
\index{funzioni!sicure} per l'uso all'interno di un gestore di segnali (si
ricordi quanto detto in sez.~\ref{sec:sig_signal_handler}).
Se invece di operare su un semaforo se ne vuole solamente leggere il valore,
\index{funzioni!sicure} per l'uso all'interno di un gestore di segnali (si
ricordi quanto detto in sez.~\ref{sec:sig_signal_handler}).
Se invece di operare su un semaforo se ne vuole solamente leggere il valore,
Richiede il valore del semaforo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
Richiede il valore del semaforo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
La funzione legge il valore del semaforo indicato dall'argomento \param{sem} e
lo restituisce nella variabile intera puntata dall'argomento
La funzione legge il valore del semaforo indicato dall'argomento \param{sem} e
lo restituisce nella variabile intera puntata dall'argomento
semaforo lo standard prevede che la funzione possa restituire un valore nullo
oppure il numero di processi bloccati in una \func{sem\_wait} sul suddetto
semaforo; nel caso di Linux vale la prima opzione.
semaforo lo standard prevede che la funzione possa restituire un valore nullo
oppure il numero di processi bloccati in una \func{sem\_wait} sul suddetto
semaforo; nel caso di Linux vale la prima opzione.
-Questa funzione può essere utilizzata per avere un suggerimento sullo stato di
-un semaforo, ovviamente non si può prendere il risultato riportato in
+Questa funzione può essere utilizzata per avere un suggerimento sullo stato di
+un semaforo, ovviamente non si può prendere il risultato riportato in
-Una volta che non ci sia più la necessità di operare su un semaforo se ne può
-terminare l'uso con la funzione \funcd{sem\_close}, il cui prototipo è:
+Una volta che non ci sia più la necessità di operare su un semaforo se ne può
+terminare l'uso con la funzione \funcd{sem\_close}, il cui prototipo è:
Chiude il semaforo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
Chiude il semaforo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
nell'uso dello stesso vengono rilasciate. Questo significa che un altro
processo bloccato sul semaforo a causa della acquisizione da parte del
nell'uso dello stesso vengono rilasciate. Questo significa che un altro
processo bloccato sul semaforo a causa della acquisizione da parte del
Si tenga presente poi che come per i file all'uscita di un processo tutti i
semafori che questo aveva aperto vengono automaticamente chiusi; questo
comportamento risolve il problema che si aveva con i semafori del \textit{SysV
Si tenga presente poi che come per i file all'uscita di un processo tutti i
semafori che questo aveva aperto vengono automaticamente chiusi; questo
comportamento risolve il problema che si aveva con i semafori del \textit{SysV
risorse possono restare bloccate. Si tenga poi presente che, a differenza di
quanto avviene per i file, in caso di una chiamata ad \func{execve} tutti i
semafori vengono chiusi automaticamente.
Come per i semafori del \textit{SysV IPC} anche quelli POSIX hanno una
risorse possono restare bloccate. Si tenga poi presente che, a differenza di
quanto avviene per i file, in caso di una chiamata ad \func{execve} tutti i
semafori vengono chiusi automaticamente.
Come per i semafori del \textit{SysV IPC} anche quelli POSIX hanno una
-persistenza di sistema; questo significa che una volta che si è creato un
-semaforo con \func{sem\_open} questo continuerà ad esistere fintanto che il
+persistenza di sistema; questo significa che una volta che si è creato un
+semaforo con \func{sem\_open} questo continuerà ad esistere fintanto che il
-lo si cancelli esplicitamente. Per far questo si può utilizzare la funzione
-\funcd{sem\_unlink}, il cui prototipo è:
+lo si cancelli esplicitamente. Per far questo si può utilizzare la funzione
+\funcd{sem\_unlink}, il cui prototipo è:
Rimuove il semaforo \param{name}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
Rimuove il semaforo \param{name}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
prende un valore identico a quello usato per creare il semaforo stesso con
\func{sem\_open}. Il semaforo viene rimosso dal filesystem immediatamente; ma
il semaforo viene effettivamente cancellato dal sistema soltanto quando tutti
prende un valore identico a quello usato per creare il semaforo stesso con
\func{sem\_open}. Il semaforo viene rimosso dal filesystem immediatamente; ma
il semaforo viene effettivamente cancellato dal sistema soltanto quando tutti
semantica usata con \func{unlink} per i file, trattata in dettaglio in
sez.~\ref{sec:file_link}.
semantica usata con \func{unlink} per i file, trattata in dettaglio in
sez.~\ref{sec:file_link}.
-Una delle caratteristiche peculiari dei semafori POSIX è che questi possono
-anche essere utilizzati anche in forma anonima, senza necessità di fare
+Una delle caratteristiche peculiari dei semafori POSIX è che questi possono
+anche essere utilizzati anche in forma anonima, senza necessità di fare
Inizializza il semaforo anonimo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
Inizializza il semaforo anonimo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
Qualora il semaforo debba essere condiviso dai \itindex{thread}
\textit{thread} di uno stesso processo (nel qual caso si parla di
Qualora il semaforo debba essere condiviso dai \itindex{thread}
\textit{thread} di uno stesso processo (nel qual caso si parla di
-renderlo visibile a tutti è di porlo in un tratto di memoria condivisa. Questo
-potrà essere ottenuto direttamente sia con \func{shmget} (vedi
+renderlo visibile a tutti è di porlo in un tratto di memoria condivisa. Questo
+potrà essere ottenuto direttamente sia con \func{shmget} (vedi
sez.~\ref{sec:ipc_sysv_shm}) che con \func{shm\_open} (vedi
sez.~\ref{sec:ipc_posix_shm}), oppure, nel caso che tutti i processi in gioco
abbiano un genitore comune, con una mappatura anonima con \func{mmap} (vedi
sez.~\ref{sec:ipc_sysv_shm}) che con \func{shm\_open} (vedi
sez.~\ref{sec:ipc_posix_shm}), oppure, nel caso che tutti i processi in gioco
abbiano un genitore comune, con una mappatura anonima con \func{mmap} (vedi
condivisa vengono mantenuti nei processi figli attraverso la funzione
\func{fork}.} a cui essi poi potranno accedere.
condivisa vengono mantenuti nei processi figli attraverso la funzione
\func{fork}.} a cui essi poi potranno accedere.
-\func{sem\_post}. Si tenga presente però che inizializzare due volte lo stesso
-semaforo può dar luogo ad un comportamento indefinito.
+\func{sem\_post}. Si tenga presente però che inizializzare due volte lo stesso
+semaforo può dar luogo ad un comportamento indefinito.
Elimina il semaforo anonimo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
Elimina il semaforo anonimo \param{sem}.
\bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
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
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
-Si tenga presente infine che utilizzare un semaforo che è stato distrutto con
-\func{sem\_destroy} di nuovo può dare esito a comportamenti indefiniti. Nel
+Si tenga presente infine che utilizzare un semaforo che è stato distrutto con
+\func{sem\_destroy} di nuovo può dare esito a comportamenti indefiniti. Nel
caso ci si trovi in una tale evenienza occorre reinizializzare il semaforo una
seconda volta con \func{sem\_init}.
Come esempio di uso sia della memoria condivisa che dei semafori POSIX si sono
caso ci si trovi in una tale evenienza occorre reinizializzare il semaforo una
seconda volta con \func{sem\_init}.
Come esempio di uso sia della memoria condivisa che dei semafori POSIX si sono
-Il corpo principale del primo dei due, il cui codice completo è nel file
-\file{message\_getter.c} dei sorgenti allegati, è riportato in
-fig.~\ref{fig:ipc_posix_sem_shm_message_server}; si è tralasciata la parte che
+Il corpo principale del primo dei due, il cui codice completo è nel file
+\file{message\_getter.c} dei sorgenti allegati, è riportato in
+fig.~\ref{fig:ipc_posix_sem_shm_message_server}; si è tralasciata la parte che
tratta la gestione delle opzioni a riga di comando (che consentono di
impostare un nome diverso per il semaforo e il segmento di memoria condivisa)
ed il controllo che al programma venga fornito almeno un argomento, contenente
la stringa iniziale da inserire nel segmento di memoria condivisa.
tratta la gestione delle opzioni a riga di comando (che consentono di
impostare un nome diverso per il semaforo e il segmento di memoria condivisa)
ed il controllo che al programma venga fornito almeno un argomento, contenente
la stringa iniziale da inserire nel segmento di memoria condivisa.
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})
del gestore del segnale usato per liberare le risorse utilizzate, delle
variabili globali contenenti i nomi di default del segmento di memoria
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})
del gestore del segnale usato per liberare le risorse utilizzate, delle
variabili globali contenenti i nomi di default del segmento di memoria
-Come prima istruzione (\texttt{\small 10}) si è provveduto ad installare un
-gestore di segnale che consentirà di effettuare le operazioni di pulizia
+Come prima istruzione (\texttt{\small 10}) si è provveduto ad installare un
+gestore di segnale che consentirà di effettuare le operazioni di pulizia
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.
Si tenga presente che la funzione \func{CreateShm} richiede che il segmento
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.
Si tenga presente che la funzione \func{CreateShm} richiede che il segmento
-non sia già presente e fallirà qualora un'altra istanza, o un altro programma
-abbia già allocato un segmento con quello stesso nome. Per semplicità di
-gestione si è usata una dimensione fissa pari a 256 byte, definita tramite la
+non sia già presente e fallirà qualora un'altra istanza, o un altro programma
+abbia già allocato un segmento con quello stesso nome. Per semplicità di
+gestione si è usata una dimensione fissa pari a 256 byte, definita tramite la
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
combinazione di flag \code{O\_CREAT|O\_EXCL} come secondo argomento, si esce
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
combinazione di flag \code{O\_CREAT|O\_EXCL} come secondo argomento, si esce
preoccupare di eventuali \itindex{race~condition} \textit{race condition}
qualora il programma di modifica del messaggio venisse lanciato proprio in
preoccupare di eventuali \itindex{race~condition} \textit{race condition}
qualora il programma di modifica del messaggio venisse lanciato proprio in
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})
per stampare sia il contenuto del messaggio che una serie di informazioni di
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})
per stampare sia il contenuto del messaggio che una serie di informazioni di
\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
corrente.
\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
corrente.
Prima della stampa del messaggio invece si deve acquisire il semaforo
(\texttt{\small 31--34}) per evitare accessi concorrenti alla stringa da parte
del programma di modifica. Una volta eseguita la stampa (\texttt{\small 41})
Prima della stampa del messaggio invece si deve acquisire il semaforo
(\texttt{\small 31--34}) 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
-(\texttt{\small 46}) è attendere per un secondo prima di eseguire da capo il
+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
riportato il corpo principale in
fig.~\ref{fig:ipc_posix_sem_shm_message_setter},\footnote{al solito il codice
riportato il corpo principale in
fig.~\ref{fig:ipc_posix_sem_shm_message_setter},\footnote{al solito il codice
essendo significativa per quanto si sta trattando, la parte relativa alla
gestione delle opzioni a riga di comando e degli argomenti, che sono identici
a quelli usati da \file{message\_getter}, con l'unica aggiunta di un'opzione
essendo significativa per quanto si sta trattando, la parte relativa alla
gestione delle opzioni a riga di comando e degli argomenti, che sono identici
a quelli usati da \file{message\_getter}, con l'unica aggiunta di un'opzione
essere presente uno solo, contenente la nuova stringa da usare come
messaggio), il programma procede (\texttt{\small 10--14}) con l'acquisizione
del segmento di memoria condivisa usando la funzione \func{FindShm} (trattata
essere presente uno solo, contenente la nuova stringa da usare come
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
+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
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
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
-che sarà possibile eseguire la sostituzione del messaggio (\texttt{\small 25})
+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}.
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
senza incorrere in possibili \itindex{race~condition} \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
-Per verificare il funzionamento dei programmi occorrerà lanciare per primo
-\file{message\_getter}\footnote{lanciare per primo \file{message\_setter} darà
+Per verificare il funzionamento dei programmi occorrerà lanciare per primo
+\file{message\_getter}\footnote{lanciare per primo \file{message\_setter} darà
contenuto del messaggio ed i suoi dati, con qualcosa del tipo:
\begin{Verbatim}
piccardi@hain:~/gapil/sources$ ./message_getter messaggio
contenuto del messaggio ed i suoi dati, con qualcosa del tipo:
\begin{Verbatim}
piccardi@hain:~/gapil/sources$ ./message_getter messaggio
%$
proseguendo indefinitamente fintanto che non si prema \texttt{C-c} per farlo
uscire. Si noti come il valore del semaforo risulti sempre pari ad 1 (in
%$
proseguendo indefinitamente fintanto che non si prema \texttt{C-c} per farlo
uscire. Si noti come il valore del semaforo risulti sempre pari ad 1 (in
messaggio, nel nostro caso per rendere evidente il funzionamento del blocco
richiederemo anche una attesa di 3 secondi, ed otterremo qualcosa del tipo:
\begin{Verbatim}
messaggio, nel nostro caso per rendere evidente il funzionamento del blocco
richiederemo anche una attesa di 3 secondi, ed otterremo qualcosa del tipo:
\begin{Verbatim}
-L'effetto di questo programma si potrà però apprezzare meglio nell'uscita di
-\file{message\_getter}, che verrà interrotta per questo stesso tempo, prima di
+L'effetto di questo programma si potrà però apprezzare meglio nell'uscita di
+\file{message\_getter}, che verrà interrotta per questo stesso tempo, prima di
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}
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}