Messi gli esempi nel testo e usata daemon dove serve nei server
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index bf63e66f9e4355888f84f31e246b793f46cf5ea7..6f69e46880c4c747a2c4843720657e6e36606658 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -349,7 +349,7 @@ 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 \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 è:
@@ -600,7 +600,7 @@ int main(int argc, char *argv[])
 {
 /* 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;
@@ -617,6 +617,7 @@ int main(int argc, char *argv[])
             exit(1);
         }
     }
+    daemon(0, 0);
     /* open fifo two times to avoid EOF */
     fifo_server = open(fifoname, O_RDONLY);
     if (fifo_server < 0) {
@@ -676,41 +677,45 @@ qualora si riscontri un errore il server uscir
 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.
@@ -719,9 +724,9 @@ richiesta dalla fifo nota (che a questo punto si bloccher
 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
@@ -802,6 +807,62 @@ la richiesta, se non si fosse fatto cos
 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
@@ -2575,19 +2636,20 @@ 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 \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}
 
@@ -2967,9 +3029,6 @@ video; al solito il codice completo si trova con i sorgenti allegati nel file
   \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;    
@@ -2981,8 +3040,7 @@ struct DirProp {
     int tot_block;   
     int tot_char;    
     int tot_sock;
-};
-struct DirProp *shmptr;
+} *shmptr;
 int shmid; 
 int mutex;
 /* main body */
@@ -2995,11 +3053,13 @@ int main(int argc, char *argv[])
         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");
@@ -3007,12 +3067,14 @@ int main(int argc, char *argv[])
     }
     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 */
@@ -3028,54 +3090,78 @@ int main(int argc, char *argv[])
   \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 comandoche 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;
@@ -3085,15 +3171,13 @@ int ComputeValues(struct dirent * direntry)
     if (S_ISREG(data.st_mode)) shmptr->tot_regular++;
     if (S_ISFIFO(data.st_mode)) shmptr->tot_fifo++;
     if (S_ISLNK(data.st_mode)) shmptr->tot_link++;
-    if (S_ISDIR(data.st_mode)) shmptr->tot_dir;
-    if (S_ISBLK(data.st_mode)) shmptr->tot_block;
-    if (S_ISCHR(data.st_mode)) shmptr->tot_char;
-    if (S_ISSOCK(data.st_mode)) shmptr->tot_sock;
+    if (S_ISDIR(data.st_mode)) shmptr->tot_dir++;
+    if (S_ISBLK(data.st_mode)) shmptr->tot_block++;
+    if (S_ISCHR(data.st_mode)) shmptr->tot_char++;
+    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)) {
@@ -3121,56 +3205,43 @@ 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 \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");
@@ -3186,8 +3257,6 @@ int main(int argc, char *argv[])
     }
     /* main loop */
     MutexLock(mutex);                                  /* lock shared memory */
-    printf("File presenti %d file, per un totale di %d byte\n",
-           shmptr->tot_files, shmptr->tot_size);
     printf("Ci sono %d file dati\n", shmptr->tot_regular);
     printf("Ci sono %d directory\n", shmptr->tot_dir);
     printf("Ci sono %d link\n", shmptr->tot_link);
@@ -3195,30 +3264,118 @@ int main(int argc, char *argv[])
     printf("Ci sono %d socket\n", shmptr->tot_sock);
     printf("Ci sono %d device a caratteri\n", shmptr->tot_char);
     printf("Ci sono %d device a blocchi\n", shmptr->tot_block);
+    printf("Totale  %d file, per %d byte\n",
+           shmptr->tot_files, shmptr->tot_size);
     MutexUnlock(mutex);                              /* unlock 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                       
+
+------ 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}%$
+
 
 
 %% Per capire meglio il funzionamento delle funzioni facciamo ancora una volta
@@ -3364,46 +3521,40 @@ disponibile.\index{file!di lock|)}
 \subsection{La sincronizzazione con il \textit{file locking}}
 \label{sec:ipc_lock_file}
 
-Dato che i file di lock presentano gli inconvenienti illustrati in precedenza,
-la tecnica alternativa di sincronizzazione più comune è quella di fare ricorso
-al \textit{file locking}\index{file!locking} (trattato in
-\secref{sec:file_locking}) usando \func{fcntl} su un file creato per
-l'occasione per ottenere un write lock. In questo modo potremo usare il lock
-come un \textit{mutex}: per bloccare la risorsa basterà acquisire il lock, per
-sbloccarla basterà rilasciare il lock; una richiesta fatta con un write lock
-metterà automaticamente il processo in stato di attesa, senza necessità di
-ricorrere al \textit{polling}\index{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.
+Dato che i file di lock\index{file!di lock} presentano gli inconvenienti
+illustrati in precedenza, la tecnica alternativa di sincronizzazione più
+comune è quella di fare ricorso al \textit{file locking}\index{file!locking}
+(trattato in \secref{sec:file_locking}) usando \func{fcntl} su un file creato
+per l'occasione per ottenere un write lock. In questo modo potremo usare il
+lock come un \textit{mutex}: per bloccare la risorsa basterà acquisire il
+lock, per sbloccarla basterà rilasciare il lock. Una richiesta fatta con un
+write lock metterà automaticamente il processo in stato di attesa, senza
+necessità di ricorrere al \textit{polling}\index{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
-non consuma risorse permanentemente allocate nel sistema, lo svantaggio è che
-dovendo fare ricorso a delle operazioni sul filesystem esso è in genere
+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.
 
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
     \begin{lstlisting}{} 
-/*
- * Function CreateMutex: Create a mutex using file locking.  
- */
+/* Function CreateMutex: Create a mutex using file locking. */
 int CreateMutex(const char *path_name)
 {
     return open(path_name, O_EXCL|O_CREAT);
 }
-/*
- * Function UnlockMutex: unlock a file.  
- */
+/* Function UnlockMutex: unlock a file. */
 int FindMutex(const char *path_name)
 {
     return open(path_name, O_RDWR);
 }
-/*
- * Function LockMutex: lock mutex using file locking.
- */
+/* Function LockMutex: lock mutex using file locking. */
 int LockMutex(int fd)
 {
     struct flock lock;                                /* file lock structure */
@@ -3416,9 +3567,7 @@ int LockMutex(int fd)
     /* do locking */
     return fcntl(fd, F_SETLKW, &lock);
 }
-/*
- * Function UnlockMutex: unlock a file.  
- */
+/* Function UnlockMutex: unlock a file. */
 int UnlockMutex(int fd)
 {
     struct flock lock;                                /* file lock structure */
@@ -3430,16 +3579,12 @@ int UnlockMutex(int fd)
     /* do locking */
     return fcntl(fd, F_SETLK, &lock);
 }
-/*
- * Function RemoveMutex: remove a mutex (unlinking the lock file).
- */
+/* Function RemoveMutex: remove a mutex (unlinking the lock file). */
 int RemoveMutex(const char *path_name)
 {
     return unlink(path_name);
 }
-/*
- * Function ReadMutex: read a mutex status.
- */
+/* Function ReadMutex: read a mutex status. */
 int ReadMutex(int fd)
 {
     int res;
@@ -3458,34 +3603,79 @@ int ReadMutex(int fd)
     \end{lstlisting}
   \end{minipage} 
   \normalsize 
-  \caption{Il codice delle funzioni che permettono di creare un
-    \textit{mutex} utilizzando il file locking\index{file!locking}.}
+  \caption{Il codice delle funzioni che permettono per la gestione dei 
+    \textit{mutex} con il file locking\index{file!locking}.}
   \label{fig:ipc_flock_mutex}
 \end{figure}
 
-Il codice per implementare un mutex utilizzando il file
-locking\index{file!locking} è riportato in \figref{fig:ipc_flock_mutex}; a
-differenza del precedente caso in cui si sono usati i semafori le funzioni
-questa volta sono sufficienti due funzioni, \func{LockMutex} e
-\func{UnlockMutex}, usate rispettivamente per acquisire e rilasciare il mutex.
-
-La prima funzione (\texttt{\small 1--22}) serve per acquisire il mutex.
-Anzitutto si apre (\texttt{\small 9--11}), creandolo se non esiste, il file
-specificato dall'argomento \param{pathname}. In caso di errore si ritorna
-immediatamente, altrimenti si prosegue impostando (\texttt{\small 12--16}) la
-struttura \var{lock} in modo da poter acquisire un write lock sul file.
-Infine si richiede (\texttt{\small 17--20}) il file lock (restituendo il
-codice di ritorno di \func{fcntl} caso di errore). Se il file è libero il lock
-è acquisito e la funzione ritorna immediatamente; altrimenti \func{fcntl} si
-bloccherà (si noti che la si è chiamata con \func{F\_SETLKW}) fino al rilascio
-del lock.
-
-La seconda funzione (\texttt{\small 23--44}) serve a rilasciare il mutex. Di
-nuovo si apre (\texttt{\small 30--33}) il file specificato dall'argomento
-\param{pathname} (che stavolta deve esistere), ritornando immediatamente in
-caso di errore. Poi si passa ad inizializzare (\texttt{\small 34--38}) la
-struttura \var{lock} per il rilascio del lock, che viene effettuato
-(\texttt{\small 39--42}) subito dopo.
+Il codice delle varie funzioni usate per implementare un mutex utilizzando il
+file locking\index{file!locking} è riportato in \figref{fig:ipc_flock_mutex};
+si è mantenuta volutamente una struttura analoga alle precedenti funzioni che
+usano i semafori, anche se le due interfacce non possono essere completamente
+equivalenti, specie per quanto riguarda la rimozione del mutex.
+
+La prima funzione (\texttt{\small 1--5}) è \func{CreateMutex}, e serve a
+creare il mutex; la funzione è estremamente semplice, e si limita
+(\texttt{\small 4}) a creare, con una opportuna chiamata ad \func{open}, il
+file che sarà usato per il successivo file locking, assicurandosi che non
+esista già (nel qual caso segnala un errore); poi restituisce il file
+descriptor che sarà usato dalle altre funzioni per acquisire e rilasciare il
+mutex.
+
+La seconda funzione (\texttt{\small 6--10}) è \func{FindMutex}, che, come la
+precedente, è stata definita per mantenere una analogia con la corrispondente
+funzione basata sui semafori. Anch'essa si limita (\texttt{\small 9}) ad
+aprire il file da usare per il file locking, solo che in questo caso le
+opzioni di \func{open} sono tali che il file in questione deve esistere di
+già.
+
+La terza funzione (\texttt{\small 11--23}) è \func{LockMutex} e serve per
+acquisire il mutex. La funzione definisce (\texttt{\small 14}) e inizializza
+(\texttt{\small 17--20}) la struttura \var{lock} da usare per acquisire un
+write lock sul file, che poi (\texttt{\small 21}) viene richiesto con
+\func{fcntl}, restituendo il valore di ritorno di quest'ultima. Se il file è
+libero il lock viene acquisito e la funzione ritorna immediatamente;
+altrimenti \func{fcntl} si bloccherà (si noti che la si è chiamata con
+\func{F\_SETLKW}) fino al rilascio del lock.
+
+La quarta funzione (\texttt{\small 24--35}) è \func{UnlockMutex} e serve a
+rilasciare il mutex. La funzione è analoga alla precedente, solo che in questo
+caso si inizializza (\texttt{\small 29--32}) la struttura \var{lock} per il
+rilascio del lock, che viene effettuato (\texttt{\small 34}) con la opportuna
+chiamata a \func{fcntl}. Avendo usato il file locking in semantica POSIX (si
+riveda quanto detto \secref{sec:file_posix_lock}) solo il processo che ha
+precedentemente eseguito il lock può sbloccare il mutex.
+
+La quinta funzione (\texttt{\small 36--40}) è \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 39}) il file con una chiamata ad \func{unlink}. Si noti che in
+questo caso la funzione non ha effetto sui mutex già ottenuti con precedenti
+chiamate a \func{FindMutex} o \func{CreateMutex}, che continueranno ad essere
+disponibili fintanto che i relativi file descriptor restano aperti. Pertanto
+per rilasciare un mutex occorrerà prima chiamare \func{UnlockMutex} oppure
+chiudere il file usato per il lock.
+
+La sesta funzione (\texttt{\small 41--56}) è \func{ReadMutex} e serve a
+leggere lo stato del mutex. In questo caso si prepara (\texttt{\small 47--50})
+la solita struttura \var{lock} come l'acquisizione del lock, ma si effettua
+(\texttt{\small 52}) la chiamata a \func{fcntl} usando il comando
+\const{F\_GETLK} per ottenere lo stato del lock, e si restituisce
+(\texttt{\small 53}) il valore di ritorno in caso di errore, ed il valore del
+campo \var{l\_type} (che descrive lo stato del lock) altrimenti. Per questo
+motivo la funzione restituirà -1 in caso di 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 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, 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
+\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.
 
 
 \subsection{Il \textit{memory mapping} anonimo}