X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=3151c403163487de2b3766617e6253c03baa721b;hp=c7aa4fcafc093db1c2a8a8738a52d98a9a95548f;hb=b8248eaf35d824e8816c76ad9f9561c76d67b915;hpb=e18f3ea57b725bc148f0d3443e384bf5270b2b9f diff --git a/ipc.tex b/ipc.tex index c7aa4fc..3151c40 100644 --- a/ipc.tex +++ b/ipc.tex @@ -2940,23 +2940,210 @@ sequenziale\footnote{come accennato in \secref{sec:ipc_sysv_mq} per la modalità predefinita. Un esempio classico di uso della memoria condivisa è quello del -``\textit{monitor}'', in cui essa viene per scambiare informazioni fra un -processo server che vi scrive dei dati di interesse generale che ha -ottenuto, e tutti i processi client interessati agli stessi dati che così -possono leggerli in 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 al processo server di dover gestire l'invio a tutti -i client di tutti i dati (non potendo il server sapere quali di essi servono -effettivamente al singolo client). +``\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 +processi client interessati agli stessi dati che così possono leggerli in +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 +al processo server di dover gestire l'invio a tutti i client di tutti i dati +(non potendo il server sapere quali di essi servono effettivamente al singolo +client). Nel nostro caso implementeremo un ``\textsl{monitor}'' di una directory: un processo si incaricherà di tenere sotto controllo alcuni parametri relativi ad -una directory (il numero dei file contenuti, la dimensione totale, 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. + +In \figref{fig:ipc_dirmonitor_main} si è riportata la sezione principale del +corpo del programma server, insieme alle definizioni delle altre funzioni +usate nel programma e delle variabili globali, omettendo tutto quello che +riguarda la gestione delle opzioni e la stampa delle istruzioni di uso a +video; al solito il codice completo si trova con i sorgenti allegati nel file +\file{DirMonitor.c}. + +\begin{figure}[!htb] + \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_files; + int tot_regular; + int tot_fifo; + int tot_link; + int tot_dir; + int tot_block; + int tot_char; + int tot_sock; +}; +struct DirProp *shmptr; +int shmid; +int mutex; +/* main body */ +int main(int argc, char *argv[]) +{ + int i; + key_t key; + ... + if ((argc - optind) != 1) { /* There must be remaing parameters */ + printf("Wrong number of arguments %d\n", argc - optind); + usage(); + } + 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 */ + shmid = shmget(key, 4096, IPC_CREAT|0666); /* get a shared memory */ + if (shmid < 0) { + perror("Cannot create shared memory"); + exit(1); + } + if ( (shmptr = shmat(shmid, NULL, 0)) == NULL ) { /* attach to process */ + perror("Cannot attach segment"); + } + if ((mutex = MutexCreate(key)) == -1) { /* get a Mutex */ + perror("Cannot create mutex"); + exit(1); + } + /* main loop, monitor directory properties each 10 sec */ + while (1) { + MutexLock(mutex); /* lock shared memory */ + memset(shmptr, 0, sizeof(struct DirProp)); /* erase previous data */ + DirScan(argv[1], ComputeValues); /* execute scan */ + MutexUnlock(mutex); /* unlock shared memory */ + sleep(pause); /* sleep until next watch */ + } +} + \end{lstlisting} + \end{minipage} + \normalsize + \caption{Codice della funzione principale del programma \file{DirMonitor.c}.} + \label{fig:ipc_dirmonitor_main} +\end{figure} + +Il programma usa delle variabili globali (\texttt{\small 4--18}) per mantenere +i valori relativi agli oggetti usati per la comunicazione inter-processo; si è +definita inoltre una apposita struttura \struct{DirProp} che contiene i dati +relativi alle proprietà che si vogliono mantenere nella memoria condivisa, per +l'accesso da parte dei client. + +Il programma, dopo la sezione, omessa, relativa alla gestione delle opzioni da +riga di comando, che si limitano alla eventuale stampa di un messaggio di +aiuto a video ed all'impostazione della durata dell'intervallo con cui viene +ripetuto il calcolo delle proprietà della directory, controlla (\texttt{\small + 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, che utilizzaremo 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}. +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \begin{lstlisting}{} +... +/* + * Routine to print file name and size 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 inoltre (\texttt{\small + 23--35}) il codice del gestore di segnali usato per terminare il programma, +che si incarica di cancellare tutti gli oggetti non più necessari. + +Anzitutto (\texttt{\small 24}) si acquisisce il mutex per evitare di operare +mentre un client sta ancora leggendo i dati, dopo di che si distacca +(\texttt{\small 25--28}) il segmento e lo si cancella (\texttt{\small + 29--32}). Infine (\texttt{\small 33}) si rimuove il mutex e si esce. %% Per capire meglio il funzionamento delle funzioni facciamo ancora una volta @@ -2981,9 +3168,9 @@ potranno accedere per ricavare la parte di informazione che interessa. Come abbiamo detto in \secref{sec:ipc_sysv_generic}, e ripreso nella 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 sono già stati accennati in precedenza) ed elenca alcune possibili -tecniche alternative, che vogliamo riprendere in questa sezione. + capitolo 14.} Stevens ne effettua una accurata analisi (alcuni dei concetti +sono già stati accennati in precedenza) ed elenca alcune possibili tecniche +alternative, che vogliamo riprendere in questa sezione. \subsection{Alternative alle code di messaggi} @@ -3064,7 +3251,6 @@ int UnlockFile(const char* path_name) { return unlink(path_name); } - \end{lstlisting} \end{minipage} \normalsize @@ -3101,6 +3287,7 @@ pi accedere alla seriale si limita a segnalare che la risorsa non è disponibile.\index{file!di lock|)} + \subsection{La sincronizzazione con il \textit{file locking}} \label{sec:ipc_lock_file}