X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=ipc.tex;h=6cb8cc482a4bdbd2811d480609a84c2f882b8854;hp=61eb8a076585b97d43cce044756ee03c90dfdbe4;hb=e77571fc3b2e3083b4f819a9626d2be454456fab;hpb=305928c5c349fa8fd0131dcf5a095e98c610e6bb diff --git a/ipc.tex b/ipc.tex index 61eb8a0..6cb8cc4 100644 --- a/ipc.tex +++ b/ipc.tex @@ -150,7 +150,7 @@ possa reinviarlo al browser che ha effettuato la richiesta, che in questo modo è in grado di visualizzarlo opportunamente. Per realizzare quanto voluto useremo in sequenza i programmi \cmd{barcode} e -\cmd{gs}, il primo infatti è in grado di generare immagini postscript di +\cmd{gs}, il primo infatti è in grado di generare immagini PostScript di 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 @@ -259,7 +259,7 @@ richiesta.\footnote{la funzione \func{WriteMess} non 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 +caratteri, la converte nell'immagine PostScript del codice a barre ad essa corrispondente, e poi scrive il risultato direttamente sullo standard output. Per poter utilizzare queste caratteristiche prima di eseguire \cmd{barcode} si @@ -268,7 +268,7 @@ ne collega (\texttt{\small 21}) il capo in lettura allo standard input, usando \func{dup2}. Si ricordi che invocando \func{dup2} il secondo file, qualora risulti aperto, viene, come nel caso corrente, chiuso prima di effettuare la duplicazione. Allo stesso modo, dato che \cmd{barcode} scrive l'immagine -postscript del codice a barre sullo standard output, per poter effettuare una +PostScript del codice a barre sullo standard output, per poter effettuare una ulteriore redirezione il capo in lettura della seconda pipe viene chiuso (\texttt{\small 22}) mentre il capo in scrittura viene collegato allo standard output (\texttt{\small 23}). @@ -276,7 +276,7 @@ output (\texttt{\small 23}). 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. +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 @@ -287,11 +287,11 @@ definitivamente chiusa (\texttt{\small 28}), si attende poi (\texttt{\small 29}) che l'esecuzione di \cmd{barcode} sia completata. Alla conclusione della sua esecuzione \cmd{barcode} avrà inviato l'immagine -postscript del codice a barre sul capo in scrittura della seconda pipe; a +PostScript del codice a barre sul capo in scrittura della seconda pipe; a questo punto si può eseguire la seconda conversione, da PS a JPEG, usando il programma \cmd{gs}. Per questo si crea (\texttt{\small 30--34}) un secondo processo figlio, che poi (\texttt{\small 35--42}) eseguirà questo programma -leggendo l'immagine postscript creata da \cmd{barcode} dallo standard input, +leggendo l'immagine PostScript creata da \cmd{barcode} dallo standard input, per convertirla in JPEG. Per fare tutto ciò anzitutto si chiude (\texttt{\small 37}) il capo in @@ -372,8 +372,8 @@ precedente: il programma mostrato in \figref{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 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 +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 @@ -436,7 +436,7 @@ int main(int argc, char *argv[], char *envp[]) }; char content[]="Content-type: image/png\n\n"; int i; - /* write mime-type to stout */ + /* write mime-type to stdout */ write(STDOUT_FILENO, content, strlen(content)); /* execute chain of command */ for (i=0; i<4; i++) { @@ -1133,7 +1133,7 @@ Il sistema dispone sempre di un numero fisso di oggetti di IPC,\footnote{fino kernel, andando a modificarne la definizione nei relativi header file. A partire dal kernel 2.4.x è possibile cambiare questi valori a sistema attivo scrivendo sui file \file{shmmni}, \file{msgmni} e \file{sem} di - \file{/proc/sys/kernel} o con l'uso di \texttt{syscntl}.} e per ciascuno 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 l'oggetto viene creato usando uno spazio che era già stato utilizzato in @@ -1323,7 +1323,7 @@ coda. Le code di messaggi sono caratterizzate da tre limiti fondamentali, definiti negli header e corrispondenti alle prime tre costanti riportate in \tabref{tab:ipc_msg_limits}, come accennato però in Linux è possibile -modificare questi limiti attraverso l'uso di \func{syscntl} o scrivendo nei +modificare questi limiti attraverso l'uso di \func{sysctl} o scrivendo nei file \file{msgmax}, \file{msgmnb} e \file{msgmni} di \file{/proc/sys/kernel/}. @@ -1371,13 +1371,13 @@ struct msqid_ds { \end{lstlisting} \end{minipage} \normalsize - \caption{La struttura \structd{msgid\_ds}, associata a ciascuna coda di + \caption{La struttura \structd{msqid\_ds}, associata a ciascuna coda di messaggi.} - \label{fig:ipc_msgid_ds} + \label{fig:ipc_msqid_ds} \end{figure} A ciascuna coda è associata una struttura \struct{msgid\_ds}, la cui -definizione, è riportata in \secref{fig:ipc_msgid_ds}. In questa struttura il +definizione, è riportata in \secref{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, essa viene usata nei kernel della serie 2.4.x solo per compatibilità in @@ -1385,7 +1385,7 @@ coda.\footnote{come accennato questo vale fino ai kernel della serie 2.2.x, sia una differenza con i campi mostrati nello schema di \figref{fig:ipc_mq_schema} che sono presi dalla definizione di \file{linux/msg.h}, e fanno riferimento alla definizione della omonima - struttura usata nel kernel.} In \figref{fig:ipc_msgid_ds} sono elencati i + struttura usata nel kernel.} In \figref{fig:ipc_msqid_ds} sono elencati i campi significativi definiti in \file{sys/msg.h}, a cui si sono aggiunti gli ultimi tre campi che sono previsti dalla implementazione originale di System V, ma non dallo standard Unix98. @@ -2471,9 +2471,7 @@ nullo per segnalarne l'indisponibilit \footnotesize \centering \begin{minipage}[c]{15cm} \begin{lstlisting}{} -/* - * Function MutexCreate: create a mutex/semaphore - */ +/* Function MutexCreate: create a mutex/semaphore */ int MutexCreate(key_t ipc_key) { const union semun semunion={1}; /* semaphore union structure */ @@ -2488,23 +2486,17 @@ int MutexCreate(key_t ipc_key) } return sem_id; } -/* - * Function MutexFind: get the semaphore/mutex Id given the IPC key value - */ +/* Function MutexFind: get the semaphore/mutex Id given the IPC key value */ int MutexFind(key_t ipc_key) { return semget(ipc_key,1,0); } -/* - * Function MutexRead: read the current value of the mutex/semaphore - */ +/* Function MutexRead: read the current value of the mutex/semaphore */ int MutexRead(int sem_id) { return semctl(sem_id, 0, GETVAL); } -/* - * Define sembuf structures to lock and unlock the semaphore - */ +/* Define sembuf structures to lock and unlock the semaphore */ struct sembuf sem_lock={ /* to lock semaphore */ 0, /* semaphore number (only one so 0) */ -1, /* operation (-1 to use resource) */ @@ -2513,19 +2505,20 @@ struct sembuf sem_ulock={ /* to unlock semaphore */ 0, /* semaphore number (only one so 0) */ 1, /* operation (1 to release resource) */ SEM_UNDO}; /* flag (in this case 0) */ -/* - * Function MutexLock: to lock a mutex/semaphore - */ +/* Function MutexLock: to lock a mutex/semaphore */ int MutexLock(int sem_id) { return semop(sem_id, &sem_lock, 1); } -/* - * Function MutexUnlock: to unlock a mutex/semaphore - */ +/* Function MutexUnlock: to unlock a mutex/semaphore */ int MutexUnlock(int sem_id) { return semop(sem_id, &sem_ulock, 1); +} +/* Function MutexRemove: remove a mutex/semaphore */ +int MutexRemove(int sem_id) +{ + return semctl(sem_id, 0, IPC_RMID); } \end{lstlisting} \end{minipage} @@ -2535,44 +2528,49 @@ int MutexUnlock(int sem_id) \label{fig:ipc_mutex_create} \end{figure} -La prima funzione (\texttt{\small 1--17}) è \func{MutexCreate} che data una +La prima funzione (\texttt{\small 2--15}) è \func{MutexCreate} che data una chiave crea il semaforo usato per il mutex e lo inizializza, restituendone -l'identificatore. Il primo passo (\texttt{\small 8}) è chiamare \func{semget} +l'identificatore. Il primo passo (\texttt{\small 6}) è chiamare \func{semget} 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 9--11}) si ritorna subito il risultato di \func{semget}, -altrimenti (\texttt{\small 12}) si inizializza il semaforo chiamando +(\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 6}) +\struct{semunion} dichiarata ed avvalorata in precedenza (\texttt{\small 4}) ad 1 per significare che risorsa è libera. In caso di errore (\texttt{\small - 13--16}) si restituisce il valore di ritorno di \func{semctl}, altrimenti 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. -La seconda funzione (\texttt{\small 18--24}) è \func{MutexFind}, che data una +La seconda funzione (\texttt{\small 17--20}) è \func{MutexFind}, che, data una chiave, restituisce l'identificatore del semaforo ad essa associato. La -comprensione del suo funzionamento è immediata in quanto è solo un +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 - stesse funzionalità.} di \func{semget} per cercare l'identificatore -associato alla chiave, restituendo direttamente il valore di ritorno della -funzione. + stesse funzionalità.} di una chiamata a \func{semget} per cercare +l'identificatore associato alla chiave, il valore di ritorno di quest'ultima +viene passato all'indietro al chiamante. -La terza funzione (\texttt{\small 25--31}) è \func{MutexRead} che, dato -l'identificatore, restituisce il valore del mutex. Anche in questo caso la -funzione è un \textit{wrapper} per la chiamata di \func{semctl}, questa volta -con il comando \const{GETVAL}, che permette di restituire il valore del -semaforo. +La terza funzione (\texttt{\small 22--25}) è \func{MutexRead} che, dato un +identificatore, restituisce il valore del semaforo associato al mutex. Anche +in questo caso la funzione è un \textit{wrapper} per una chiamata a +\func{semctl} con il comando \const{GETVAL}, che permette di restituire il +valore del semaforo. -La quarta e la quinta funzione (\texttt{\small 43--56}) sono \func{MutexLock}, +La quarta e la quinta funzione (\texttt{\small 36--44}) sono \func{MutexLock}, e \func{MutexUnlock}, che permettono rispettivamente di bloccare e sbloccare il mutex. Entrambe fanno da wrapper per \func{semop}, utilizzando le due strutture \var{sem\_lock} e \var{sem\_unlock} definite in precedenza -(\texttt{\small 32--42}). Si noti come per queste ultime si sia fatto uso +(\texttt{\small 27--34}). Si noti come per queste ultime si sia fatto uso dell'opzione \const{SEM\_UNDO} per evitare che il semaforo resti bloccato in caso di terminazione imprevista del processo. +L'ultima funzione (\texttt{\small 46--49}) della serie, è \func{MutexRemove}, +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 +smemaforo; 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 @@ -2584,8 +2582,9 @@ crescerebbe oltre 1, e \func{MutexLock} non avrebbe pi (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. -Vedremo in \secref{sec:ipc_posix_sem} come è possibile ottenere un'interfaccia -analoga senza questo problemi usando il file locking\index{file!locking}. +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}. @@ -3056,7 +3055,7 @@ 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 -intrfaccia già descritte in \secref{sec:ipc_sysv_sem}) che utilizzaremo per +interfaccia già descritte in \secref{sec:ipc_sysv_sem}) che utilizzeremo per regolare l'accesso alla memoria condivisa. Una volta completata l'inizializzazione e la creazione degli oggetti di @@ -3075,7 +3074,7 @@ tempo specificato a riga di comando con l'opzione \code{-p}. \begin{lstlisting}{} ... /* - * Routine to print file name and size inside DirScan + * Routine to compute directory properties inside DirScan */ int ComputeValues(struct dirent * direntry) { @@ -3194,7 +3193,7 @@ int main(int argc, char *argv[]) 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 carrateri\n", shmptr->tot_char); + 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 */ } @@ -3212,7 +3211,7 @@ memoria condivisa (che in questo caso deve gi 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 -richede pure l'identificatore del mutex. +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 @@ -3268,8 +3267,6 @@ diversa con un uso combinato della memoria condivisa e dei meccanismi di sincronizzazione, per cui alla fine l'uso delle code di messaggi classiche è relativamente poco diffuso. - - \subsection{I \textsl{file di lock}} \label{sec:ipc_file_lock} @@ -3349,13 +3346,13 @@ solo se si opera all'interno di uno stesso filesystem. Un generale comunque l'uso di un \textsl{file di lock} presenta parecchi problemi, che non lo rendono una alternativa praticabile per la -sincronizzazione: anzitutto anche in questo caso, 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 -\textit{polling}\index{polling}, ed è quindi molto inefficiente. +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 \textit{polling}\index{polling}, +ed è quindi molto inefficiente. -La tecnica dei file di lock non di meno ha una sua utilità, e può essere usata +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 usa spesso per evitare interferenze sull'uso delle porte seriali da parte di @@ -3368,16 +3365,16 @@ disponibile.\index{file!di lock|)} \label{sec:ipc_lock_file} Dato che i file di lock presentano gli inconvenienti illustrati in precedenza, -la tecnica alternativa 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. +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 @@ -3390,49 +3387,61 @@ leggermente pi \footnotesize \centering \begin{minipage}[c]{15cm} \begin{lstlisting}{} -/* - * Function LockMutex: lock a file (creating it if not existent). - */ -int LockMutex(const char *path_name) +/* 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. */ +int FindMutex(const char *path_name) +{ + return open(path_name, O_RDWR); +} +/* Function LockMutex: lock mutex using file locking. */ +int LockMutex(int fd) { - int fd, res; struct flock lock; /* file lock structure */ /* first open the file (creating it if not existent) */ - if ( (fd = open(path_name, O_EXCL|O_CREAT)) < 0) { /* first open file */ - return fd; - } /* set flock structure */ lock.l_type = F_WRLCK; /* set type: read or write */ lock.l_whence = SEEK_SET; /* start from the beginning of the file */ lock.l_start = 0; /* set the start of the locked region */ lock.l_len = 0; /* set the length of the locked region */ /* do locking */ - if ( (res = fcntl(fd, F_SETLKW, &lock)) < 0 ) { - return res; - } - return 0; + return fcntl(fd, F_SETLKW, &lock); } -/* - * Function UnLockMutex: unlock a file. - */ -int UnlockMutex(const char *path_name) +/* Function UnlockMutex: unlock a file. */ +int UnlockMutex(int fd) { - int fd, res; struct flock lock; /* file lock structure */ - /* first open the file */ - if ( (fd = open(path_name, O_RDWR)) < 0) { /* first open file */ - return fd; - } /* set flock structure */ lock.l_type = F_UNLCK; /* set type: unlock */ lock.l_whence = SEEK_SET; /* start from the beginning of the file */ lock.l_start = 0; /* set the start of the locked region */ lock.l_len = 0; /* set the length of the locked region */ /* do locking */ - if ( (res = fcntl(fd, F_SETLK, &lock)) < 0 ) { + return fcntl(fd, F_SETLK, &lock); +} +/* 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. */ +int ReadMutex(int fd) +{ + int res; + struct flock lock; /* file lock structure */ + /* set flock structure */ + lock.l_type = F_WRLCK; /* set type: unlock */ + lock.l_whence = SEEK_SET; /* start from the beginning of the file */ + lock.l_start = 0; /* set the start of the locked region */ + lock.l_len = 0; /* set the length of the locked region */ + /* do locking */ + if ( (res = fcntl(fd, F_GETLK, &lock)) ) { return res; } - return 0; + return lock.l_type; } \end{lstlisting} \end{minipage} @@ -3442,11 +3451,14 @@ int UnlockMutex(const char *path_name) \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. +Il codice delle varie funzioni definite per implementare un mutex utilizzando +il file locking\index{file!locking} è riportato in +\figref{fig:ipc_flock_mutex}; si è mantenuta una struttura analoga a quelle +viste in precedenza, anche se le due interfacce non possono essere +completamente equivalenti, specie per quanto riguarda la rimozione del 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