\textit{unreliable}).
Nella semantica \textsl{inaffidabile} (quella implementata dalle prime
-versioni di unix) la routine di gestione del segnale specificata dall'utente
+versioni di Unix) la routine di gestione del segnale specificata dall'utente
non resta attiva una volta che è stata eseguita; è perciò compito dell'utente
stesso ripetere l'installazione della stessa all'interno della routine di
gestione, in tutti i casi in cui si vuole che il manipolatore esterno resti
è specificata una azione diversa (nel qual caso solo i segnali successivi alla
nuova specificazione saranno notificati).
-Una volta che il segnale viene notificato (che questo avvenga subito o dopo
-una attesa più o meno lunga) viene eseguita l'azione specificata per detto
+Una volta che un segnale viene notificato (che questo avvenga subito o dopo
+una attesa più o meno lunga) viene eseguita l'azione specificata per il
segnale. Per alcuni segnali (\macro{SIGKILL} e \macro{SIGSTOP}) questa azione
-è fissa e non può essere cambiata, ma per tutti gli altri si può specificare
-una scelta fra le tre seguenti:
+è fissa e non può essere cambiata, ma per tutti gli altri si può selezionare
+una delle tre possibilità seguenti:
\begin{itemize*}
-\item \textsl{ignorare} il segnale.
-\item \textsl{catturare} il segnale, ed utilizzare il manipolatore
- specificato.
+\item ignorare il segnale.
+\item catturare il segnale, ed utilizzare il manipolatore specificato.
\item accettare l'azione di default per quel segnale.
\end{itemize*}
-Un programma può specificare queste scelte usano le due funzioni \func{signal}
-e \func{sigaction} (vedi \secref{sec:sig_signal} e ); se si è installato un
-manipolatore sarà quest'ultimo ad essere eseguito alla notifica del segnale.
-Inoltre il sistema fa si che mentre viene eseguito il manipolatore di un
-segnale, questo ultimo venga automaticamente bloccato (così si possono evitare
-race condition).
+Un programma può specificare queste scelte usando le due funzioni
+\func{signal} e \func{sigaction} (vedi \secref{sec:sig_signal} e
+\secref{sec:sig_sigaction}); se si è installato un manipolatore sarà
+quest'ultimo ad essere eseguito alla notifica del segnale. Inoltre il sistema
+fa si che mentre viene eseguito il manipolatore di un segnale, questo ultimo
+venga automaticamente bloccato (così si possono evitare race condition).
-Se arriva un segnale per il quale non è stato specificata un'azione viene
-utilizzata l'azione standard. Questa è diversa da segnale a segnale (come
-vedremo in \secref{sec:sig_standard}); nella maggior parte dei casi essa
-comporta la terminazione del processo, per alcuni segnali che rappresentano
-eventi innocui invece l'azione di default è quella di essere ignorati.
+Nel caso non sia stata specificata un'azione, viene utilizzata l'azione
+standard che (come vedremo in \secref{sec:sig_standard}) è propria di ciascun
+segnale; nella maggior parte dei casi essa porta alla terminazione del
+processo, ma alcuni segnali che rappresentano eventi innocui vengono ignorati.
Quando un segnale termina un processo, il padre può determinare la causa della
terminazione esaminando il codice di stato riportato delle funzioni
I segnali che rappresentano errori del programma (divisione per zero o
violazioni di accesso) hanno anche la caratteristica di scrivere un file di
-\textit{core dump} che registra lo stato del processo prima della
-terminazione, che e può essere esaminato da un debugger per investigare sulla
-causa dell'errore. Lo stesso avviene se i suddetti segnale vengono generati
-con una \func{kill}.
+\textit{core dump} che registra lo stato del processo (ed in particolare della
+memoria e dello stack) prima della terminazione. Questo può essere esaminato
+in seguito con un debugger per investigare sulla causa dell'errore. Lo stesso
+avviene se i suddetti segnale vengono generati con una \func{kill}.
+
\section{La classificazione dei segnali}
\label{sec:sig_classification}
-Esamineremo in questa sezione i vari segnali definiti nel sistema, le loro
-caratteristiche e tipologia, le varie macro e costanti che permettono di
-identificarli, e le funzioni che ne stampano la descrizione.
+Esamineremo in questa sezione quali sono i vari segnali definiti nel sistema,
+le loro caratteristiche e tipologia, le varie macro e costanti che permettono
+di identificarli, e le funzioni che ne stampano la descrizione.
\subsection{I segnali standard}
Ciascun segnale è identificato rispetto al sistema da un numero, ma l'uso
diretto di questo numero da parte dei programmi è da evitare, in quanto esso
-può variare a seconda dell'implementazione del sistema.
+può variare a seconda dell'implementazione del sistema, e nel caso si Linux,
+anche a seconda dell'architettura hardware.
\begin{table}[htb]
\footnotesize
\textbf{Segnale}&\textbf{Standard}&\textbf{Azione}&\textbf{Descrizione} \\
\hline
\hline
- \macro{SIGHUP} &PL& A &Hangup o fine del processo di controllo\\
- \macro{SIGINT} &PL& A &Interrupt da tastiera (\cmd{C-c})\\
- \macro{SIGQUIT} &PL& C &Quit da tastiera (\cmd{C-y}) \\
- \macro{SIGILL} &PL& C & Istruzione illegale\\
- \macro{SIGABRT} &PL& C & Segnale di abort da \func{abort} \\
- \macro{SIGFPE} &PL& C & Errore aritmetico\\
- \macro{SIGKILL} &PL&AEF& Segnale di terminazione forzata \\
- \macro{SIGSEGV} &PL& C & Errore di accesso in memoria\\
- \macro{SIGPIPE} &PL& A & Pipe spezzata\\
- \macro{SIGALRM} &PL& A & Segnale del timer da \func{alarm} \\
- \macro{SIGTERM} &PL& A & Segnale di terminazione \verb|C-\|\\
- \macro{SIGUSR1} &PL& A & Segnale utente numero 1\\
- \macro{SIGUSR2} &PL& A & Segnale utente numero 2\\
- \macro{SIGCHLD} &PL& B & Figlio terminato o fermato\\
- \macro{SIGCONT} &PL& & Continua se fermato\\
- \macro{SIGSTOP} &PL&DEF& Ferma il processo\\
- \macro{SIGTSTP} &PL& D & Stop typed at tty \\
- \macro{SIGTTIN} &PL& D & Input sul terminale per un processo
- in background\\
- \macro{SIGTTOU} &PL& D & Output sul terminale per un processo
- in background\\
- \macro{SIGBUS} &SL& C & Errore sul bus (bad memory access) \\
- \macro{SIGPOLL} &SL& A & Pollable event (Sys V).
- Sinonimo di \macro{SIGIO}\\
- \macro{SIGPROF} &SL& A & Timer del profiling scaduto \\
- \macro{SIGSYS} &SL& C & Bad argument to routine (SVID)\\
- \macro{SIGTRAP} &SL & C & Trace/breakpoint trap \\
- \macro{SIGURG} &SLB& B & Urgent condition on socket\\
- \macro{SIGVTALRM}&SLB& A & Virtual alarm clock\\
- \macro{SIGXCPU} &SLB& C & Ecceduto il limite sul CPU time\\
- \macro{SIGXFSZ} &SLB& C & Ecceduto il limite sulla dimezsione dei file\\
- \macro{SIGIOT} &L & C & IOT trap. A synonym for SIGABRT \\
- \macro{SIGEMT} &L & & \\
- \macro{SIGSTKFLT}&L & A & Stack fault on coprocessor \\
- \macro{SIGIO} &LB& A & I/O now possible (4.2 BSD) \\
- \macro{SIGCLD} &L & & A synonym for SIGCHLD \\
- \macro{SIGPWR} &L & A & Power failure (System V) \\
- \macro{SIGINFO} &L & & A synonym for SIGPWR \\
- \macro{SIGLOST} &L & A & File lock lost \\
- \macro{SIGWINCH} &LB& B & Window resize signal (4.3 BSD, Sun) \\
- \macro{SIGUNUSED}&L & A & Unused signal (will be SIGSYS) \\
+ \macro{SIGHUP} &PL & A & Hangup o fine del processo di controllo \\
+ \macro{SIGINT} &PL & A & Interrupt da tastiera (\cmd{C-c}) \\
+ \macro{SIGQUIT} &PL & C & Quit da tastiera (\cmd{C-y}) \\
+ \macro{SIGILL} &PL & C & Istruzione illegale \\
+ \macro{SIGABRT} &PL & C & Segnale di abort da \func{abort} \\
+ \macro{SIGFPE} &PL & C & Errore aritmetico \\
+ \macro{SIGKILL} &PL &AEF& Segnale di terminazione forzata \\
+ \macro{SIGSEGV} &PL & C & Errore di accesso in memoria \\
+ \macro{SIGPIPE} &PL & A & Pipe spezzata \\
+ \macro{SIGALRM} &PL & A & Segnale del timer da \func{alarm} \\
+ \macro{SIGTERM} &PL & A & Segnale di terminazione \verb|C-\| \\
+ \macro{SIGUSR1} &PL & A & Segnale utente numero 1 \\
+ \macro{SIGUSR2} &PL & A & Segnale utente numero 2 \\
+ \macro{SIGCHLD} &PL & B & Figlio terminato o fermato \\
+ \macro{SIGCONT} &PL & & Continua se fermato \\
+ \macro{SIGSTOP} &PL &DEF& Ferma il processo \\
+ \macro{SIGTSTP} &PL & D & Stop typed at tty \\
+ \macro{SIGTTIN} &PL & D & Input sul terminale per un processo
+ in background \\
+ \macro{SIGTTOU} &PL & D & Output sul terminale per un processo
+ in background \\
+ \macro{SIGBUS} &SL & C & Errore sul bus (bad memory access) \\
+ \macro{SIGPOLL} &SL & A & Pollable event (Sys V).
+ Sinonimo di \macro{SIGIO} \\
+ \macro{SIGPROF} &SL & A & Timer del profiling scaduto \\
+ \macro{SIGSYS} &SL & C & Bad argument to routine (SVID) \\
+ \macro{SIGTRAP} &SL & C & Trace/breakpoint trap \\
+ \macro{SIGURG} &SLB& B & Urgent condition on socket \\
+ \macro{SIGVTALRM}&SLB& A & Virtual alarm clock \\
+ \macro{SIGXCPU} &SLB& C & Ecceduto il limite sul CPU time \\
+ \macro{SIGXFSZ} &SLB& C & Ecceduto il limite sulla dimensione dei file \\
+ \macro{SIGIOT} &L & C & IOT trap. A synonym for \macro{SIGABRT} \\
+ \macro{SIGEMT} &L & & \\
+ \macro{SIGSTKFLT}&L & A & Stack fault on coprocessor \\
+ \macro{SIGIO} &LB & A & I/O now possible (4.2 BSD) \\
+ \macro{SIGCLD} &L & & A synonym for \macro{SIGCHLD} \\
+ \macro{SIGPWR} &L & A & Fallimento dell'alimentazione \\
+ \macro{SIGINFO} &L & & A synonym for \macro{SIGPWR} \\
+ \macro{SIGLOST} &L & A & Perso un lock sul file (per NFS) \\
+ \macro{SIGWINCH} &LB & B & Window resize signal (4.3 BSD, Sun) \\
+ \macro{SIGUNUSED}&L & A & Unused signal (will be SIGSYS) \\
\hline
\end{tabular}
\caption{Lista dei segnali in Linux.}
\label{tab:sig_signal_list}
\end{table}
-Per questo motivo ad ogni segnale viene associato un nome, che corrisponde,
-tramite una macro di preprocessore, al suddetto numero. Sono questi nomi, che
-sono standardizzati e sostanzialemnte uniformi rispetto alle varie
+Per questo motivo ad ogni segnale viene associato un nome, definendo con una
+macro di preprocessore una costante uguale al suddetto numero. Sono questi
+nomi, che sono standardizzati e sostanzialemnte uniformi rispetto alle varie
implementazioni, che si devono usare nei programmi. Tutti i nomi e le funzioni
che concernono i segnali sono definiti nell'header di sistema \file{signal.h}.
\hline
P & POSIX. \\
B & BSD. \\
- L & Linux \\
- S & SUSv2 \\
+ L & Linux.\\
+ S & SUSv2.\\
\hline
\end{tabular}
\caption{Legenda dei valori della colonna \textbf{Standard} di
Una modalità alternativa per utilizzare le descrizioni restituite da
\func{strsignal} e \func{psignal} è quello di fare usare la variabile
-\var{sys\_siglist}, che può essere acceduta dichiarando:
+\var{sys\_siglist}, che è definita in \file{signal.h} e può essere acceduta
+con la dichiarazione:
\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
extern const char *const sys_siglist[]
\end{lstlisting}
-\var{sys\_siglist} contiene le stringhe di descrizione indicizzate per numero
-di segnale, per cui \code{char *decr = strsignal(SIGINT)} può essere
-sostituito dall'equivalente \code{char *decr = sys\_siglist[SIGINT]}.
+l'array \var{sys\_siglist} contiene i puntatori alle stringhe di descrizione,
+indicizzate per numero di segnale, per cui una chiamata del tipo di \code{char
+ *decr = strsignal(SIGINT)} può essere sostituita dall'equivalente \code{char
+ *decr = sys\_siglist[SIGINT]}.
\section{La gestione dei segnali}
-\label{sec:sig_handlers}
+\label{sec:sig_management}
+
+I segnali sono il primo e più classico esempio di eventi asincroni, cioè di
+eventi che possono accadere in un qualunque momento durante l'esecuzione di un
+programma. Per questa loro caratteristica la loro gestione non può essere
+effettuata all'interno del normale flusso di esecuzione dello stesso, ma è
+delegata appunto agli eventuali manipolatori che si sono installati.
+
+In questa sezione vedremo come si effettua gestione dei segnali, a partire
+dalla loro interazione con le system call, passando per le varie funzioni che
+permettono di installare i manipolatori e controllare le reazioni di un
+processo alla loro occorrenza.
+
+
+\subsection{Il comportamento generale del sistema.}
+\label{sec:sig_gen_beha}
+
+Abbiamo già trattato in \secref{sec:sig_intro} le modalità con cui il sistema
+gestisce l'interazione fra segnali e processi, ci resta da esaminare però il
+comportamento delle system call; in particolare due di esse, \func{fork} ed
+\func{exec}, dovranno essere prese esplicitamente in considerazione, data la
+loro stretta relazione con la creazione di nuovi processi.
+
+Come accennato in \secref{sec:proc_fork} quando viene creato un nuovo processo
+con \func{fork} esso eredita dal padre sia le azioni che sono state settate
+per i singoli segnali, che la maschera dei segnali bloccati (tratteremo
+quest'ultimo argomento in \ref{sec:sig_sigpending}). Invece tutti i segnali
+pendenti e gli allarmi vengono cancellati; essi infatti devono essere
+recapitati solo al padre, al figlio dovranno arrivare solo i segnali dovuti
+alle sue azioni.
+
+Quando si mette in esecuzione un nuovo programma con \func{exec} (si ricordi
+quanto detto in \secref{sec:prog_exec}) tutti i segnali per i quali è stato
+installato un manipolatore vengono resettati a \macro{SIG\_DFL}. Non ha più
+senso infatti fare riferimento a funzioni definite nel programma originario,
+che non sono nemmeno presenti nello spazio di indirizzi del nuovo programma.
+
+Si noti che questo vale solo per le azioni per le quali è stato installato un
+manipolatore; viene mantenuto invece ogni eventuale settaggio dell'azione a
+\macro{SIG\_IGN}. Questo permette ad esempio alla shell di settare ad
+\macro{SIG\_IGN} le risposte per \macro{SIGINT} e \macro{SIGQUIT} per i
+programmi eseguiti in background, che altrimenti sarebbero interrotti da una
+successiva pressione di \texttt{C-c} o \texttt{C-y}.
+
+Per quanto riguarda tutte le altre system call esse vengono tradizionalmente
+classificate, proprio in base al loro comportamento nei confronti dei segnali,
+in \textsl{lente} (\textit{slow}) e \textsl{veloci} (\textit{fast}). La gran
+parte appartiene a quest'ultima categoria che non è influenzata dall'arrivo di
+un segnale. In tal caso un eventuale manipolatore viene sempre eseguito dopo
+che la system call è stata completata. Esse sono dette \textsl{veloci} proprio
+in quanto la loro esecuzione è sostanzialmente immediata e attendere per
+eseguire un manipolatore non comporta nessun inconveniente.
+
+Esistono però dei casi in cui questo non è possibile perché renderebbe
+impossibile una risposta pronta al segnale. In generale questo avviene tutte
+le volte che si ha a che fare con system call che possono bloccarsi
+indenfinitamente, che per questo vengono chiamate \textsl{lente}. Un elenco
+dei casi in cui si presenta questa situazione è il seguente:
+\begin{itemize*}
+\item lettura da file che possono bloccarsi in attesa di dati non ancora
+ presenti (come per certi dispositivi, la rete o le pipe).
+\item scrittura sugli stessi file, nel caso in cui dati non possano essere
+ accettati immediatamente.
+\item apertura di un file di dipositivo che richiede operazioni non immediate
+ per una una risposta.
+\item operazioni eseguite con \func{ioctl} che non è detto possano essere
+ eseguite immediatamente.
+\item le funzioni di intercomunicazione che si bloccano in attesa di risposte
+ da altri processi.
+\item la funzione \func{pause} (usata appunto per attendere l'arrivo di un
+ segnale).
+\item la funzione \func{wait} (se nessun processo figlio è ancora terminato).
+\end{itemize*}
+
+In questo caso si pone il problema di cosa fare una volta che il manipolatore
+sia ritornato. La scelta originaria dei primi Unix era quella di far ritornare
+anche la system call restituendo l'errore di \macro{EINTR}. Questa è a
+tutt'oggi una scelta corrente, ma comporta che i programmi che usano dei
+manipolatori controllino lo stato di uscita delle funzioni per ripeterne la
+chiamata qualora l'errore fosse questo.
+
+Dimenticarsi di richiamare una system call interrotta da un segnale è un
+errore comune, tanto che le \acr{glibc} provvedono una macro
+\code{TEMP\_FAILURE\_RETRY(expr)} che esegue l'operazione automaticamente,
+ripetendo l'esecuzione dell'espressione \var{expr} fintanto che il risultato
+non è diverso dall'uscita con un errore \macro{EINTR}.
-I segnali sono il primo e più classico esempio di eventi asincroni, che
-possono accadere in un qualunque momento durante l'esecuzione di un programma.
-Non essendo sotto il controllo del programma la gestione dei segnali non potrà
-essere controllata all'interno del flusso di esecuzione di quest'ultimo, ma
-tutto quello che si potrà fare è di specificare (al kernel, che li genera)
-quale azione andrà intrapresa quando essi si verificano.
+La soluzione è comunque poco elegante e BSD ha scelto un approccio molto
+diverso, che è quello di fare ripartire automaticamente la system call invece
+di farla fallire. In questo caso ovviamente non c'è da preoccuparsi di
+controllare il codice di errore; si perde però la possibilità di eseguire
+azioni specifiche all'occorrenza di questa particolare condizione.
-In questa sezione vedremo allora come si gestiscono i segnali, esaminando le
-funzioni che si usano per effettuare la gestione dei segnali ed analizzando le
-problematiche relative alla gestione di eventi asincroni di questo tipo.
+Linux e le \acr{glibc} consentono di utilizzare entrambi gli approcci,
+attraverso una opportuna opzione di \func{sigaction} (vedi
+\secref{sec:sig_sigaction}). È da chiarire comunque che nel caso di
+interruzione nel mezzo di un trasferimento parziale di dati, le system call
+ritornano sempre indicando i byte trasferiti.
\subsection{La funzione \func{signal}}
\label{sec:sig_signal}
-L'interfaccia più semplice alla manipolazione dei segnali è costituita dalla
-funzione \func{signal}; questa funzione è definita fin dallo standard ANSI C
-che però non considera sistemi multitasking, per cui la sua definizione in
-tale standard è tanto vaga da essere del tutto inutile in un sistema unix, per
-questo ogni implementazione successiva ne ha modificato e ridefinito il
+L'interfaccia più semplice per la gestione dei segnali è costituita dalla
+funzione \func{signal} che è definita fin dallo standard ANSI C. Quest'ultimo
+però non considera sistemi multitasking, per cui la definizione è tanto vaga
+da essere del tutto inutile in un sistema Unix; è questo il motivo per cui
+ogni implementazione successiva ne ha modificato e ridefinito il
comportamento, pur mantenendone immutato il prototipo\footnote{in realtà
alcune vecchie implementazioni (SVR4 e 4.3+BSD) usano parametri aggiuntivi
per definire il comportamento della funzione} che è:
\begin{prototype}{signal.h}
{sighandler\_t signal(int signum, sighandler\_t handler)}
- Installa una nuova funzione di gestione (manipolatore) per il segnale
- \param{signum}, usando il manipolatore \param{handler}.
+ Installa la funzione di gestione \param{handler} (il manipolatore) per il
+ segnale \param{signum}.
\bodydesc{La funzione ritorna il precedente manipolatore in caso di successo
o \macro{SIG\_ERR} in caso di errore.}
\end{prototype}
In questa definizione si è usato il tipo \type{sighandler\_t} che è una
-estensione GNU definita in Linux che permette di riscrivere il prototipo in
-forma più leggibile dell'originario \code{void (*signal(int signum, void
- (*handler)(int)))int)}, e che è sostanzialmente equivalente alla
-definizione:
+estensione GNU definita dalle \acr{glibc} che permette di riscrivere il
+prototipo in una forma più leggibile dell'originario:
+\begin{verbatim}
+void (*signal(int signum, void (*handler)(int)))int)
+\end{verbatim}
+questa infatti, per la poca chiarezza della sintassi del C quando si vanno a
+trattare puntatori a funzioni, è molto meno comprensibile. Da un confronto
+con il precedente prototipo si può dedurre la definizione di
+\type{sighandler\_t} che è:
\begin{verbatim}
typedef void (* sighandler_t)(int)
\end{verbatim}
-cioè un puntatore ad una funzione di tipo \type{void} con un parametro di tipo
-\type{int}\footnote{si devono usare le parentesi intorno al nome della
- funzione per via delle precedenze degli operatori del C, senza di esse si
- sarebbe definita una funzione che ritorna un puntatore a \type{void} e non
- un puntatore ad una funzione \type{void}}.
-
-Il numero di segnale passato in \param{signum} segnale può essere indicato
-direttamente con una delle costanti definite in \secref{sec:sig_standard}, il
+e cioè un puntatore ad una funzione \type{void} (cioè senza valore di ritorno)
+e che prende un argomento di tipo \type{int}\footnote{si devono usare le
+ parentesi intorno al nome della funzione per via delle precedenze degli
+ operatori del C, senza di esse si sarebbe definita una funzione che ritorna
+ un puntatore a \type{void} e non un puntatore ad una funzione \type{void}}.
+La funzione \func{signal} quindi restituisce e prende come secondo argomento
+un puntatore a una funzione di questo tipo, che è appunto il manipolatore del
+segnale.
+
+Il numero di segnale passato in \param{signum} può essere indicato
+direttamente con una delle costanti definite in \secref{sec:sig_standard}. Il
manipolatore \param{handler} invece, oltre all'indirizzo della funzione da
-chiamare all'occorrenza del segnale, può assumere anche i valori costanti
+chiamare all'occorrenza del segnale, può assumere anche i due valori costanti
\macro{SIG\_IGN} con cui si dice ignorare il segnale e \macro{SIG\_DFL} per
-installare l'azione di di default (si ricordi però che i due segnali
-\macro{SIGKILL} e \macro{SIGSTOP} non possono essere ignorati né
-intercettati).
+installare l'azione di di default\footnote{si ricordi però che i due segnali
+ \macro{SIGKILL} e \macro{SIGSTOP} non possono essere ignorati né
+ intercettati}.
\subsection{Funzioni rientranti e default dei segnali}
+\subsection{Le funzioni \func{kill} e \func{raise}}
+\label{sec:sig_kill_raise}
+
+\subsection{Le funzioni \func{alarm} e \func{pause}}
+\label{sec:sig_alarm_pause}
+
+
+\section{Il controllo dei segnali}
+\label{sec:sig_control}
-\subsection{La funzione \func{sigpending}}
+
+
+\subsection{Le funzioni \func{sigprocmask} e \func{sigpending}}
\label{sec:sig_sigpending}
+
+\subsection{La funzione \func{sigaction}}
+\label{sec:sig_sigaction}
+
+
+
+
+, affrontando inoltre le varie problematiche di programmazione che si devono
+tenere presenti quando si ha a che fare con essi.
+
+
+
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "gapil"