+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \begin{lstlisting}{}
+...
+/*
+ * Routine to compute directory properties inside DirScan
+ */
+int ComputeValues(struct dirent * direntry)
+{
+ struct stat data;
+ stat(direntry->d_name, &data); /* get stat data */
+ shmptr->tot_size += data.st_size;
+ shmptr->tot_files++;
+ 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;
+ return 0;
+}
+/*
+ * Signal Handler to manage termination
+ */
+void HandSIGTERM(int signo) {
+ MutexLock(mutex);
+ if (shmdt(shmptr)) {
+ perror("Error detaching shared memory");
+ exit(1);
+ }
+ if (shmctl(shmid, IPC_RMID, NULL)) {
+ perror("Cannot remove shared memory segment");
+ exit(1);
+ }
+ MutexRemove(mutex);
+ exit(0);
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Codice delle funzione ausiliarie usate da \file{DirMonitor.c}.}
+ \label{fig:ipc_dirmonitor_sub}
+\end{figure}
+
+Si noti come per il calcolo dei valori da mantenere nella memoria condivisa si
+sia usata ancora una volta la funzione \func{DirScan}, già utilizzata (e
+descritta in dettaglio) in \secref{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 \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
+ciascuna voce, per ottenerne i dati, che poi utilizza per incrementare i vari
+contatori.
+
+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
+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}.
+
+\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 */
+ shmid = shmget(key, 4096, 0); /* get the shared memory ID */
+ if (shmid < 0) {
+ perror("Cannot find shared memory");
+ exit(1);
+ }
+ if ( (shmptr = shmat(shmid, NULL, 0)) == NULL ) { /* attach to process */
+ perror("Cannot attach segment");
+ exit(1);
+ }
+ if ((mutex = MutexFind(key)) == -1) { /* get the Mutex */
+ perror("Cannot find mutex");
+ exit(1);
+ }
+ /* 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);
+ printf("Ci sono %d fifo\n", shmptr->tot_fifo);
+ 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);
+ MutexUnlock(mutex); /* unlock shared memory */
+}
+ \end{lstlisting}
+ \end{minipage}
+ \normalsize
+ \caption{Codice del programma client \file{ReadMonitor.c}.}
+ \label{fig:ipc_dirmonitor_client}
+\end{figure}
+
+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.
+
+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.