Completata la descrizione dell'esempio dei mutex realizzati con i semafori.
authorSimone Piccardi <piccardi@gnulinux.it>
Wed, 20 Nov 2002 23:34:02 +0000 (23:34 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Wed, 20 Nov 2002 23:34:02 +0000 (23:34 +0000)
biblio.bib
ipc.tex
sources/wrappers.h

index f30a1c250c05c4fb9d18f88a86919b147fb7e5cf..a258933bc3f1652842ee7243b1d334f4e2e431c2 100644 (file)
   OPTnote =     {},
   OPTannote =   {}
 }
+@Book{PratC,
+  author =      {S. Oullaine},
+  editor =      {O'Reilly},
+  title =       {Pratical C},
+  publisher =   {O'Reilly},
+  year =        {2002},
+  OPTkey =      {},
+  OPTvolume =   {},
+  OPTnumber =   {},
+  OPTseries =   {},
+  OPTaddress =          {},
+  OPTedition =          {2nd},
+  OPTmonth =    {},
+  OPTnote =     {},
+  OPTannote =   {}
+}
 @Book{glibc,
   author =      {Sandra Loosemore Richard M. Stallman Roland McGrath Andrew Oram and Ulrich Drepper},
   editor =      {Free Software Foundation},
diff --git a/ipc.tex b/ipc.tex
index 1060b49d15190a352d62cf3ed23acce734c7e64a..9dec79a907d64106343fb941ceac99990aed297b 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -2440,66 +2440,72 @@ ignorare silenziosamente le altre; questo per
 ripristino non è comunque garantito in tutte le occasioni.
 
 Come esempio di uso dell'interfaccia dei semafori vediamo come implementare
-con essa dei semplici \textit{mutex} (cioè semafori binari), tutte le funzioni
-relative sono definite come \ctyp{inline}\footnote{la direttiva \func{inline}
-  viene usata per dire al compilatore di non trattare la funzione cui essa fa
-  riferimento come una funzione, ma di inserire il codice direttamente nel
-  testo del programma. Anche se i compilatori più moderni sono in grado di
-  effettuare da soli queste manipolazioni (impostando le opportune
-  ottimizzazioni) questa è una tecnica usata per migliorare le prestazioni per
-  le funzioni piccole ed usate di frequente, in tal caso infatti le istruzioni
-  per creare un nuovo frame nello stack per chiamare la funzione
-  costituirebbero una parte rilevante del codice, appesantendo inutilmente il
-  programma. Originariamente questa era fatto utilizzando delle macro, ma
-  queste hanno tutta una serie di problemi di sintassi nel passaggio degli
-  argomenti (si veda ad esempio \cite[oullaine]) che in questo modo possono
-  essere evitati.} nel file \file{wrappers.h}. In
-\secref{fig:ipc_mutex_create} si è riportata la definizione delle due funzioni
-che permettono di acquisire il \textit{mutex}; la prima è \func{MutexCreate}
-che crea il semaforo usato per il mutex e lo inizializza, restituendone
-l'identificatore; la seconda è \func{MutexFind}, che data una chiave
-restitituisce l'identificatore del semaforo ad essa associato.
+con essa dei semplici \textit{mutex} (cioè semafori binari), tutto il codice
+in questione, contenuto nel file \file{wrappers.h} allegato ai sorgenti, è
+riportato in \figref{fig:ipc_mutex_create}. Utilizzeremo l'interfaccia per
+creare un insieme contenente un singolo semaforo, per il quale poi useremo un
+valore unitario per segnalare la disponibilità della risorsa, ed un valore
+nullo per segnalarne l'indisponibilità. 
 
 \begin{figure}[!bht]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
-    \begin{lstlisting}{}
+    \begin{lstlisting}{} 
 /*
- * Function MutexCreate:
- *
- * Input: an IPC key value (to create an unique semaphore)
- * Return: the semaphore id#
+ * Function MutexCreate: create a mutex/semaphore
  */
-const union semun semunion={1};    /* semaphore union structure */
 inline int MutexCreate(key_t ipc_key) 
 {
-    int sem_id;
-    if( (sem_id=semget(ipc_key,1,IPC_CREAT|0666))<0 ){ /* get sem ID */
-        perror("cannot create semaphore");     /* a sem_id <0 is an error */
-        printf("semid=%d",sem_id);
-        exit(1);
+    const union semun semunion={1};             /* semaphore union structure */
+    int sem_id, ret;
+    sem_id = semget(ipc_key, 1, IPC_CREAT|0666);         /* get semaphore ID */
+    if (sem_id == -1) {                              /* if error return code */
+        return sem_id;
     }
-    if ( (semctl(sem_id,0,SETVAL,semunion)) < 0 ) {
-        perror("cannot init semaphore");       /* <0 is an error */
-        printf("on semid=%d",sem_id);
-        exit(1);
+    ret = semctl(sem_id, 0, SETVAL, semunion);             /* init semaphore */
+    if (ret == -1) {
+        return ret;
     }
     return sem_id;
 }
 /*
- * Find Mutex
- * get the semaphore/mutex Id given the IPC key value
- *
- * Input: an IPC key value
+ * Function MutexFind: get the semaphore/mutex Id given the IPC key value
  */
 inline int MutexFind(key_t ipc_key) 
 {
-    int sem_id;
-    if( (sem_id=semget(ipc_key,1,0))<0 ){       /* find sem .ID */
-        perror("cannot find semaphore");
-        exit(1);
-    }
-    return sem_id;
+    return semget(ipc_key,1,0);
+}
+/*
+ * Function MutexRead: read the current value of the mutex/semaphore
+ */
+inline int MutexRead(int sem_id) 
+{
+    return semctl(sem_id, 0, GETVAL);
+}
+/*
+ * 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) */
+    SEM_UNDO};                                /* flag (set for undo at exit) */
+struct sembuf sem_ulock={                             /* to unlock semaphore */
+    0,                                   /* semaphore number (only one so 0) */
+    1,                                  /* operation (1 to release resource) */
+    SEM_UNO};                                       /* flag (in this case 0) */
+/*
+ * Function MutexLock: to lock a mutex/semaphore
+ */
+inline int MutexLock(int sem_id) 
+{
+    return semop(sem_id, &sem_lock, 1);
+}
+/*
+ * Function MutexUnlock: to unlock a mutex/semaphore
+ */
+inline int MutexUnlock(int sem_id) 
+{
+    return semop(sem_id, &sem_ulock, 1);
 }
     \end{lstlisting}
   \end{minipage} 
@@ -2509,16 +2515,72 @@ inline int MutexFind(key_t ipc_key)
   \label{fig:ipc_mutex_create}
 \end{figure}
 
-
-La prima funzione definita (\texttt{\small 8--22}) è \func{MutexCreate},
-anzitutto (\texttt{\small 11--15}) si chiama \func{semget} con
-\macro{IPC\_CREATE} per creare il semaforo qualora non esista, assegnandogli i
-privilegi di lettura e scrittura per l'utente. In caso di errore si
-scrive un errore e si esce. 
-
-
-
-
+La prima funzione (\texttt{\small 1--17}) è \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}
+con \macro{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
+\func{semctl} con il comando \macro{SETVAL}, utilizzando l'unione
+\var{semunion} dichiarata ed avvalorata in precedenza (\texttt{\small 6}) 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.
+
+La seconda funzione (\texttt{\small 18--24}) è \func{MutexFind}, che data una
+chiave, restituisce l'identificatore del semaforo ad essa associato. La
+comprensione del suo funzionamento è immediata in quanto è solo 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.
+
+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 \macro{GETVAL}, che permette di restituire il valore del
+semaforo.
+
+La quarta e la quinta funzione (\texttt{\small 43--56}) 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
+dell'opzione \macro{SEM\_UNDO} per evitare che il semaforo resti bloccato in
+caso di terminazione imprevista del processo. Si noti infine come, essendo
+tutte le funzioni riportate in \figref{fig:ipc_mutex_create} estremamente
+semplici, se si sono definite tutte come \ctyp{inline}.\footnote{la direttiva
+  \func{inline} viene usata per dire al compilatore di non trattare la
+  funzione cui essa fa riferimento come una funzione, ma di inserire il codice
+  direttamente nel testo del programma.  Anche se i compilatori più moderni
+  sono in grado di effettuare da soli queste manipolazioni (impostando le
+  opportune ottimizzazioni) questa è una tecnica usata per migliorare le
+  prestazioni per le funzioni piccole ed usate di frequente, in tal caso
+  infatti le istruzioni per creare un nuovo frame nello stack per chiamare la
+  funzione costituirebbero una parte rilevante del codice, appesantendo
+  inutilmente il programma. Originariamente questa era fatto utilizzando delle
+  macro, ma queste hanno tutta una serie di problemi di sintassi nel passaggio
+  degli argomenti (si veda ad esempio \cite{PratC} che in questo modo possono
+  essere evitati.}
+
+
+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
+rilasciata. Chiamando \func{MutexUnlock} il valore del semaforo sarà
+incrementato di uno, sbloccandolo qualora fosse bloccato.  Si noti che occorre
+eseguire sempre prima \func{MutexLock} e poi \func{MutexUnlock}, perché se per
+un qualche errore si esegue più volte quest'ultima il valore del semaforo
+crescerebbe oltre 1, e \func{MutexLock} non avrebbe più l'effetto aspettato
+(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.
 
 
 
@@ -2578,7 +2640,7 @@ lettura si deve essere sicuri che i dati restano coerenti e non vengono
 sovrascritti da un accesso in scrittura sullo stesso segmento da parte di un
 altro processo; per questo in genere la memoria condivisa viene sempre
 utilizzata in abbinamento ad un meccanismo di sincronizzazione, il che, di
-norma, significa insime a dei semafori.
+norma, significa insieme a dei semafori.
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -2615,7 +2677,7 @@ invece:
   inizializzato al valore di \param{size}.
 \item il campo \var{shm\_ctime}, che esprime il tempo di creazione del
   segmento, viene inizializzato al tempo corrente.
-\item i campi \var{shm\_atime} e \var{shm\_atime}, che esprimno
+\item i campi \var{shm\_atime} e \var{shm\_atime}, che esprimono
   rispettivamente il tempo dell'ultima volta che il segmento è stato
   agganciato o sganciato da un processo, vengono inizializzati a zero.
 \item il campo \var{shm\_lpid}, che esprime il \acr{pid} del processo che ha
@@ -2795,7 +2857,7 @@ In caso di successo la funzione aggiorna anche i seguenti campi di
 \end{itemize*} 
 
 Come accennato in \secref{sec:proc_fork} un segmento di memoria condivisa
-agganciato ad un precesso viene ereditato da un figlio attraverso una
+agganciato ad un processo viene ereditato da un figlio attraverso una
 \func{fork}, dato che quest'ultimo riceve una copia dello spazio degli
 indirizzi del padre. Invece, dato che attraverso una \func{exec} viene
 eseguito un diverso programma con uno spazio di indirizzi completamente
@@ -2920,12 +2982,12 @@ polling\index{polling}, che 
 
 Per questo motivo la tecnica alternativa più pulita è quella di fare ricorso
 al \textit{file locking} visto in \secref{sec:file_locking} ed utilizzare
-\func{fcntl} su un file creato per l'occazione per ottenere un write lock; in
+\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 determimanare la dispobilità della
+\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.
 
index ee8fa89da88d4d85489ae1bb209807408907eeab..15ddd826c2f3500668632b8d1cea932e6a95fef1 100644 (file)
@@ -5,7 +5,7 @@
  *
  * Author: S. Piccardi
  *
- * $Id: wrappers.h,v 1.3 2002/08/18 23:24:44 piccardi Exp $
+ * $Id: wrappers.h,v 1.4 2002/11/20 23:34:02 piccardi Exp $
  *
  ***************************************************************/
 #include <sys/sem.h>     /* IPC semaphore declarations */
@@ -32,45 +32,8 @@ union semun {
 };
 #endif
 /*
- * Define the sem_lock and sem_ulock sembuf structures to 
- * lock and unlock the semaphore (used to implement a mutex)
- */
-struct sembuf sem_lock={      /* to lock semaphore */
-    0,    /* semaphore number (only one so 0) */
-    -1,   /* semaphore operation (-1 to use resource) */
-    0};   /* semaphore flag (in this case 0) */
-struct sembuf sem_ulock={     /* to unlock semaphore */
-    0,    /* semaphore number (only one so 0) */
-    1,    /* semaphore operation (-1 to release resource) */
-    0};   /* semaphore flag (in this case 0) */
-/*
- * Function MutexLock:
- * to lock a mutex/semaphore
- *
- * Input: a semaphore id #
- */
-inline void MutexLock(int sem_id) 
-{
-    if (semop(sem_id,&sem_lock,1)) {
-       perror("Cannot lock the semaphore");
-       exit(1);
-    }
-}
-/*
- * Function MutexUnlock
- * to unlock a mutex/semaphore
+ * Function MutexCreate: create a mutex/semaphore
  *
- * Input: a semaphore id #
- */
-inline void MutexUnlock(int sem_id) 
-{
-    if (semop(sem_id,&sem_ulock,1)) {
-       perror("Cannot unlock the semaphore");
-       exit(1);
-    }
-}
-/*
- * Function MutexCreate:
  * First call create a semaphore, using the given key. 
  * We want only one semaphore so we set second argument to 1; third 
  * parameter is the flag argument, and is set to create a semaphore 
@@ -78,55 +41,72 @@ inline void MutexUnlock(int sem_id)
  * Second call initialize the semaphore to 1 (unlocked)
  *
  * Input: an IPC key value (to create an unique semaphore)
- * Return: the semaphore id#
+ * Return: the semaphore id# or -1 on error
  */
-const union semun semunion={1};    /* semaphore union structure */
 inline int MutexCreate(key_t ipc_key) 
 {
-    int sem_id;
-    if( (sem_id=semget(ipc_key,1,IPC_CREAT|0666))<0 ){ /* get sem ID */
-       perror("cannot create semaphore");     /* a sem_id <0 is an error */
-       printf("semid=%d",sem_id);
-       exit(1);
+    const union semun semunion={1};             /* semaphore union structure */
+    int sem_id, ret;
+    sem_id = semget(ipc_key, 1, IPC_CREAT|0666);         /* get semaphore ID */
+    if (sem_id == -1) {                              /* if error return code */
+       return sem_id;
     }
-    if ( (semctl(sem_id,0,SETVAL,semunion)) < 0 ) {
-        perror("cannot init semaphore");       /* <0 is an error */
-       printf("on semid=%d",sem_id);
-       exit(1);
+    ret = semctl(sem_id, 0, SETVAL, semunion);             /* init semaphore */
+    if (ret == -1) {
+       return ret;
     }
     return sem_id;
 }
 /*
- * Find Mutex
- * get the semaphore/mutex Id given the IPC key value
+ * Function MutexFind: get the semaphore/mutex Id given the IPC key value
  *
  * Input: an IPC key value
  */
 inline int MutexFind(key_t ipc_key) 
 {
-    int sem_id;
-    if( (sem_id=semget(ipc_key,1,0))<0 ){       /* find sem .ID */
-       perror("cannot find semaphore");
-        exit(1);
-    }
-    return sem_id;
+    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
  *
  * Input:  a semaphore id #
  * Return: the semaphore value
  */
 inline int MutexRead(int sem_id) 
 {
-    int value;
-    if ( (value=semctl(sem_id,0,GETVAL,semunion)) < 0 ) {
-             perror("cannot read semaphore");       /* a <0 is an error */
-             printf("on semid=%d\n",sem_id);
-             exit(1);
-    } 
-    return value;
+    return semctl(sem_id, 0, GETVAL);
+}
+/*
+ * Define sembuf structures to lock and unlock the semaphore 
+ * (used to implement a mutex)
+ */
+struct sembuf sem_lock={                                /* to lock semaphore */
+    0,                                   /* semaphore number (only one so 0) */
+    -1,                                    /* operation (-1 to use resource) */
+    SEM_UNDO};                                /* flag (set for undo at exit) */
+struct sembuf sem_ulock={                             /* to unlock semaphore */
+    0,                                   /* semaphore number (only one so 0) */
+    1,                                  /* operation (1 to release resource) */
+    SEM_UNO};                                       /* flag (in this case 0) */
+/*
+ * Function MutexLock: to lock a mutex/semaphore
+ *
+ * Input:  a semaphore id #
+ * Output: semop return code  (0 OK, -1 KO)
+ */
+inline int MutexLock(int sem_id) 
+{
+    return semop(sem_id, &sem_lock, 1);
+}
+/*
+ * Function MutexUnlock: to unlock a mutex/semaphore
+ *
+ * Input:  a semaphore id #
+ * Return: semop return code (0 OK, -1 KO)
+ */
+inline int MutexUnlock(int sem_id) 
+{
+    return semop(sem_id, &sem_ulock, 1);
 }
 /*
  * Function ShmCreate: