Completata la descrizione dell'esempio dei mutex realizzati con i semafori.
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index 293dd29b5d3f65fde7b0ed33f36765cbe84146e2..9dec79a907d64106343fb941ceac99990aed297b 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -2439,6 +2439,152 @@ effettuare subito le operazioni che non prevedono un blocco del processo e di
 ignorare silenziosamente le altre; questo però comporta il fatto che il
 ripristino non è comunque garantito in tutte le occasioni.
 
 ignorare silenziosamente le altre; questo però comporta il fatto che il
 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), 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}{} 
+/*
+ * Function MutexCreate: create a mutex/semaphore
+ */
+inline int MutexCreate(key_t ipc_key) 
+{
+    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;
+    }
+    ret = semctl(sem_id, 0, SETVAL, semunion);             /* init semaphore */
+    if (ret == -1) {
+        return ret;
+    }
+    return sem_id;
+}
+/*
+ * Function MutexFind: get the semaphore/mutex Id given the IPC key value
+ */
+inline int MutexFind(key_t ipc_key) 
+{
+    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} 
+  \normalsize 
+  \caption{Il codice delle funzioni che permettono di creare o recuperare
+    l'identificatore di un semaforo da utilizzare come \textit{mutex}.}
+  \label{fig:ipc_mutex_create}
+\end{figure}
+
+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.
+
+
+
+
 
 \subsection{Memoria condivisa}
 \label{sec:ipc_sysv_shm}
 
 \subsection{Memoria condivisa}
 \label{sec:ipc_sysv_shm}
@@ -2494,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
 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
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -2531,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.
   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
   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
@@ -2711,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
 \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
 \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
@@ -2836,20 +2982,22 @@ 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
 
 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
 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.
 
 Questo approccio presenta il notevole vantaggio che alla terminazione di un
 processo tutti i lock acquisiti vengono rilasciati automaticamente (alla
 chiusura dei relativi file) e non ci si deve preoccupare di niente, e non
 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
 chiusura dei relativi file) e non ci si deve preoccupare di niente, e non
-consuma risorse di sistema, lo svantaggio è che dovendo fare ricorso a delle
-operazioni sul filesystem esso è in genere leggermente più lento.
+consuma risorse permanentemente allocate nel sistema, lo svantaggio è che
+dovendo fare ricorso a delle operazioni sul filesystem esso è in genere
+leggermente più lento.
+
 
 
 \subsection{Il \textit{memory mapping} anonimo}
 
 
 \subsection{Il \textit{memory mapping} anonimo}