From 2c87ecb104050dd0cd78865a5390d8635b989b1a Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Mon, 6 Jan 2003 21:24:41 +0000 Subject: [PATCH] Aggiunta funzione MurexRead, riscritti Mutex con il file locking --- ipc.tex | 171 +++++++++++++++++++++++++++--------------------- sources/Mutex.c | 86 ++++++++++++++++++------ 2 files changed, 162 insertions(+), 95 deletions(-) diff --git a/ipc.tex b/ipc.tex index bdf39a9..bf63e66 100644 --- a/ipc.tex +++ b/ipc.tex @@ -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}. @@ -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 @@ -3391,48 +3388,72 @@ leggermente pi \begin{minipage}[c]{15cm} \begin{lstlisting}{} /* - * Function LockMutex: lock a file (creating it if not existent). + * 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(const char *path_name) +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) +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} diff --git a/sources/Mutex.c b/sources/Mutex.c index 076c593..52991f5 100644 --- a/sources/Mutex.c +++ b/sources/Mutex.c @@ -22,7 +22,7 @@ * * Author: S. Piccardi Dec. 2002 * - * $Id: Mutex.c,v 1.4 2003/01/04 17:24:30 piccardi Exp $ + * $Id: Mutex.c,v 1.5 2003/01/06 21:24:41 piccardi Exp $ * *****************************************************************************/ #include /* IPC semaphore declarations */ @@ -130,52 +130,98 @@ int MutexRemove(int sem_id) * *****************************************************************************/ /* - * Function LockMutex: lock a file (creating it if not existent). + * Function CreateMutex: Create a mutex using file locking. + * + * Open a new lock file (creating it if not existent, and giving error + * otherwise). Is a simple wrapper for open. + * + * Input: a filename + * Output: a file descriptor (>0 OK, -1 KO) + */ +int CreateMutex(const char *path_name) +{ + return open(path_name, O_EXCL|O_CREAT); +} +/* + * Function UnlockMutex: unlock a file. + * + * Open a lock file (failing if not existent). Is a simple wrapper for + * open. * * Input: a filename + * Output: a return code (>0 OK, -1 KO) + */ +int FindMutex(const char *path_name) +{ + return open(path_name, O_RDWR); +} +/* + * Function LockMutex: lock mutex using file locking. + * + * Input: a mutex (i.e. a file descriptor) * Output: a return code (0 OK, -1 KO) */ -int LockMutex(const char *path_name) +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. * - * Input: a filename + * Input: a mutex (i.e. a file descriptor) * Output: a return code (0 OK, -1 KO) */ -int UnlockMutex(const char *path_name) +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). + * + * Just remove the lock file. + * + * Input: a filename + * Output: a return code (0 OK, -1 KO) + */ +int RemoveMutex(const char *path_name) +{ + return unlink(path_name); +} +/* + * Function ReadMutex: read a mutex status. + * + * Read the status for a mutex. + * + * Input: a mutex (i.e. a file descriptor) + * Output: the lock type (F_UNLCK, F_RDLCK or F_WRLCK, or -1 if KO) + */ +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; } -- 2.30.2