Completata la descrizione dell'esempio dei mutex realizzati con i semafori.
[gapil.git] / ipc.tex
diff --git a/ipc.tex b/ipc.tex
index 2bd1a9ccdcbbf00ec46c4df004ca434496e63f6d..9dec79a907d64106343fb941ceac99990aed297b 100644 (file)
--- a/ipc.tex
+++ b/ipc.tex
@@ -879,20 +879,20 @@ molti altri devono poter leggere non pu
 Per questo nello sviluppo di System V vennero introdotti una serie di nuovi
 oggetti per la comunicazione fra processi ed una nuova interfaccia di
 programmazione, che fossero in grado di garantire una maggiore flessibilità.
 Per questo nello sviluppo di System V vennero introdotti una serie di nuovi
 oggetti per la comunicazione fra processi ed una nuova interfaccia di
 programmazione, che fossero in grado di garantire una maggiore flessibilità.
-In questa sezione esamineremo come Linux supporta quello che viene ormai
-chiamato il \textsl{Sistema di comunicazione inter-processo} di System V, o
-\textit{System V IPC (Inter-Process Comunication)}.
+In questa sezione esamineremo come Linux supporta quello che viene chiamato il
+\textsl{Sistema di comunicazione inter-processo} di System V, cui da qui in
+avanti faremo riferimento come \textit{SysV IPC} (dove IPC è la sigla di
+\textit{Inter-Process Comunication}).
 
 
 
 \subsection{Considerazioni generali}
 \label{sec:ipc_sysv_generic}
 
 
 
 
 \subsection{Considerazioni generali}
 \label{sec:ipc_sysv_generic}
 
-La principale caratteristica del sistema di IPC di System V è quella di essere
-basato su oggetti permanenti che risiedono nel kernel. Questi, a differenza di
-quanto avviene per i file descriptor, non mantengono un contatore dei
-riferimenti, e non vengono cancellati dal sistema una volta che non sono più
-in uso. 
+La principale caratteristica del \textit{SysV IPC} è quella di essere basato
+su oggetti permanenti che risiedono nel kernel. Questi, a differenza di quanto
+avviene per i file descriptor, non mantengono un contatore dei riferimenti, e
+non vengono cancellati dal sistema una volta che non sono più in uso.
 
 Questo comporta due problemi: il primo è che, al contrario di quanto avviene
 per pipe e fifo, la memoria allocata per questi oggetti non viene rilasciata
 
 Questo comporta due problemi: il primo è che, al contrario di quanto avviene
 per pipe e fifo, la memoria allocata per questi oggetti non viene rilasciata
@@ -903,13 +903,13 @@ file, un contatore del numero di riferimenti che ne indichi l'essere in uso,
 essi possono essere cancellati anche se ci sono dei processi che li stanno
 utilizzando, con tutte le conseguenze (negative) del caso.
 
 essi possono essere cancellati anche se ci sono dei processi che li stanno
 utilizzando, con tutte le conseguenze (negative) del caso.
 
-Un'ulteriore caratteristica negativa è che gli oggetti usati nel System V IPC
-vengono creati direttamente dal kernel, e sono accessibili solo specificando
-il relativo \textsl{identificatore}. Questo è un numero progressivo (un po'
-come il \acr{pid} dei processi) che il kernel assegna a ciascuno di essi
-quanto vengono creati (sul procedimento di assegnazione torneremo in
-\secref{sec:ipc_sysv_id_use}). L'identificatore viene restituito dalle
-funzioni che creano l'oggetto, ed è quindi locale al processo che le ha
+Un'ulteriore caratteristica negativa è che gli oggetti usati nel \textit{SysV
+  IPC} vengono creati direttamente dal kernel, e sono accessibili solo
+specificando il relativo \textsl{identificatore}. Questo è un numero
+progressivo (un po' come il \acr{pid} dei processi) che il kernel assegna a
+ciascuno di essi quanto vengono creati (sul procedimento di assegnazione
+torneremo in \secref{sec:ipc_sysv_id_use}). L'identificatore viene restituito
+dalle funzioni che creano l'oggetto, ed è quindi locale al processo che le ha
 eseguite. Dato che l'identificatore viene assegnato dinamicamente dal kernel
 non è possibile prevedere quale sarà, né utilizzare un qualche valore statico,
 si pone perciò il problema di come processi diversi possono accedere allo
 eseguite. Dato che l'identificatore viene assegnato dinamicamente dal kernel
 non è possibile prevedere quale sarà, né utilizzare un qualche valore statico,
 si pone perciò il problema di come processi diversi possono accedere allo
@@ -922,7 +922,7 @@ primitivo \type{key\_t}, da specificare in fase di creazione dell'oggetto, e
 tramite la quale è possibile ricavare l'identificatore.\footnote{in sostanza
   si sposta il problema dell'accesso dalla classificazione in base
   all'identificatore alla classificazione in base alla chiave, una delle tante
 tramite la quale è possibile ricavare l'identificatore.\footnote{in sostanza
   si sposta il problema dell'accesso dalla classificazione in base
   all'identificatore alla classificazione in base alla chiave, una delle tante
-  complicazioni inutili presenti nell'IPC di System V.} Oltre la chiave, la
+  complicazioni inutili presenti nel \textit{SysV IPC}.} Oltre la chiave, la
 struttura, la cui definizione è riportata in \figref{fig:ipc_ipc_perm},
 mantiene varie proprietà ed informazioni associate all'oggetto.
 
 struttura, la cui definizione è riportata in \figref{fig:ipc_ipc_perm},
 mantiene varie proprietà ed informazioni associate all'oggetto.
 
@@ -973,7 +973,7 @@ file ed un numero di versione; il suo prototipo 
   
   \funcdecl{key\_t ftok(const char *pathname, int proj\_id)}
   
   
   \funcdecl{key\_t ftok(const char *pathname, int proj\_id)}
   
-  Restituisce una chiave per identificare un oggetto del System V IPC.
+  Restituisce una chiave per identificare un oggetto del \textit{SysV IPC}.
   
   \bodydesc{La funzione restituisce la chiave in caso di successo e -1
     altrimenti, nel qual caso \var{errno} sarà uno dei possibili codici di
   
   \bodydesc{La funzione restituisce la chiave in caso di successo e -1
     altrimenti, nel qual caso \var{errno} sarà uno dei possibili codici di
@@ -1011,11 +1011,11 @@ creato da chi ci si aspetta.
 
 Questo è, insieme al fatto che gli oggetti sono permanenti e non mantengono un
 contatore di riferimenti per la cancellazione automatica, il principale
 
 Questo è, insieme al fatto che gli oggetti sono permanenti e non mantengono un
 contatore di riferimenti per la cancellazione automatica, il principale
-problema del sistema di IPC di System V. Non esiste infatti una modalità
-chiara per identificare un oggetto, come sarebbe stato se lo si fosse
-associato ad in file, e tutta l'interfaccia è inutilmente complessa.  Per
-questo ne è stata effettuata una revisione completa nello standard POSIX.1b,
-che tratteremo in \secref{sec:ipc_posix}.
+problema del \textit{SysV IPC}. Non esiste infatti una modalità chiara per
+identificare un oggetto, come sarebbe stato se lo si fosse associato ad in
+file, e tutta l'interfaccia è inutilmente complessa.  Per questo ne è stata
+effettuata una revisione completa nello standard POSIX.1b, che tratteremo in
+\secref{sec:ipc_posix}.
 
 
 \subsection{Il controllo di accesso}
 
 
 \subsection{Il controllo di accesso}
@@ -1116,10 +1116,10 @@ un identificatore pu
 Il sistema dispone sempre di un numero fisso di oggetti di IPC,\footnote{fino
   al kernel 2.2.x questi valori, definiti dalle costanti \macro{MSGMNI},
   \macro{SEMMNI} e \macro{SHMMNI}, potevano essere cambiati (come tutti gli
 Il sistema dispone sempre di un numero fisso di oggetti di IPC,\footnote{fino
   al kernel 2.2.x questi valori, definiti dalle costanti \macro{MSGMNI},
   \macro{SEMMNI} e \macro{SHMMNI}, potevano essere cambiati (come tutti gli
-  altri limiti relativi al \textit{System V IPC}) solo con una ricompilazione
-  del kernel, andando a modificarne la definizione nei relativi header file.
-  A partire dal kernel 2.4.x è possibile cambiare questi valori a sistema
-  attivo scrivendo sui file \file{shmmni}, \file{msgmni} e \file{sem} di
+  altri limiti relativi al \textit{SysV IPC}) solo con una ricompilazione del
+  kernel, andando a modificarne la definizione nei relativi header file.  A
+  partire dal kernel 2.4.x è possibile cambiare questi valori a sistema attivo
+  scrivendo sui file \file{shmmni}, \file{msgmni} e \file{sem} di
   \file{/proc/sys/kernel} o con l'uso di \texttt{syscntl}.} e per ciascuno di
 essi viene mantenuto in \var{seq} un numero di sequenza progressivo che viene
 incrementato di uno ogni volta che l'oggetto viene cancellato. Quando
   \file{/proc/sys/kernel} o con l'uso di \texttt{syscntl}.} e per ciascuno di
 essi viene mantenuto in \var{seq} un numero di sequenza progressivo che viene
 incrementato di uno ogni volta che l'oggetto viene cancellato. Quando
@@ -1217,7 +1217,7 @@ mantenuta staticamente all'interno del sistema.
 \subsection{Code di messaggi}
 \label{sec:ipc_sysv_mq}
 
 \subsection{Code di messaggi}
 \label{sec:ipc_sysv_mq}
 
-Il primo oggetto introdotto dal \textit{System V IPC} è quello delle code di
+Il primo oggetto introdotto dal \textit{SysV IPC} è quello delle code di
 messaggi.  Le code di messaggi sono oggetti analoghi alle pipe o alle fifo,
 anche se la loro struttura è diversa. La funzione che permette di ottenerne
 una è \func{msgget} ed il suo prototipo è:
 messaggi.  Le code di messaggi sono oggetti analoghi alle pipe o alle fifo,
 anche se la loro struttura è diversa. La funzione che permette di ottenerne
 una è \func{msgget} ed il suo prototipo è:
@@ -1651,6 +1651,24 @@ modificati:
 \item Il valore \var{msg\_rtime}, che viene impostato al tempo corrente.
 \end{itemize*}
 
 \item Il valore \var{msg\_rtime}, che viene impostato al tempo corrente.
 \end{itemize*}
 
+Le code di messaggi presentano il solito problema di tutti gli oggetti del
+SysV IPC; essendo questi permanenti restano nel sistema occupando risorse
+anche quando un processo è terminato, al contrario delle pipe per le quali
+tutte le risorse occupate vengono rilasciate quanto l'ultimo processo che le
+utilizzava termina. Questo comporta che in caso di errori si può saturare il
+sistema, e che devono comunque essere esplicitamente previste delle funzioni
+di rimozione in caso di interruzioni o uscite dal programma (come vedremo in
+\figref{fig:ipc_mq_fortune_server}).
+
+L'altro problema è non facendo uso di file descriptor le tecniche di
+\textit{I/O multiplexing} descritte in \secref{sec:file_multiplexing} non
+possono essere utilizzate, e non si ha a disposizione niente di analogo alle
+funzioni \func{select} e \func{poll}. Questo rende molto scomodo usare più di
+una di queste strutture alla volta; ad esempio non si può scrivere un server
+che aspetti un messaggio su più di una coda senza fare ricorso ad una tecnica
+di \textit{polling}\index{polling} che esegua un ciclo di attesa su ciascuna
+di esse.
+
 Come esempio dell'uso delle code di messaggi possiamo riscrivere il nostro
 server di \textit{fortunes} usando queste al posto delle fifo. In questo caso
 useremo una sola coda di messaggi, usando il tipo di messaggio per comunicare
 Come esempio dell'uso delle code di messaggi possiamo riscrivere il nostro
 server di \textit{fortunes} usando queste al posto delle fifo. In questo caso
 useremo una sola coda di messaggi, usando il tipo di messaggio per comunicare
@@ -1886,7 +1904,7 @@ della risorsa; in generale per
 utilizzando il valore del contatore come indicatore del ``numero di risorse''
 ancora disponibili.
 
 utilizzando il valore del contatore come indicatore del ``numero di risorse''
 ancora disponibili.
 
-Il sistema di comunicazione interprocesso di System V IPC prevede anche i
+Il sistema di comunicazione interprocesso di \textit{SysV IPC} prevede anche i
 semafori, ma gli oggetti utilizzati non sono semafori singoli, ma gruppi di
 semafori detti \textsl{insiemi} (o \textit{semaphore set}); la funzione che
 permette di creare o ottenere l'identificatore di un insieme di semafori è
 semafori, ma gli oggetti utilizzati non sono semafori singoli, ma gruppi di
 semafori detti \textsl{insiemi} (o \textit{semaphore set}); la funzione che
 permette di creare o ottenere l'identificatore di un insieme di semafori è
@@ -1929,8 +1947,8 @@ richiesta dell'identificatore di un insieme gi
 Purtroppo questa implementazione complica inutilmente lo schema elementare che
 abbiamo descritto, dato che non è possibile definire un singolo semaforo, ma
 se ne deve creare per forza un insieme.  Ma questa in definitiva è solo una
 Purtroppo questa implementazione complica inutilmente lo schema elementare che
 abbiamo descritto, dato che non è possibile definire un singolo semaforo, ma
 se ne deve creare per forza un insieme.  Ma questa in definitiva è solo una
-complicazione inutile, il problema è che i semafori del System V IPC soffrono
-di altri due, ben più gravi, difetti.
+complicazione inutile, il problema è che i semafori del \textit{SysV IPC}
+soffrono di altri due, ben più gravi, difetti.
 
 Il primo difetto è che non esiste una funzione che permetta di creare ed
 inizializzare un semaforo in un'unica chiamata; occorre prima creare l'insieme
 
 Il primo difetto è che non esiste una funzione che permetta di creare ed
 inizializzare un semaforo in un'unica chiamata; occorre prima creare l'insieme
@@ -1938,8 +1956,8 @@ dei semafori con \func{semget} e poi inizializzarlo con \func{semctl}, si
 perde così ogni possibilità di eseguire atomicamente questa operazione.
 
 Il secondo difetto deriva dalla caratteristica generale degli oggetti del
 perde così ogni possibilità di eseguire atomicamente questa operazione.
 
 Il secondo difetto deriva dalla caratteristica generale degli oggetti del
-System V IPC di essere risorse globali di sistema, che non vengono cancellate
-quando nessuno le usa più; ci si così a trova a dover affrontare
+\textit{SysV IPC} di essere risorse globali di sistema, che non vengono
+cancellate quando nessuno le usa più; ci si così a trova a dover affrontare
 esplicitamente il caso in cui un processo termina per un qualche errore,
 lasciando un semaforo occupato, che resterà tale fino al successivo riavvio
 del sistema. Come vedremo esistono delle modalità per evitare tutto ciò, ma
 esplicitamente il caso in cui un processo termina per un qualche errore,
 lasciando un semaforo occupato, che resterà tale fino al successivo riavvio
 del sistema. Come vedremo esistono delle modalità per evitare tutto ciò, ma
@@ -1988,8 +2006,8 @@ semaforo), per quanto riguarda gli altri campi invece:
 Ciascun semaforo dell'insieme è realizzato come una struttura di tipo
 \var{sem} che ne contiene i dati essenziali, la sua definizione\footnote{si è
   riportata la definizione originaria del kernel 1.0, che contiene la prima
 Ciascun semaforo dell'insieme è realizzato come una struttura di tipo
 \var{sem} che ne contiene i dati essenziali, la sua definizione\footnote{si è
   riportata la definizione originaria del kernel 1.0, che contiene la prima
-  realizzazione del System V IPC in Linux. In realtà questa struttura ormai è
-  ridotta ai soli due primi membri, e gli altri vengono calcolati
+  realizzazione del \textit{SysV IPC} in Linux. In realtà questa struttura
+  ormai è ridotta ai soli due primi membri, e gli altri vengono calcolati
   dinamicamente. La si è utilizzata a scopo di esempio, perché indica tutti i
   valori associati ad un semaforo, restituiti dalle funzioni di controllo, e
   citati dalle pagine di manuale.} è riportata in \figref{fig:ipc_sem}. Questa
   dinamicamente. La si è utilizzata a scopo di esempio, perché indica tutti i
   valori associati ad un semaforo, restituiti dalle funzioni di controllo, e
   citati dalle pagine di manuale.} è riportata in \figref{fig:ipc_sem}. Questa
@@ -2360,8 +2378,8 @@ occorre fare riferimento all'implementazione usata in Linux, che 
 in maniera semplificata nello schema di \figref{fig:ipc_sem_schema}.  Si è
 presa come riferimento l'architettura usata fino al kernel 2.2.x che è più
 semplice (ed illustrata in dettaglio in \cite{tlk}); nel kernel 2.4.x la
 in maniera semplificata nello schema di \figref{fig:ipc_sem_schema}.  Si è
 presa come riferimento l'architettura usata fino al kernel 2.2.x che è più
 semplice (ed illustrata in dettaglio in \cite{tlk}); nel kernel 2.4.x la
-struttura del System V IPC è stata modificata, ma le definizioni relative a
-queste strutture restano per compatibilità.\footnote{in particolare con le
+struttura del \textit{SysV IPC} è stata modificata, ma le definizioni relative
+queste strutture restano per compatibilità.\footnote{in particolare con le
   vecchie versioni delle librerie del C, come le libc5.}
 
 \begin{figure}[htb]
   vecchie versioni delle librerie del C, come le libc5.}
 
 \begin{figure}[htb]
@@ -2421,12 +2439,158 @@ 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}
 
-Il terzo oggetto introdotto dal \textit{System V IPC} è quello dei segmenti di
-memoria condivisa. La funzione che permette di ottenerne uno è \func{shmget}
+Il terzo oggetto introdotto dal \textit{SysV IPC} è quello dei segmenti di
+memoria condivisa. La funzione che permette di ottenerne uno è \func{shmget},
 ed il suo prototipo è:
 \begin{functions}
   \headdecl{sys/types.h} 
 ed il suo prototipo è:
 \begin{functions}
   \headdecl{sys/types.h} 
@@ -2460,6 +2624,24 @@ ripeteremo quanto detto al proposito in \secref{sec:ipc_sysv_mq}. L'argomento
 \param{size} specifica invece la dimensione, in byte, del segmento, che viene
 comunque arrotondata al multiplo superiore di \macro{PAGE\_SIZE}.
 
 \param{size} specifica invece la dimensione, in byte, del segmento, che viene
 comunque arrotondata al multiplo superiore di \macro{PAGE\_SIZE}.
 
+La memoria condivisa è la forma più veloce di comunicazione fra due processi,
+in quanto permette agli stessi di vedere nel loro spazio di indirizzi una
+stessa sezione di memoria.  Pertanto non è necessaria nessuna operazione di
+copia per trasmettere i dati da un processo all'altro, in quanto ciascuno può
+accedervi direttamente con le normali operazioni di lettura e scrittura dei
+dati in memoria.
+
+Ovviamente tutto questo ha un prezzo, ed il problema fondamentale della
+memoria condivisa è la sincronizzazione degli accessi. È evidente infatti che
+se un processo deve scambiare dei dati con un altro, si deve essere sicuri che
+quest'ultimo non acceda al segmento di memoria condivisa prima che il primo
+non abbia completato le operazioni di scrittura, inoltre nel corso di una
+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 insieme a dei semafori.
+
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
@@ -2495,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
@@ -2554,75 +2736,325 @@ un segmento di memoria condivisa 
     \begin{errlist}
     \item[\macro{EACCES}] Si è richiesto \macro{IPC\_STAT} ma i permessi non
       consentono l'accesso in lettura al segmento.
     \begin{errlist}
     \item[\macro{EACCES}] Si è richiesto \macro{IPC\_STAT} ma i permessi non
       consentono l'accesso in lettura al segmento.
-    \item[\macro{EINVAL}] .
-    \item[\macro{ENOMEM}] .
-    \end{errlist}.}
+    \item[\macro{EINVAL}] O \param{shmid} o \param{cmd} hanno valori non
+      validi.
+    \item[\macro{EIDRM}] L'argomento \param{shmid} fa riferimento ad un
+      segmento che è stato cancellato.
+    \item[\macro{EPERM}] Si è specificato un comando con \macro{IPC\_SET} o
+      \macro{IPC\_RMID} senza i permessi necessari.
+    \item[\macro{EOVERFLOW}] L'argomento \param{shmid} fa riferimento ad un
+      segmento che è stato cancellato.
+    \end{errlist}
+  ed inoltre \macro{EFAULT}.}
 \end{functions}
 
 \end{functions}
 
-Per utilizzare i segmenti di memoria condivisa si usano due funzioni,
-\func{shmat} e \func{shmdt}, che consentono di agganciarli e sganciarli da un
-processo, così che questo possa vederli nel suo spazio di indirizzi; i loro
-prototipi sono:
+Il comportamento della funzione dipende dal valore del comando passato
+attraverso l'argomento \param{cmd}, i valori possibili sono i seguenti:
+\begin{basedescript}{\desclabelwidth{2.2cm}\desclabelstyle{\nextlinelabel}}
+\item[\macro{IPC\_STAT}] Legge le informazioni riguardo il segmento di memoria
+  condivisa nella struttura \var{shmid\_ds} puntata da \param{buf}. Occorre
+  avere il permesso di lettura sulla coda.
+\item[\macro{IPC\_RMID}] Marca il segmento di memoria condivisa per la
+  rimozione, questo verrà cancellato effettivamente solo quando l'ultimo
+  processo ad esso agganciato si sarà staccato. Questo comando può essere
+  eseguito solo da un processo con userid effettivo, corrispondente al
+  creatore o al proprietario della coda, o all'amministratore.
+\item[\macro{IPC\_SET}] Permette di modificare i permessi ed il proprietario
+  del segmento.  Per modificare i valori di \var{shm\_perm.mode},
+  \var{shm\_perm.uid} e \var{shm\_perm.gid} occorre essere il proprietario o
+  il creatore della coda, oppure l'amministratore. Compiuta l'operazione
+  aggiorna anche il valore del campo \var{shm\_ctime}.
+\item[\macro{SHM\_LOCK}] Abilita il \textit{memory locking}\index{memory
+    locking} (vedi \secref{sec:proc_mem_lock}) sul segmento di memoria
+  condivisa. Solo l'amministratore può utilizzare questo comando.
+\item[\macro{SHM\_UNLOCK}] Disabilita il \textit{memory locking}. Solo
+  l'amministratore può utilizzare questo comando.
+\end{basedescript}
+i primi tre comandi sono gli stessi già visti anche per le code ed i semafori,
+gli ultimi due sono delle estensioni previste da Linux. 
+
+Per utilizzare i segmenti di memoria condivisa l'interfaccia prevede due
+funzioni, la prima è \func{shmat}, che serve ad agganciare un segmento al
+processo chiamante, in modo che quest'ultimo possa vederlo nel suo spazio di
+indirizzi; il suo prototipo è:
 \begin{functions}
   \headdecl{sys/types.h} 
   \headdecl{sys/shm.h}
   
   \funcdecl{void *shmat(int shmid, const void *shmaddr, int shmflg)}
   Aggancia al processo un segmento di memoria condivisa.
 \begin{functions}
   \headdecl{sys/types.h} 
   \headdecl{sys/shm.h}
   
   \funcdecl{void *shmat(int shmid, const void *shmaddr, int shmflg)}
   Aggancia al processo un segmento di memoria condivisa.
-
-  \funcdecl{int shmdt(const void *shmaddr)}
-  Sgancia dal processo un segmento di memoria condivisa.
   
   
-  \bodydesc{Le funzioni restituiscono rispettivamente l'indirizzo del segmento
-    e 0 in caso di successo, mentre entrambe restituiscono -1 in caso di
-    errore, nel qual caso \var{errno} assumerà i valori:
+  \bodydesc{La funzione restituisce l'indirizzo del segmento in caso di
+    successo, e -1 in caso di errore, nel qual caso \var{errno} assumerà i
+    valori:
     \begin{errlist}
     \begin{errlist}
-    \item[\macro{EACCES}] Il processo non ha i provilegi di accesso.
+    \item[\macro{EACCES}] Il processo non ha i privilegi per accedere al
+      segmento nella modalità richiesta.
     \item[\macro{EINVAL}] Si è specificato un identificatore invalido per
     \item[\macro{EINVAL}] Si è specificato un identificatore invalido per
-      \param{shmid}, o un indirizzo non valido per \param{shmaddr}.
-    \item[\macro{EPERM}] Si è richiesto \macro{IPC\_SET} o \macro{IPC\_RMID}
-      senza avere i permessi del creatore o del proprietario del segmento (o
-      quelli dell'amministratore).
-    \item[\macro{EOVERFLOW}] Si è richiesto \macro{IPC\_STAT} ma alcuni valori
-      sono troppo grandi per essere memorizzati nella struttura puntata da
-      \param{buf}.
+      \param{shmid}, o un indirizzo non allineato sul confine di una pagina
+      per \param{shmaddr}.
     \end{errlist}
     \end{errlist}
-    ed inoltre \macro{EFAULT} e \macro{EIDRM}.}
+    ed inoltre \macro{ENOMEM}.}
+\end{functions}
+
+La funzione inserisce un segmento di memoria condivisa all'interno dello
+spazio di indirizzi del processo, in modo che questo possa accedervi
+direttamente, la situazione dopo l'esecuzione di \func{shmat} è illustrata in
+\figref{fig:ipc_shmem_layout} (per la comprensione del resto dello schema si
+ricordi quanto illustrato al proposito in \secref{sec:proc_mem_layout}). Si
+tenga presente che la funzione ha successo anche se il segmento è stato
+marcato per la cancellazione.
+
+\begin{figure}[htb]
+  \centering
+  \includegraphics[height=10cm]{img/sh_memory_layout}
+  \caption{Disposizione dei segmenti di memoria di un processo quando si è
+    agganciato un segmento di memoria condivisa.}
+  \label{fig:ipc_shmem_layout}
+\end{figure}
+
+L'argomento \param{shmaddr} specifica a quale indirizzo\footnote{Lo standard
+  SVID prevede che l'argomento \param{shmaddr} sia di tipo \ctyp{char *}, così
+  come il valore di ritorno della funzione. In Linux è stato così con le
+  \acr{libc4} e le \acr{libc5}, con il passaggio alle \acr{glibc} il tipo di
+  \param{shmaddr} è divenuto un \ctyp{const void *} e quello del valore di
+  ritorno un \ctyp{void *}.} deve essere associato il segmento, se il valore
+specificato è \macro{NULL} è il sistema a scegliere opportunamente un'area di
+memoria libera (questo è il modo più portabile e sicuro di usare la funzione).
+Altrimenti il kernel aggancia il segmento all'indirizzo specificato da
+\param{shmaddr}; questo però può avvenire solo se l'indirizzo coincide con il
+limite di una pagina, cioè se è un multiplo esatto del parametro di sistema
+\macro{SHMLBA}, che in Linux è sempre uguale \macro{PAGE\_SIZE}.
+
+L'argomento \param{shmflg} permette di cambiare il comportamento della
+funzione; esso va specificato come maschera binaria, i bit utilizzati sono
+solo due e sono identificati dalle costanti \macro{SHM\_RND} e
+\macro{SHM\_RDONLY}, che vanno combinate con un OR aritmetico.  Specificando
+\macro{SHM\_RND} si evita che \func{shmat} ritorni un errore quando
+\param{shmaddr} non è allineato ai confini di una pagina. Si può quindi usare
+un valore qualunque per \param{shmaddr}, e il segmento verrà comunque
+agganciato, ma al più vicino multiplo di \macro{SHMLBA} (il nome della
+costante sta infatti per \textit{rounded}, e serve per specificare un
+indirizzo come arrotondamento).
+
+Il secondo bit permette di agganciare il segmento in sola lettura (si ricordi
+che anche le pagine di memoria hanno dei permessi), in tal caso un tentativo
+di scrivere sul segmento comporterà una violazione di accesso con l'emissione
+di un segnale di \macro{SIGSEGV}. Il comportamento usuale di \func{shmat} è
+quello di agganciare il segmento con l'accesso in lettura e scrittura (ed il
+processo deve aver questi permessi in \var{shm\_perm}), non è prevista la
+possibilità di agganciare un segmento in sola scrittura.
+
+In caso di successo la funzione aggiorna anche i seguenti campi di
+\var{shmid\_ds}:
+\begin{itemize*}
+\item il tempo \var{shm\_atime} dell'ultima operazione di aggancio viene
+  impostato al tempo corrente.
+\item il \acr{pid} \var{shm\_lpid} dell'ultimo processo che ha operato sul
+  segmento viene impostato a quello del processo corrente.
+\item il numero \var{shm\_nattch} di processi agganciati al segmento viene
+  aumentato di uno.
+\end{itemize*} 
+
+Come accennato in \secref{sec:proc_fork} un segmento di memoria condivisa
+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
+diverso, tutti i segmenti agganciati al processo originario vengono
+automaticamente sganciati. Lo stesso avviene all'uscita del processo
+attraverso una \func{exit}.
+
+
+Una volta che un segmento di memoria condivisa non serve più, si può
+sganciarlo esplicitamente dal processo usando l'altra funzione
+dell'interfaccia, \func{shmdt}, il cui prototipo è:
+\begin{functions}
+  \headdecl{sys/types.h} 
+  \headdecl{sys/shm.h}
+
+  \funcdecl{int shmdt(const void *shmaddr)}
+  Sgancia dal processo un segmento di memoria condivisa.
+  
+  \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
+    errore, la funzione fallisce solo quando non c'è un segmento agganciato
+    all'indirizzo \func{shmaddr}, con \var{errno} che assume il valore
+    \macro{EINVAL}.}
 \end{functions}
 
 \end{functions}
 
-La prima funzione, \func{shmat}, aggancia un segmento di memoria condivisa
-allo spazio di indirizzi del processo, così che questo possa accedervi.
-L'argomento \param{shmaddr} specifica a quale indirizzo deve essere associato
-il segmento.
+La funzione sgancia dallo spazio degli indirizzi del processo un segmento di
+memoria condivisa; questo viene identificato con l'indirizzo \param{shmaddr}
+restituito dalla precedente chiamata a \func{shmat} con il quale era stato
+agganciato al processo.
+
+Per capire meglio il funzionamento delle funzioni facciamo ancora una volta
+riferimento alle strutture con cui il kernel implementa i segmenti di memoria
+condivisa; uno schema semplificato della struttura è illustrato in
+\figref{fig:ipc_shm_struct}. 
+
+\begin{figure}[htb]
+  \centering
+  \includegraphics[width=10cm]{img/shmstruct}
+   \caption{Schema dell'implementazione dei segmenti di memoria condivisa in
+    Linux.}
+  \label{fig:ipc_shm_struct}
+\end{figure}
+
+
 
 
 
 
+\section{Tecniche alternative}
+\label{sec:ipc_alternatives}
+
+Come abbiamo visto in \secref{sec:ipc_sysv_generic} il \textit{SysV IPC}
+presenta numerosi problemi; in \cite{APUE}\footnote{in particolare nel
+  capitolo 14.}  Stevens effettua una accurata analisi (alcuni dei concetti
+sono già stati accennati in precedenza) ed elenca alcune possibili
+alternative, che vogliamo riprendere in questa sezione.
+
+
+\subsection{Alternative alle code di messaggi}
+\label{sec:ipc_mq_alternative}
+Le code di messaggi sono probabilmente il meno usato degli oggetti del
+\textit{SysV IPC}; esse infatti nacquero principalmente come meccanismo di
+comunicazione bidirezionale quando ancora le pipe erano unidirezionali; con la
+disponibilità di \func{socketpair} (vedi \secref{sec:ipc_socketpair}) si può
+ottenere lo stesso risultato senza incorrere nelle complicazioni introdotte
+dal \textit{SysV IPC}.
+
+In realtà, grazie alla presenza del campo \var{mtype}, le code di messaggi
+hanno delle caratteristiche ulteriori, consentendo una classificazione dei
+messaggi ed un accesso non rigidamente sequenziale, due caratteristiche che
+sono impossibili da ottenere con le pipe e i socket di \func{socketpair};
+a queste esigenze però si può comunque ovviare in maniera diversa con un uso
+combinato della memoria condivisa e dei meccanismi di sincronizzazione, per
+cui alla fine l'uso delle code di messaggi classiche è poco diffuso.
+
+
+\subsection{La sincronizzazione con il \textit{file locking}}
+\label{sec:ipc_file_lock}
+
+Come illustrato in \secref{sec:ipc_sysv_sem} i semafori del \textit{SysV IPC}
+presentano una interfaccia inutilmente complessa e con alcuni difetti
+strutturali, per questo quando si ha una semplice esigenza di sincronizzazione
+per la quale basterebbe un semaforo binario (quello che abbiamo definito come
+\textit{mutex}, che indica la disponibilità o meno di una risorsa, e non ha
+associato un contatore come i semafori) si possono utilizzare metodi
+alternativi.
+
+La prima possibilità, utilizzata fin dalle origini di Unix, è quella di usare
+dei \textsl{file di lock} (per i quali esiste anche una opportuna directory,
+\file{/var/lock}, nel filesystem standard). Per questo si usa la
+caratteristica della funzione \func{open} (illustrata in
+\secref{sec:file_open}) che prevede\footnote{questo è quanto dettato dallo
+  standard POSIX.1, ciò non toglie che in alcune implementazioni questa
+  tecnica possa non funzionare; in particolare per Linux, nel caso di NFS, si
+  è comunque soggetti alla possibilità di una race condition.} che essa
+ritorni un errore quando usata con i flag di \macro{O\_CREAT} e
+\macro{O\_EXCL}. In tal modo la creazione di un file di lock può essere
+eseguita atomicamente, il processo che crea il file con successo si può
+considerare come titolare del lock (e della risorsa ad esso associata) mentre
+il rilascio si può eseguire con una chiamata ad
+\func{unlink}.\footnote{abbiamo già accennato in \secref{sec:file_open} che
+  questa tecnica può non funzionare se il filesystem su cui si va ad operare è
+  su NFS; in tal caso si può adottare una tecnica alternativa che prevede
+  l'uso di \func{link} per creare come file di lock un hard link ad un file
+  esistente; se il link esiste già e la funzione fallisce, la risorsa
+  significa che la risorsa è bloccata e potrà essere sbloccata solo con un
+  \func{unlink}, altrimenti il link è creato ed il lock acquisito; il
+  controllo e l'eventuale acquisizione sono atomici; il difetto di questa
+  soluzione è che funziona solo se si opera all'interno di uno stesso
+  filesystem.}
+
+L'uso di un file di lock presenta però parecchi problemi, che non lo rendono
+una alternativa praticabile per la sincronizzazione:\footnote{ma può essere
+  una tecnica 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 più programmi: qualora trovi un file di lock il
+  programma che cerca di accedere alla seriale si limita a segnalare che la
+  risorsa non è disponibile.}  anzitutto anche in questo caso in caso di
+terminazione imprevista del processo lascia allocata la risorsa (il file di
+lock) e questa deve essere sempre cancellata esplicitamente.  Inoltre il
+controllo della disponibilità può essere fatto solo con una tecnica di
+polling\index{polling}, che è molto inefficiente. 
+
+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'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
+chiusura dei relativi file) e non ci si deve preoccupare di niente, e non
+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}
+\label{sec:ipc_mmap_anonymous}
+
+Abbiamo visto in \secref{sec:file_memory_map} come sia possibile 
+
 
 \section{La comunicazione fra processi di POSIX}
 \label{sec:ipc_posix}
 
 
 \section{La comunicazione fra processi di POSIX}
 \label{sec:ipc_posix}
 
-Lo standard POSIX.1b ha introdotto dei nuovi meccanismi di comunicazione,
-rifacendosi a quelli di System V, introducendo una nuova interfaccia che
-evitasse i principali problemi evidenziati in coda a
-\secref{sec:ipc_sysv_generic}.  
+Per superare i numerosi problemi del \textit{SysV IPC}, evidenziati per i suoi
+aspetti generali in coda a \secref{sec:ipc_sysv_generic} e per i singoli
+oggetti nei paragrafi successivi, lo standard POSIX.1b ha introdotto dei nuovi
+meccanismi di comunicazione, che vanno sotto il nome di POSIX IPC, definendo
+una interfaccia completamente nuova, che tratteremo in questa sezione.
 
 
 
 \subsection{Considerazioni generali}
 \label{sec:ipc_posix_generic}
 
 
 
 
 \subsection{Considerazioni generali}
 \label{sec:ipc_posix_generic}
 
+Il Linux non tutti gli oggetti del POSIX IPC sono supportati nel kernel
+ufficiale; solo la memoria condivisa è presente, ma solo a partire dal kernel
+2.4.x, per gli altri oggetti esistono patch e librerie non
+ufficiali. Nonostante questo è importante esaminare questa interfaccia per la
+sua netta superiorità nei confronti di quella del \textit{SysV IPC}.
 
 
 \subsection{Code di messaggi}
 \label{sec:ipc_posix_mq}
 
 
 
 \subsection{Code di messaggi}
 \label{sec:ipc_posix_mq}
 
+Le code di messaggi non sono supportate a livello del kernel, esse però
+possono essere implementate, usando la memoria condivisa ed i mutex, con
+funzioni di libreria. In generale esse sono comunque poco usate, i socket, nei
+casi in cui sono sufficienti, sono più comodi, e negli altri casi la
+comunicazione può essere gestita direttamente con la stessa metodologia usata
+per implementare le code di messaggi. Per questo ci limiteremo ad una
+descrizione essenziale. 
+
+
 
 \subsection{Semafori}
 \label{sec:ipc_posix_sem}
 
 
 \subsection{Semafori}
 \label{sec:ipc_posix_sem}
 
+Dei semafori POSIX esistono sostanzialmente due implementazioni; una è fatta a
+livello di libreria ed è fornita dalla libreria dei thread; questa però li
+implementa solo a livello di thread e non di processi. Esiste una 
+
 
 \subsection{Memoria condivisa}
 \label{sec:ipc_posix_shm}
 
 
 \subsection{Memoria condivisa}
 \label{sec:ipc_posix_shm}
 
+La memoria condivisa è l'unico degli oggetti di IPC POSIX già presente nel
+kernel ufficiale. 
+
+
 %%% Local Variables: 
 %%% mode: latex
 %%% TeX-master: "gapil"
 %%% Local Variables: 
 %%% mode: latex
 %%% TeX-master: "gapil"