Aggiunte varie sempre sui segnali real-time
[gapil.git] / signal.tex
index 246c308c1f36bb0ab62cfe6ca999cdd6fdd5ed10..ea8454e2555c90322f0e83db3d7db492d783e634 100644 (file)
@@ -120,8 +120,8 @@ int sig_handler()
 Questa è la ragione per cui l'implementazione dei segnali secondo questa
 semantica viene chiamata \textsl{inaffidabile}; infatti la ricezione del
 segnale e la reinstallazione del suo manipolatore non sono operazioni
-atomiche, e sono sempre possibili delle race condition (sull'argomento vedi
-quanto detto in \secref{sec:proc_multi_prog}).
+atomiche, e sono sempre possibili delle race condition\index{race condition}
+(sull'argomento vedi quanto detto in \secref{sec:proc_multi_prog}).
 
 Un'altro problema è che in questa semantica non esiste un modo per bloccare i
 segnali quando non si vuole che arrivino; i processi possono ignorare il
@@ -242,7 +242,8 @@ Un programma pu
 \secref{sec:sig_sigaction}). Se si è installato un manipolatore sarà
 quest'ultimo ad essere eseguito alla notifica del segnale.  Inoltre il sistema
 farà si che mentre viene eseguito il manipolatore di un segnale, quest'ultimo
-venga automaticamente bloccato (così si possono evitare race condition).
+venga automaticamente bloccato (così si possono evitare race
+condition\index{race condition}).
 
 Nel caso non sia stata specificata un'azione, viene utilizzata l'azione
 standard che (come vedremo in \secref{sec:sig_standard}) è propria di ciascun
@@ -411,9 +412,9 @@ tipologia, verr
 \label{sec:sig_prog_error}
 
 Questi segnali sono generati quando il sistema, o in certi casi direttamente
-l'hardware (come per i page fault non validi) rileva un qualche errore
-insanabile nel programma in esecuzione. In generale la generazione di questi
-segnali significa che il programma ha dei gravi problemi (ad esempio ha
+l'hardware (come per i \textit{page fault} non validi) rileva un qualche
+errore insanabile nel programma in esecuzione. In generale la generazione di
+questi segnali significa che il programma ha dei gravi problemi (ad esempio ha
 dereferenziato un puntatore non valido o ha eseguito una operazione aritmetica
 proibita) e l'esecuzione non può essere proseguita.
 
@@ -1121,7 +1122,7 @@ illustrati in precedenza usare; i possibili valori sono riportati in
 Il valore della struttura specificata \param{value} viene usato per settare il
 timer, se il puntatore \param{ovalue} non è nullo il precedente valore viene
 salvato qui. I valori dei timer devono essere indicati attraverso una
-struttura \var{itimerval}, definita in \figref{fig:file_stat_struct}.
+struttura \type{itimerval}, definita in \figref{fig:file_stat_struct}.
 
 La struttura è composta da due membri, il primo, \var{it\_interval} definisce
 il periodo del timer; il secondo, \var{it\_value} il tempo mancante alla
@@ -1145,7 +1146,7 @@ struct itimerval
     \end{lstlisting}
   \end{minipage} 
   \normalsize 
-  \caption{La struttura \var{itimerval}, che definisce i valori dei timer di
+  \caption{La struttura \type{itimerval}, che definisce i valori dei timer di
     sistema.} 
   \label{fig:sig_itimerval}
 \end{figure}
@@ -1472,8 +1473,9 @@ tutti gli stati di terminazione sono stati ricevuti.
 
 Le funzioni esaminate finora fanno riferimento ad alle modalità più elementari
 della gestione dei segnali; non si sono pertanto ancora prese in
-considerazione le tematiche più complesse, collegate alle varie race condition
-che i segnali possono generare e alla natura asincrona degli stessi.
+considerazione le tematiche più complesse, collegate alle varie race
+condition\index{race condition} che i segnali possono generare e alla natura
+asincrona degli stessi.
 
 Affronteremo queste problematiche in questa sezione, partendo da un esempio
 che le evidenzi, per poi prendere in esame le varie funzioni che permettono di
@@ -1540,13 +1542,13 @@ unsigned int sleep(unsigned int seconds)
 
 Questo codice però, a parte il non gestire il caso in cui si è avuta una
 precedente chiamata a \func{alarm} (che si è tralasciato per brevità),
-presenta una pericolosa race condition.  Infatti se il processo viene
-interrotto fra la chiamata di \func{alarm} e \func{pause} può capitare (ad
-esempio se il sistema è molto carico) che il tempo di attesa scada prima
-dell'esecuzione quest'ultima, cosicché essa sarebbe eseguita dopo l'arrivo di
-\macro{SIGALRM}. In questo caso ci si troverebbe di fronte ad un deadlock, in
-quanto \func{pause} non verrebbe mai più interrotta (se non in caso di un
-altro segnale).
+presenta una pericolosa race condition\index{race condition}.  Infatti se il
+processo viene interrotto fra la chiamata di \func{alarm} e \func{pause} può
+capitare (ad esempio se il sistema è molto carico) che il tempo di attesa
+scada prima dell'esecuzione quest'ultima, cosicché essa sarebbe eseguita dopo
+l'arrivo di \macro{SIGALRM}. In questo caso ci si troverebbe di fronte ad un
+deadlock, in quanto \func{pause} non verrebbe mai più interrotta (se non in
+caso di un altro segnale).
 
 Questo problema può essere risolto (ed è la modalità con cui veniva fatto in
 SVr2) usando la funzione \func{longjmp} (vedi \secref{sec:proc_longjmp}) per
@@ -1650,10 +1652,10 @@ quale potr
 segnale, e prendere le relative azioni conseguenti (\texttt{\small 6-11}).
 
 Questo è il tipico esempio di caso, già citato in \secref{sec:proc_race_cond},
-in cui si genera una race condition; se infatti il segnale arriva
-immediatamente dopo l'esecuzione del controllo (\texttt{\small 6}) ma prima
-della cancellazione del flag (\texttt{\small 7}), la sua occorrenza sarà
-perduta.
+in cui si genera una race condition\index{race condition}; se infatti il
+segnale arriva immediatamente dopo l'esecuzione del controllo (\texttt{\small
+  6}) ma prima della cancellazione del flag (\texttt{\small 7}), la sua
+occorrenza sarà perduta.
 
 Questi esempi ci mostrano che per una gestione effettiva dei segnali occorrono
 funzioni più sofisticate di quelle illustrate finora, che hanno origine dalla
@@ -1852,19 +1854,20 @@ in \tabref{tab:sig_sa_flag}.
 \end{table}
 
 Come si può notare in \figref{fig:sig_sigaction} \func{sigaction}
-permette\footnote{La possibilità è prevista dallo standard POSIX.1b, ma in
-  Linux è stata aggiunta a partire dai kernel della serie 2.2.x. In precedenza
-  era possibile ottenere alcune informazioni addizionali usando
-  \var{sa\_handler} con un secondo parametro addizionale di tipo \var{struct
-    sigcontext}, che adesso è deprecato.}  di utilizzare due forme diverse di
-manipolatore, da specificare, a seconda dell'uso o meno del flag
-\macro{SA\_SIGINFO}, rispettivamente attraverso i campi \var{sa\_sigaction} o
-\var{sa\_handler}, (che devono essere usati in maniera alternativa, in certe
-implementazioni questi vengono addirittura definiti come \ctyp{union}): la
-prima è quella classica usata anche con \func{signal}, la seconda permette
-invece di usare un manipolatore in grado di ricevere informazioni più
-dettagliate dal sistema, attraverso la struttura \var{siginfo\_t}, riportata
-in \figref{fig:sig_siginfo_t}.
+permette\footnote{La possibilità è prevista dallo standard POSIX.1b, ed è
+  stata aggiunta nei kernel della serie 2.1.x con l'introduzione dei segnali
+  real-time (vedi \secref{sec:sig_real_time}). In precedenza era possibile
+  ottenere alcune informazioni addizionali usando \var{sa\_handler} con un
+  secondo parametro addizionale di tipo \var{struct sigcontext}, che adesso è
+  deprecato.}  di utilizzare due forme diverse di manipolatore, da
+specificare, a seconda dell'uso o meno del flag \macro{SA\_SIGINFO},
+rispettivamente attraverso i campi \var{sa\_sigaction} o \var{sa\_handler},
+(che devono essere usati in maniera alternativa, in certe implementazioni
+questi vengono addirittura definiti come \ctyp{union}): la prima è quella
+classica usata anche con \func{signal}, la seconda permette invece di usare un
+manipolatore in grado di ricevere informazioni più dettagliate dal sistema,
+attraverso la struttura \type{siginfo\_t}, riportata in
+\figref{fig:sig_siginfo_t}.
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -1889,29 +1892,41 @@ siginfo_t {
     \end{lstlisting}
   \end{minipage} 
   \normalsize 
-  \caption{La struttura \var{siginfo\_t}.} 
+  \caption{La struttura \type{siginfo\_t}.} 
   \label{fig:sig_siginfo_t}
 \end{figure}
  
 Installando un manipolatore di tipo \var{sa\_sigaction} diventa allora
 possibile accedere alle informazioni restituite attraverso il puntatore a
 questa struttura. Tutti i segnali settano i campi \var{si\_signo}, che riporta
-il segnale ricevuto, \var{si\_errno}, che riporta il codice di errore, e
-\var{si\_code}, che viene usato per indicare la ragione per cui è stato emesso
-il segnale (come i dettagli sul tipo di errore per \macro{SIGFPE} e
-\macro{SIGILL}) ed ha valori diversi\footnote{un elenco dettagliato è
-  disponibile nella man page di \func{sigaction}.} a seconda del tipo di
-segnale ricevuto.
-
-Il resto della struttura può essere definito come \ctyp{union} ed i valori
+il numero del segnale ricevuto, \var{si\_errno}, che riporta, quando diverso
+da zero, il codice dell'errore associato al segnale, e \var{si\_code}, che
+viene usato dal kernel per specificare maggiori dettagli riguardo l'evento che
+ha causato l'emissione del segnale.
+
+In generale \var{si\_code} contiene, per i segnali generici, per quelli
+real-time e per tutti quelli inviati tramite \func{kill}, informazioni circa
+l'origine del segnale (se generato dal kernel, da un timer, da \func{kill},
+ecc.). Alcuni segnali però usano \var{si\_code} per fornire una informazione
+specifica: ad esempio i vari segnali di errore (\macro{SIGFPE},
+\macro{SIGILL}, \macro{SIGBUS} e \macro{SIGSEGV}) lo usano per fornire
+maggiori dettagli riguardo l'errore (come il tipo di errore aritmetico, di
+istruzione illecita o di violazione di memoria) mentre alcuni segnali di
+controllo (\macro{SIGCHLD}, \macro{SIGTRAP} e \macro{SIGPOLL}) forniscono
+altre informazioni speecifiche.  In tutti i casi il valore del campo è
+riportato attraverso delle costanti (le cui definizioni si trovano
+\file{bits/siginfo.h}) il cui elenco dettagliato è disponibile nella man page
+di \func{sigaction}.
+
+Il resto della struttura è definito come \ctyp{union} ed i valori
 eventualmente presenti dipendono dal segnale, così \macro{SIGCHLD} ed i
-segnali POSIX.1b\footnote{NdA trovare quale sono e completare l'informazione.}
-inviati tramite \func{kill} avvalorano \var{si\_pid} e \var{si\_uid} coi
-valori corrispondenti al processo che ha emesso il segnale, \macro{SIGILL},
-\macro{SIGFPE}, \macro{SIGSEGV} e \macro{SIGBUS} avvalorano \var{si\_addr} con
-l'indirizzo cui è avvenuto l'errore, \macro{SIGIO} (vedi
-\secref{sec:file_asyncronous_io}) e \macro{SIGPOLL} avvalorano \var{si\_fd}
-con il numero del file descriptor.
+segnali real-time (vedi \secref{sec:sig_real_time}) inviati tramite
+\func{kill} avvalorano \var{si\_pid} e \var{si\_uid} coi valori corrispondenti
+al processo che ha emesso il segnale, \macro{SIGILL}, \macro{SIGFPE},
+\macro{SIGSEGV} e \macro{SIGBUS} avvalorano \var{si\_addr} con l'indirizzo cui
+è avvenuto l'errore, \macro{SIGIO} (vedi \secref{sec:file_asyncronous_io})
+avvalora \var{si\_fd} con il numero del file descriptor e \var{si\_band} per i
+dati urgenti su un socket.
 
 Benché sia possibile usare nello stesso programma sia \func{sigaction} che
 \func{signal} occorre molta attenzione, in quanto le due funzioni possono
@@ -2048,15 +2063,15 @@ occorre ricordare che qualunque modifica alla maschera dei segnali viene
 perduta alla conclusione del terminatore. 
 
 Benché con l'uso di \func{sigprocmask} si possano risolvere la maggior parte
-dei casi di race condition restano aperte alcune possibilità legate all'uso di
-\func{pause}; il caso è simile a quello del problema illustrato nell'esempio
-di \secref{fig:sig_sleep_incomplete}, e cioè la possibilità che il processo
-riceva il segnale che si intende usare per uscire dallo stato di attesa
-invocato con \func{pause} immediatamente prima dell'esecuzione di
-quest'ultima. Per poter effettuare atomicamente la modifica della maschera dei
-segnali (di solito attivandone uno specifico) insieme alla sospensione del
-processo lo standard POSIX ha previsto la funzione \func{sigsuspend}, il cui
-prototipo è:
+dei casi di race condition\index{race condition} restano aperte alcune
+possibilità legate all'uso di \func{pause}; il caso è simile a quello del
+problema illustrato nell'esempio di \secref{fig:sig_sleep_incomplete}, e cioè
+la possibilità che il processo riceva il segnale che si intende usare per
+uscire dallo stato di attesa invocato con \func{pause} immediatamente prima
+dell'esecuzione di quest'ultima. Per poter effettuare atomicamente la modifica
+della maschera dei segnali (di solito attivandone uno specifico) insieme alla
+sospensione del processo lo standard POSIX ha previsto la funzione
+\func{sigsuspend}, il cui prototipo è:
 \begin{prototype}{signal.h}
 {int sigsuspend(const sigset\_t *mask)} 
   
@@ -2084,14 +2099,9 @@ presenta neanche questa necessit
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
     \begin{lstlisting}{}
-#include <unistd.h>      /* unix standard library */
-#include <signal.h>      /* POSIX signal library */
 void alarm_hand(int);
 unsigned int sleep(unsigned int seconds)
 {
-/* 
- * Variables definition  
- */
     struct sigaction new_action, old_action;
     sigset_t old_mask, stop_mask, sleep_mask;
     /* set the signal handler */
@@ -2115,9 +2125,6 @@ unsigned int sleep(unsigned int seconds)
     /* return remaining time */
     return alarm(0);
 }
-/*
- * Signal Handler for SIGALRM
- */
 void alarm_hand(int sig) 
 {
     return;     /* just return to interrupt sigsuspend */
@@ -2146,18 +2153,18 @@ fine (\texttt{\small 27}), e al contempo si prepara la maschera dei segnali
 \var{sleep\_mask} per riattivare \macro{SIGALRM} all'esecuzione di
 \func{sigsuspend}.  
 
-In questo modo non sono più possibili race condition dato che \macro{SIGALRM}
-viene disabilitato con \func{sigprocmask} fino alla chiamata di
-\func{sigsuspend}. Questo metodo è assolutamente generale e può essere
-applicato a qualunque altra situazione in cui si deve attendere per un
+In questo modo non sono più possibili race condition\index{race condition}
+dato che \macro{SIGALRM} viene disabilitato con \func{sigprocmask} fino alla
+chiamata di \func{sigsuspend}. Questo metodo è assolutamente generale e può
+essere applicato a qualunque altra situazione in cui si deve attendere per un
 segnale, i passi sono sempre i seguenti:
-\begin{enumerate}
+\begin{enumerate*}
 \item Leggere la maschera dei segnali corrente e bloccare il segnale voluto
   con \func{sigprocmask}. 
 \item Mandare il processo in attesa con \func{sigsuspend} abilitando la
   ricezione del segnale voluto.
 \item Ripristinare la maschera dei segnali originaria.
-\end{enumerate}
+\end{enumerate*}
 Per quanto possa sembrare strano bloccare la ricezione di un segnale per poi
 riabilitarla immediatamente dopo, in questo modo si evita il deadlock dovuto
 all'arrivo del segnale prima dell'esecuzione di \func{sigsuspend}.
@@ -2193,7 +2200,7 @@ sistema un altro stack (invece di quello relativo al processo, vedi
 \secref{sec:proc_mem_layout}) solo durante l'esecuzione di un
 manipolatore. L'uso di uno stack alternativo è del tutto trasparente ai
 manipolatori, occorre però seguire una certa procedura:
-\begin{enumerate}
+\begin{enumerate*}
 \item Allocare un'area di memoria di dimensione sufficiente da usare come
   stack alternativo.
 \item Usare la funzione \func{sigaltstack} per rendere noto al sistema
@@ -2202,7 +2209,7 @@ manipolatori, occorre per
   specificando il flag \macro{SA\_ONSTACK} (vedi \tabref{tab:sig_sa_flag}) per
   dire al sistema di usare lo stack alternativo durante l'esecuzione del
   manipolatore. 
-\end{enumerate}
+\end{enumerate*}
 
 In genere il primo passo viene effettuato allocando un'opportuna area di
 memoria con \code{malloc}; in \file{signal.h} sono definite due costanti,
@@ -2332,6 +2339,140 @@ parte l'uso di \type{sigjmp\_buf} per \param{env}, 
 \func{longjmp}.
 
 
+
+\subsection{I segnali real-time}
+\label{sec:sig_real_time}
+
+
+Lo standard POSIX.1b, nel definire una serie di nuove interfacce per i servizi
+real-time, ha introdotto una estensione del modello classico dei segnali che
+presenta dei significativi miglioramenti,\footnote{questa estensione è stata
+  introdotta in Linux a partire dal kernel 2.1.43(?), e dalle \acr{glibc}
+  2.1(?).} in particolare sono stati superati tre limiti fondamentali dei
+segnali classici:
+\begin{description}
+\item[I segnali non sono accumulati] 
+  
+  se più segnali vengono generati prima dell'esecuzione di un manipolatore
+  questo sarà eseguito una sola volta, ed il processo non sarà in grado di
+  accorgersi di quante volte l'evento che ha generato il segnale è accaduto.
+\item[I segnali non trasportano informazione] 
+  
+  i segnali classici non prevedono prevedono altra informazione sull'evento
+  che li ha generati se non il fatto che sono stati emessi (tutta
+  l'informazione che il kernel associa ad un segnale è il suo numero).
+\item[I segnali non hanno un ordine di consegna] 
+
+  l'ordine in cui diversi segnali vengono consegnati è casuale e non
+  prevedibile. Non è possibile stabilire una priorità per cui la reazione a
+  certi segnali ha la precedenza rispetto ad altri.
+\end{description}
+
+
+Per poter superare queste limitazioni lo standard ha introdotto delle nuove
+caratteristiche, che sono state associate ad una nuova classe di segnali, che
+vengono chiamati \textsl{segnali real-time}, in particolare:
+
+\begin{itemize*}
+\item i segnali sono inseriti in una coda che permette di consegnare istanze
+  multiple dello stesso segnale qualora esso venga inviato più volte prima
+  dell'esecuzione del manipolatore; si assicura così che il processo riceva un
+  segnale per ogni occorrenza dell'evento che lo genera.
+\item è stata introdotta una priorità nella consegna dei segnali: i segnali
+  vengono consegnati in ordine a seconda del loro valore, partendo da quelli
+  con un numero minore, che pertanto hanno una priorità maggiore.
+\item è stata introdotta la possibilità di restituire dei dati al
+  manipolatore, attraverso l'uso di un campo apposito nella struttura
+  \type{siginfo\_t} accessibile tramite manipolatori di tipo
+  \var{sa\_sigaction}.
+\end{itemize*}
+
+Queste nuove caratteristiche (eccetto l'ultima, che, come visto in
+\secref{sec:sig_sigaction}, è parzialmente disponibile anche con i segnali
+ordinari) si applicano solo ai nuovi segnali real-time; questi ultimi sono
+accessibili in un range di valori specificati dalle due macro \macro{SIGRTMIN}
+e \macro{SIGRTMAX},\footnote{in Linux di solito il primo valore è 32, ed il
+  secondo \code{\_NSIG-1}, che di norma è 63, per un totale di 32 segnali
+  disponibili, contro gli almeno 8 richiesti da POSIX.1b.} che specificano il
+numero minimo e massimo associato ad un segnale real-time.
+
+I segnali con un numero più basso hanno una priorità maggiore e vengono
+consegnati per primi, inoltre i segnali real-time non possono interrompere
+l'esecuzione di un manipolatore di un segnale a priorità più alta; la loro
+azione di default è quella di terminare il programma.  I segnali ordinari
+hanno tutti la stessa priorità, che è più alta di quella di qualunque segnale
+real-time.
+
+Si tenga presente che questi nuovi segnali non sono associati a nessun evento
+sepcifico (a meno di non utilizzarli, come vedremo in
+\secref{sec:file_asyncronous_io}, per l'I/O asincrono) e devono essere inviati
+esplicitamente. Tutti i segnali real-time restituiscono al manipolatore, oltre
+ai campi \var{si\_pid} e \var{si\_uid} di \type{siginfo\_t} una struttura
+\type{sigval} (riportata in \figref{fig:sig_sigval}) in cui può essere
+restituito al processo un valore o un indirizzo, che costituisce il meccanismo
+con cui il segnale è in grado di inviare una ulteriore informazione al
+processo.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
+union sigval {
+        int sival_int;
+        void *sival_ptr;
+}
+          \end{lstlisting}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \type{sigval}, usata dai segnali real time per
+    restituire dati al manipolatore.}
+  \label{fig:sig_sigval}
+\end{figure}
+
+A causa di queste loro caratteristiche, la funzione \func{kill} non è adatta
+ad inviare un segnale real time, in quanto non è in grado di fornire alcun
+valore per \var{sigval}; per questo motivo lo standard ha previsto una nuova
+funzione, \func{sigqueue}, il cui prototipo è:
+\begin{prototype}{signal.h}
+  {int sigqueue(pid\_t pid, int signo, const union sigval value)}
+  
+  Invia il segnale \param{signo} al processo \param{pid}, restituendo al
+  manipolatore il valore \param{value}.
+  
+  \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+    errore, nel qual caso \var{errno} viene settata ai valori:
+  \begin{errlist}
+  \item[\macro{EAGAIN}] La coda è esarita, ci sono già \macro{SIGQUEUE\_MAX}
+    segnali in attesa si consegna.
+  \item[\macro{EPERM}] Non si hanno privilegi appropriati per inviare il
+    segnale al processo specificato.
+  \item[\macro{ESRCH}] Il processo \param{pid} non esiste.
+  \item[\macro{EINVAL}] Si è specificato un valore non valido per
+    \param{signo}.
+  \end{errlist}
+  ed inoltre \macro{ENOMEM}.}
+\end{prototype}
+
+Il comportamento della funzione è analogo a quello di \func{kill}, ed i
+privilegi occorrenti ad inviare il segnale ad un determinato processo sono gli
+stessi; un valore nullo di \func{signo} permette di verificare le condizioni
+di errore senza inviare nessun segnale.
+
+Se il segnale è bloccato la funzione ritorna immediatamente, se si è
+installato un manipolatore con \macro{SA\_SIGINFO} e ci sono risorse
+disponibili, vale a dire che c'è posto nella coda\footnote{la profondità della
+  coda è indicata dalla costante \macro{SIGQUEUE\_MAX}, una della tante
+  costanti di sistema definite dallo standard POSIX, che non abbiamo riportato
+  esplicitamente in \secref{sec:sys_limits}. Il suo valore minimo secondo lo
+  standard, \macro{\_POSIX\_SIGQUEUE\_MAX}, è pari a 32.}, esso viene inserito
+e diventa pendente; una volta consegnato riporterà nel campo \var{si\_code} di
+\var{siginfo} il valore \macro{SI\_QUEUE} e il campo \var{si\_value} riceverà
+quanto inviato con \param{value}. Se invece si è installato un manipolatore
+nella forma classica il segnale sarà generato, ma in caso di emissioni
+multiple prima dell'esecuzione del manipolatore, sarà ricevuto una sola volta.
+
+
+
 %%% Local Variables: 
 %%% mode: latex
 %%% TeX-master: "gapil"