Lo stream restituito da \func{popen} è identico a tutti gli effetti ai file
stream visti in \capref{cha:files_std_interface}, anche se è collegato ad una
-pipe e non ad un inode\index{inode}, e viene sempre aperto in modalità
+pipe e non ad un file, e viene sempre aperto in modalità
\textit{fully-buffered} (vedi \secref{sec:file_buffering}); l'unica differenza
con gli usuali stream è che dovrà essere chiuso dalla seconda delle due nuove
funzioni, \funcd{pclose}, il cui prototipo è:
{
/* Variables definition */
int i, n = 0;
- char *fortunefilename = "/usr/share/games/fortunes/italia";
+ char *fortunefilename = "/usr/share/games/fortunes/linux";
char **fortune;
char line[80];
int fifo_server, fifo_client;
exit(1);
}
}
+ daemon(0, 0);
/* open fifo two times to avoid EOF */
fifo_server = open(fifoname, O_RDONLY);
if (fifo_server < 0) {
in cui la funzione \func{mkfifo} fallisce per la precedente esistenza della
fifo).
-Una volta che si è certi che la fifo di ascolto esiste si procede
-(\texttt{\small 23--32}) alla sua apertura. Questo viene fatto due volte
-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 dal capo in lettura,
-l'esecuzione di \func{read} ritorna con zero byte (si ha cioè una condizione
-di end-of-file).
+Una volta che si è certi che la fifo di ascolto esiste la procedura di
+inizializzazione è completata. A questo punto si può chiamare (\texttt{\small
+ 23}) la funzione \func{daemon} per far proseguire l'esecuzione del programma
+in background come demone. Si può quindi procedere (\texttt{\small 24--33})
+alla apertura della 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
+dal capo in lettura, l'esecuzione di \func{read} ritorna con zero byte (si ha
+cioè una condizione di end-of-file).
Nel nostro caso la prima apertura si bloccherà fintanto che un qualunque
client non apre a sua volta la fifo nota in scrittura per effettuare la sua
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 e a questo punto
-\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 che non si
- può scrivere per errore sul capo aperto in sola lettura.}
+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
+ fifo in lettura/scrittura, per cui si sarebbe potuto effettuare una singola
+ apertura con \const{O\_RDWR}, la doppia apertura comunque ha il vantaggio
+ che non si può scrivere per errore sul capo aperto in sola lettura.}
Per questo motivo, dopo aver eseguito l'apertura in lettura (\texttt{\small
- 24--28}),\footnote{di solito si effettua l'apertura del capo in lettura in
- modalità non bloccante, per evitare il rischio di uno stallo (se nessuno
- apre la fifo in scrittura il processo non ritornerà mai dalla \func{open})
- che nel nostro caso non esiste, mentre è necessario potersi bloccare in
- lettura in attesa di una richiesta.} si esegue una seconda apertura in
-scrittura (\texttt{\small 29--32}), scartando il relativo file descriptor che
-non sarà mai usato, ma lasciando la fifo comunque aperta anche in scrittura,
-cosicché le successive possano bloccarsi.
+ 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 è
+ 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
+a \func{read} possono bloccarsi.
A questo punto si può entrare nel ciclo principale del programma che fornisce
-le risposte ai client (\texttt{\small 34--50}), che viene eseguito
+le risposte ai client (\texttt{\small 34--50}); questo viene eseguito
indefinitamente (l'uscita del server viene effettuata inviando un segnale, in
-modo da passare attraverso la routine di chiusura che cancella la fifo).
+modo da passare attraverso la routine di chiusura che cancella la fifo).
Il server è progettato per accettare come richieste dai client delle stringhe
che contengono il nome della fifo sulla quale deve essere inviata la risposta.
non ci sono richieste). Dopo di che, una volta terminata la stringa
(\texttt{\small 40}) e selezionato (\texttt{\small 41}) un numero casuale per
ricavare la frase da inviare, si procederà (\texttt{\small 42--46})
-all'apertura della fifo per la risposta, che \texttt{\small 47--48}) poi vi
+all'apertura della fifo per la risposta, che poi \texttt{\small 47--48}) vi
sarà scritta. Infine (\texttt{\small 49}) si chiude la fifo di risposta che
-non serve più.
+non serve più.
Il codice del client è invece riportato in \figref{fig:ipc_fifo_client}, anche
in questo caso si è omessa la gestione delle opzioni e la funzione che stampa
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
+occorrerà definire la speciale variabile di ambiente \code{LD\_LIBRARY\_PATH}
+in modo che il linker dinamico possa accedervi.
+
+In generale questa variabile indica il 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 dare sarà \code{export
+ LD\_LIBRARY\_PATH=./}; a questo punto potremo lanciare il server, facendogli
+leggere una decina di frasi, con:
+\begin{verbatim}
+[piccardi@gont sources]$ ./fortuned -n10
+\end{verbatim}
+
+Avendo usato \func{daemon} per eseguire il server in background il comando
+ritornerà immediatamente, ma potremo verificare con \cmd{ps} che in effetti il
+programma resta un esecuzione in background, e senza avere associato un
+terminale di controllo (si ricordi quanto detto in \secref{sec:sess_daemon}):
+\begin{verbatim}
+[piccardi@gont sources]$ ps aux
+...
+piccardi 27489 0.0 0.0 1204 356 ? S 01:06 0:00 ./fortuned -n10
+piccardi 27492 3.0 0.1 2492 764 pts/2 R 01:08 0:00 ps aux
+\end{verbatim}%$
+e si potrà verificare anche che in \file{/tmp} è stata creata la fifo di
+ascolto \file{fortune.fifo}. A questo punto potremo interrogare il server con
+il programma client; otterremo così:
+\begin{verbatim}
+[piccardi@gont sources]$ ./fortune
+Linux ext2fs has been stable for a long time, now it's time to break it
+ -- Linuxkongreß '95 in Berlin
+[piccardi@gont sources]$ ./fortune
+Let's call it an accidental feature.
+ --Larry Wall
+[piccardi@gont sources]$ ./fortune
+......... Escape the 'Gates' of Hell
+ `:::' ....... ......
+ ::: * `::. ::'
+ ::: .:: .:.::. .:: .:: `::. :'
+ ::: :: :: :: :: :: :::.
+ ::: .::. .:: ::. `::::. .:' ::.
+...:::.....................::' .::::..
+ -- William E. Roadcap
+[piccardi@gont sources]$ ./fortune
+Linux ext2fs has been stable for a long time, now it's time to break it
+ -- Linuxkongreß '95 in Berlin
+\end{verbatim}%$
+e ripetendo varie volte il comando otterremo, in ordine casuale, le dieci
+frasi tenute in memoria dal server.
+
+Infine per chiudere il server basterà inviare un segnale di terminazione con
+\code{killall fortuned} e potremo verificare che il gestore del segnale ha
+anche correttamente cancellato la fifo di ascolto da \file{/tmp}.
+
Benché il nostro sistema client-server funzioni, la sua struttura è piuttosto
complessa e continua ad avere vari inconvenienti\footnote{lo stesso Stevens,
che esamina questa architettura in \cite{APUE}, nota come sia impossibile
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 \func{MutexUnlock}, perché se per
-un qualche errore si esegue più volte quest'ultima il valore del semaforo
-crescerebbe oltre 1, e \func{MutexLock} non avrebbe più l'effetto aspettato
-(bloccare la risorsa quando questa è considerata libera). Si tenga presente
-che usare \func{MutexRead} per controllare il valore dei mutex prima di
-proseguire non servirebbe comunque, dato che l'operazione non sarebbe atomica.
+incrementato di uno, sbloccandolo qualora fosse bloccato.
+
+Si noti che occorre eseguire sempre prima \func{MutexLock} e poi
+\func{MutexUnlock}, perché se per un qualche errore si esegue più volte
+quest'ultima il valore del semaforo crescerebbe oltre 1, e \func{MutexLock}
+non avrebbe più l'effetto aspettato (bloccare la risorsa quando questa è
+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.
Vedremo in \secref{sec:ipc_lock_file} come sia possibile ottenere
un'interfaccia analoga a quella appena illustrata, senza incorrere in questi
problemi, usando il file locking\index{file!locking}.
-
\subsection{Memoria condivisa}
\label{sec:ipc_sysv_shm}
\footnotesize \centering
\begin{minipage}[c]{15cm}
\begin{lstlisting}{}
-/* computation function for DirScan */
-int ComputeValues(struct dirent * direntry);
-void HandSIGTERM(int signo);
/* global variables for shared memory segment */
struct DirProp {
int tot_size;
int tot_block;
int tot_char;
int tot_sock;
-};
-struct DirProp *shmptr;
+} *shmptr;
int shmid;
int mutex;
/* main body */
printf("Wrong number of arguments %d\n", argc - optind);
usage();
}
+ if (chdir(argv[1])) { /* chdir to be sure dir exist */
+ perror("Cannot find directory to monitor");
+ }
Signal(SIGTERM, HandSIGTERM); /* set handlers for termination */
Signal(SIGINT, HandSIGTERM);
Signal(SIGQUIT, HandSIGTERM);
- /* create needed IPC objects */
- key = ftok("./DirMonitor.c", 1); /* define a key */
+ key = ftok("~/gapil/sources/DirMonitor.c", 1); /* define a key */
shmid = shmget(key, 4096, IPC_CREAT|0666); /* get a shared memory */
if (shmid < 0) {
perror("Cannot create shared memory");
}
if ( (shmptr = shmat(shmid, NULL, 0)) == NULL ) { /* attach to process */
perror("Cannot attach segment");
+ exit(1);
}
if ((mutex = MutexCreate(key)) == -1) { /* get a Mutex */
perror("Cannot create mutex");
exit(1);
}
/* main loop, monitor directory properties each 10 sec */
+ daemon(1, 0); /* demonize process, staying in monitored dir */
while (1) {
MutexLock(mutex); /* lock shared memory */
memset(shmptr, 0, sizeof(struct DirProp)); /* erase previous data */
\label{fig:ipc_dirmonitor_main}
\end{figure}
-Il programma usa delle variabili globali (\texttt{\small 4--18}) per mantenere
+Il programma usa delle variabili globali (\texttt{\small 2--14}) per mantenere
i valori relativi agli oggetti usati per la comunicazione inter-processo; si è
definita inoltre una apposita struttura \struct{DirProp} che contiene i dati
relativi alle proprietà che si vogliono mantenere nella memoria condivisa, per
l'accesso da parte dei client.
Il programma, dopo la sezione, omessa, relativa alla gestione delle opzioni da
-riga di comando, che si limitano alla eventuale stampa di un messaggio di
+riga di comando (che si limitano alla eventuale stampa di un messaggio di
aiuto a video ed all'impostazione della durata dell'intervallo con cui viene
-ripetuto il calcolo delle proprietà della directory, controlla (\texttt{\small
- 25--28}) che sia stato specificato un parametro (il nome della directory da
-tenere sotto controllo) senza il quale esce immediatamente con un messaggio di
-errore.
-
-Il passo successivo (\texttt{\small 29--31}) è quello di installare i gestori
-per i segnali di terminazione, infatti, visto che il programma è progettato
-come server, non è prevista una conclusione esplicita nel corpo principale,
-per cui, per gestire l'uscita, si è fatto uso di questi ultimi.
-
-Si può poi passare a creare (\texttt{\small 32--45}) gli oggetti di
-intercomunicazione necessari. Si ricava (\texttt{\small 33}) una chiave usando
-il nome del programma, con questa si ottiene (\texttt{\small 34--38}) un
-segmento di memoria condivisa \var{shmid} (uscendo in caso di errore), che si
-aggancia (\texttt{\small 39--41}) al processo all'indirizzo \var{shmptr}; sarà
-attraverso questo puntatore che potremo accedere alla memoria condivisa, che
-sarà vista nella forma data da \struct{DirProp}. Infine con la stessa chiave
-si crea (\texttt{\small 42--45}) anche un mutex (utilizzando le funzioni di
-interfaccia già descritte in \secref{sec:ipc_sysv_sem}) che utilizzeremo per
-regolare l'accesso alla memoria condivisa.
+ripetuto il calcolo delle proprietà della directory) controlla (\texttt{\small
+ 21--24}) che sia stato specificato il parametro necessario contenente il
+nome della directory da tenere sotto controllo, senza il quale esce
+immediatamente con un messaggio di errore.
+
+Poi, per verificare che il parametro specifichi effettivamente una directory,
+si esegue (\texttt{\small 25--27}) su di esso una \func{chdir}, uscendo
+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
+\func{daemon}.\footnote{Si noti come si è potuta fare questa scelta,
+ nonostante le indicazioni illustrate in \secref{sec:sess_daemon}, per il
+ particolare scopo del programma, che necessita comunque di restare
+ all'interno di una directory.} Infine (\texttt{\small 28--30}) si installano
+i gestori per i vari segnali di terminazione che, avendo a che fare con un
+programma che deve essere eseguito come server, sono il solo strumento
+disponibile per concluderne l'esecuzione.
+
+Il passo successivo (\texttt{\small 31--44}) è quello di creare gli oggetti di
+intercomunicazione necessari. Si inizia costruendo (\texttt{\small 31}) la
+chiave da usare come riferimento con il nome del programma,\footnote{si è
+ usato un riferimento relativo alla home dell'utente, supposto che i sorgenti
+ di GaPiL siano stati installati direttamente in essa. Qualora si effettui
+ una installazione diversa si dovrà correggere il programma.} dopo di che si
+richiede (\texttt{\small 32}) la creazione di un segmento di memoria condivisa
+con \func{shmget} (una pagina di memoria è sufficiente per i dati che
+useremo), uscendo (\texttt{\small 33--36}) qualora la creazione non abbia
+successo.
+
+Una volta ottenutone l'identificatore in \var{shmid}, si può agganciare
+(\texttt{\small 37--40}) il segmento al processo con \func{shmat} anche in
+questo caso si esce qualora la funzione non abbia successo. Con l'indirizzo
+\var{shmptr} così ottenuto potremo poi accedere alla memoria condivisa, che,
+per come abbiamo lo abbiamo definito, sarà vista nella forma data da
+\struct{DirProp}. Infine (\texttt{\small 41--44}) utilizzando sempre la stessa
+chiave, si crea, tramite le funzioni di interfaccia già descritte in
+\secref{sec:ipc_sysv_sem}, anche un mutex, che utilizzeremo per regolare
+l'accesso alla memoria condivisa.
Una volta completata l'inizializzazione e la creazione degli oggetti di
-intercomunicazione il programma eseguirà indefinitamente (\texttt{\small
- 46--53}) il ciclo principale: si inizia bloccando il mutex (\texttt{\small
- 48}) per poter accedere alla memoria condivisa (la funzione si bloccherà
-automaticamente se qualche client sta leggendo), poi si cancellano
-(\texttt{\small 49}) i valori precedentemente memorizzati, e si esegue
-(\texttt{\small 50}) un nuovo calcolo degli stessi; infine si sblocca il mutex
-(\texttt{\small 51}), e si attende (\texttt{\small 52}) per il periodo di
-tempo specificato a riga di comando con l'opzione \code{-p}.
+intercomunicazione il programma entra nel ciclo principale (\texttt{\small
+ 45--54}) dove vengono eseguitw indefinitamente le attività di monitoraggio.
+Il primo passo (\texttt{\small 46}) è esguire \func{daemon} per proseguire con
+l'esecuzione in background come si conviene ad un programma demone; si noti
+che si è mantenuta, usando un valore non nullo del primo argomento, la
+directory di lavoro corrente.
+
+Una volta che il programma è andato in background l'esecuzione prosegue
+(\texttt{\small 47--53}) all'interno di un ciclo infinito: si inizia
+(\texttt{\small 48}) bloccando il mutex con \func{MutexLock} per poter
+accedere alla memoria condivisa (la funzione si bloccherà automaticamente se
+qualche client sta leggendo), poi (\texttt{\small 49}) si cancellano i valori
+precedentemente immagazzinati nella memoria condivisa con \func{memset}, e si
+esegue (\texttt{\small 50}) un nuovo calcolo degli stessi utilizzando la
+funzione \func{DirScan}; infine (\texttt{\small 51}) si sblocca il mutex con
+\func{MutexUnlock}, e si attende (\texttt{\small 52}) per il periodo di tempo
+specificato a riga di comando con l'opzione \code{-p} con una \func{sleep}.
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
\begin{lstlisting}{}
-...
-/*
- * Routine to compute directory properties inside DirScan
- */
+/* Routine to compute directory properties inside DirScan */
int ComputeValues(struct dirent * direntry)
{
struct stat data;
if (S_ISSOCK(data.st_mode)) shmptr->tot_sock++;
return 0;
}
-/*
- * Signal Handler to manage termination
- */
+/* Signal Handler to manage termination */
void HandSIGTERM(int signo) {
MutexLock(mutex);
if (shmdt(shmptr)) {
esse la funzione \func{ComputeValues}, che esegue tutti i calcoli necessari.
Il codice di quest'ultima è riportato in \figref{fig:ipc_dirmonitor_sub}. Come
-si vede la funzione (\texttt{\small 5--19}) è molto semplice e si limita a
-chiamare (\texttt{\small 8}) la funzione \func{stat} sul file indicato da
+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.
+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
-condivisa usando \var{shmptr} riempiendo i campi della struttura
-\struct{DirProp}; così prima (\texttt{\small 9--10}) si sommano le dimensioni
-dei file ed il loro numero, poi utilizzando le macro di
-\tabref{tab:file_type_macro}, si contano (\texttt{\small 11--17}) quanti ce ne
+condivisa usando \var{shmptr} per riempire i campi della struttura
+\struct{DirProp}; così prima (\texttt{\small 6--7}) si sommano le dimensioni
+dei file ed il loro numero, poi, utilizzando le macro di
+\tabref{tab:file_type_macro}, si contano (\texttt{\small 8--14}) quanti ce ne
sono per ciascun tipo.
-In \figref{fig:ipc_dirmonitor_sub} è riportato anche (\texttt{\small 23--35})
-il codice del gestore di segnali di terminazione usato per chiudere il
-programma, che oltre a provocare l'uscita del programma si incarica anche di
-cancellare tutti gli oggetti di intercomunicazione non più necessari. Nel
-caso anzitutto (\texttt{\small 24}) si acquisisce il mutex per evitare di
-operare mentre un client sta ancora leggendo i dati, dopo di che prima si
-distacca (\texttt{\small 25--28}) il segmento e poi lo si cancella
-(\texttt{\small 29--32}). Infine (\texttt{\small 33}) si rimuove il mutex e si
-esce.
-
-Il codice del client che permette di leggere le informazioni mantenute nella
-memoria condivisa è riportato in \figref{fig:ipc_dirmonitor_client}, al solito
-si è omessa la sezione di gestione delle opzioni e la funzione che stampa a
-video le istruzioni; il codice completo è nei sorgenti allegati, nel file
-\file{ReadMonitor.c}.
+In \figref{fig:ipc_dirmonitor_sub} è riportato anche (\texttt{\small 17--30})
+il codice del gestore dei segnali di terminazione, usato per chiudere il
+programma. Esso, oltre a provocare l'uscita del programma, si incarica anche
+di cancellare tutti gli oggetti di intercomunicazione non più necessari. Per
+questo anzitutto (\texttt{\small 19}) acquisisce il mutex con
+\func{MutexLock}, per evitare di operare mentre un client sta ancora leggendo
+i dati, dopo di che (\texttt{\small 20--23}) prima distacca il segmento di
+memoria condivisa con \func{shmad} e poi (\texttt{\small 24--27}) lo cancella
+con \func{shctl}. Infine (\texttt{\small 28}) rimuove il mutex con
+\func{MutexRemove} ed esce.
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
\begin{lstlisting}{}
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <dirent.h> /* directory */
-#include <stdlib.h> /* C standard library */
-#include <unistd.h>
-
-#include "Gapil.h"
-#include "macros.h"
-
int main(int argc, char *argv[])
{
int i;
key_t key;
- ..
- /* find needed IPC objects */
- key = ftok("./DirMonitor.c", 1); /* define a key */
+ ...
+ /* create needed IPC objects */
+ key = ftok("~/gapil/sources/DirMonitor.c", 1); /* define a key */
shmid = shmget(key, 4096, 0); /* get the shared memory ID */
if (shmid < 0) {
perror("Cannot find shared memory");
\end{lstlisting}
\end{minipage}
\normalsize
- \caption{Codice del programma client \file{ReadMonitor.c}.}
+ \caption{Codice del programma client del monitori di directory,
+ \file{ReadMonitor.c}.}
\label{fig:ipc_dirmonitor_client}
\end{figure}
+Il codice del client, che permette di leggere le informazioni mantenute nella
+memoria condivisa, è riportato in \figref{fig:ipc_dirmonitor_client}. Al
+solito si è omessa la sezione di gestione delle opzioni e la funzione che
+stampa a video le istruzioni; il codice completo è nei sorgenti allegati, nel
+file \file{ReadMonitor.c}.
+
Una volta completata la gestione delle opzioni a riga di comando il programma
-rigenera (\texttt{\small 16}) la chiave usata per identificare memoria
-condivisa e mutex, richiede (\texttt{\small 17}) l'identificatore della
-memoria condivisa (che in questo caso deve già esistere), uscendo in caso di
-errore (\texttt{\small 18--21}). Una volta ottenuto l'identificatore si può
-(\texttt{\small 22--25}) agganciare il segmento al processo (anche in questo
-caso uscendo se qualcosa non funziona). Infine (\texttt{\small 26--29}) si
-richiede pure l'identificatore del mutex.
+rigenera (\texttt{\small 7}) con \func{ftok} la stessa chiave usata dal server
+per identificare il segmento di memoria condivisa ed il mutex, poi
+(\texttt{\small 8}) si richiede con \func{semget} l'identificatore della
+memoria condivisa, ma in questo caso si vuole che esso esista di già; al
+solito (\texttt{\small 9--12}) si esce in caso di errore. Una volta ottenuto
+l'identificatore in \var{shmid} si può (\texttt{\small 13--16}) agganciare il
+segmento al processo all'indirizzo \func{shmptr}; anche in questo caso si
+chiude immediatamente il programma se qualcosa non funziona. Infine
+(\texttt{\small 17--20}) con \func{MutexFind} si richiede l'identificatore del
+mutex.
Una volta completata l'inizializzazione ed ottenuti i riferimenti agli oggetti
di intercomunicazione necessari viene eseguito il corpo principale del
-programma (\texttt{\small 30--41}); si acquisisce (\texttt{\small 31}) il
-mutex (qui avviene il blocco se la memoria condivisa non è disponibile), e poi
-(\texttt{\small 32--40}) si stampano i vari valori in essa contenuti. Infine
-(\texttt{\small 41}) si rilascia il mutex.
+programma (\texttt{\small 21--33}); si comincia (\texttt{\small 22})
+acquisendo il mutex con \func{MutexLock}; qui avviene il blocco del processo
+se la memoria condivisa non è disponibile. Poi (\texttt{\small 23--31}) si
+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 libreira occorre definire opportunamente
+\code{LD\_LIBRARY\_PATH}; poi si potrà lanciare il server con:
+\begin{verbatim}
+[piccardi@gont sources]$ ./dirmonitor ./
+\end{verbatim}%$
+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
+Ci sono 68 file dati
+Ci sono 3 directory
+Ci sono 0 link
+Ci sono 0 fifo
+Ci sono 0 socket
+Ci sono 0 device a caratteri
+Ci sono 0 device a blocchi
+Totale 71 file, per 489831 byte
+\end{verbatim}%$
+ed un rapido calcolo (ad esempio con \code{ls -a | wc} per contare i file) ci
+permette di verificare che il totale dei file è giusto. Un controllo con
+\cmd{ipcs} ci permette inoltre di verificare la presenza di un segmento di
+memoria condivisa e di un semaforo:
+\begin{verbatim}
+[piccardi@gont sources]$ ipcs
+------ Shared Memory Segments --------
+key shmid owner perms bytes nattch status
+0xffffffff 54067205 piccardi 666 4096 1
-Verifichiamo allora il funzionamento del nostro programma
+------ Semaphore Arrays --------
+key semid owner perms nsems
+0xffffffff 229376 piccardi 666 1
+------ Message Queues --------
+key msqid owner perms used-bytes messages
+\end{verbatim}%$
+
+Se a questo punto aggiungiamo un file, ad esempio con \code{touch prova},
+potremo verificare (passati nel peggiore dei casi almeno 10 secondi, cioè
+l'intervallo scelto per la rilettura dei dati), che:
+\begin{verbatim}
+[piccardi@gont sources]$ ./readmon
+Ci sono 69 file dati
+Ci sono 3 directory
+Ci sono 0 link
+Ci sono 0 fifo
+Ci sono 0 socket
+Ci sono 0 device a caratteri
+Ci sono 0 device a blocchi
+Totale 72 file, per 489887 byte
+\end{verbatim}%$
+
+Infine potremo terminare il server con il comando \code{killall dirmonitor},
+nel qual caso, ripetendo la lettura otterremo che:
+\begin{verbatim}
+[piccardi@gont sources]$ ./readmon
+Cannot find shared memory: No such file or directory
+\end{verbatim}%$
+e potremo verificare che anche gli oggetti di intercomunicazion e sono stati
+cancellati:
+\begin{verbatim}
+[piccardi@gont sources]$ ipcs
+------ Shared Memory Segments --------
+key shmid owner perms bytes nattch status
+
+------ Semaphore Arrays --------
+key semid owner perms nsems
+
+------ Message Queues --------
+key msqid owner perms used-bytes messages
+\end{verbatim}%$
terzo valore possibile, \const{F\_RDLCK}, dato che la nostra interfaccia usa
solo i write lock. Però è sempre possibile che siano richiesti altri lock
sul file al di fuori dell'interfaccia, nel qual caso si potranno avere,
- ovviamente, interferenze indesiderate.} ) in caso di successo, ed indicare
-che il mutex è, rispettivamente libero o occupato.
-
-
+ ovviamente, interferenze indesiderate.} in caso di successo, ad indicare che
+il mutex è, rispettivamente, libero o occupato.
-Basandosi sulla semantica dei file lock POSIX valgono tutte le precisazioni
+Basandosi sulla semantica dei file lock POSIX valgono tutte le considerazioni
relative al comportamento di questi ultimi fatte in
-\secref{sec:file_posix_lock}; questo significa che, al contrario di quanto
-avveniva con l'altra interfaccia basata sui semafori, chiamate multiple a
+\secref{sec:file_posix_lock}; questo significa ad esempio che, al contrario di
+quanto avveniva con l'interfaccia basata sui semafori, chiamate multiple a
\func{UnlockMutex} o \func{LockMutex} non hanno nessun inconveniente.