Aggiunta funzione MurexRead, riscritti Mutex con il file locking
authorSimone Piccardi <piccardi@gnulinux.it>
Mon, 6 Jan 2003 21:24:41 +0000 (21:24 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Mon, 6 Jan 2003 21:24:41 +0000 (21:24 +0000)
ipc.tex
sources/Mutex.c

diff --git a/ipc.tex b/ipc.tex
index bdf39a98adbc2484ebb977781ece42e459e21a36..bf63e66f9e4355888f84f31e246b793f46cf5ea7 100644 (file)
--- 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} 
index 076c59360c430c4efe973064b8ce7e45765cddfe..52991f53026f4a13e3ceec4fbca3a2f34bb78b95 100644 (file)
@@ -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 <sys/sem.h>     /* 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;
 }