\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 */
}
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) */
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}
\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
(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}.
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}
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
\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
\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}
*
* 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 */
*
*****************************************************************************/
/*
- * 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;
}