X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=signal.tex;h=f7e8bc5f34d91b6d5d6cff6885365b9452137778;hp=50e54a86e6ab60e0a75638884cf7dbc00c179304;hb=6e74264a76f38d92c33420801d6df62dae4fa64f;hpb=877e20d4d68b182eee7f8e466e2a126a00534354 diff --git a/signal.tex b/signal.tex index 50e54a8..f7e8bc5 100644 --- a/signal.tex +++ b/signal.tex @@ -1,5 +1,5 @@ \chapter{I segnali} -\label{sec:signals} +\label{cha:signals} I segnali sono il primo e più semplice meccanismo di comunicazione nei confronti dei processi. Non portano con se nessuna informazione che non sia il @@ -28,60 +28,142 @@ segnale sono vari; un breve elenco di possibile cause essere eseguita. \item una richiesta dell'utente di terminare o fermare il programma. In genere si realizza attraverso un segnale mandato dalla shell in corrispondenza - della pressione di tasti come 'ctrl-c' o 'ctrl-z'. + della pressione di tasti del terminale come 'ctrl-c' o 'ctrl-z'. \item l'esecuzione di una \texttt{kill} o di una \texttt{raise} da parte del processo stesso o di un'altro (solo nel caso della \texttt{kill}). \end{itemize} Ciascuno di questi eventi (tranne gli ultimi due che sono controllati -dall'utente) comporta da parte del kernel la generazione un particolare tipo -di segnale. +dall'utente) comporta l'intervento diretto da parte del kernel che causa la +generazione un particolare tipo di segnale. \subsection{Le modalità di funzionamento} \label{sec:sig_semantics} -Quando un processo riceve un segnale il kernel esegue una apposita routine di -gestione (il cosiddetto \textit{signal handler}) che può essere specificata -dall'utente. Negli anni il comportamento del sistema in risposta ai segnali è -stato modificato in vari modi nelle differenti implementazioni di unix. -Attualmente si possono individuare due tipologie fondamentali di comportamento -dei segnali (dette semantiche) che vengono chiamate rispettivamente -\textit{reliable} e \textit{unreliable}. - -Nella semantica \textit{unreliable} la routine di gestione del segnale -specificata dall'utente non resta installata una volta chiamata; è perciò a -carico dell'utente stesso ripetere l'installazione all'interno della routine -di gestione stessa in tutti i casi in cui si vuole che il signal handler -esterno resti attivo. - -Per questo motivo è possibile una race-condition in cui un secondo segnale -arriva prima che il manipolatore abbia eseguito la re-installazione di se -stesso, nel qual caso il segnale può essere perso o causare il comportamento -originale assegnato al segnale (in genere la terminazione del processo). -Questa è la ragione per cui detti segnali sono chiamati \textit{inaffidabili}, -in quanto la ricezione del segnale e la reinstallazione del suo manipolatore -non sono operazioni atomiche. - -Nel caso di implementazione inaffidabile le chiamate di sistema non -sono fatte ripartire automaticamente quando sono interrotte da un segnale, per -questo il programma deve controllare lo stato di uscita della chiamata al -sistema e riperterla nel caso l'errore riportato da \texttt{errno} sia -\texttt{EINTR}. - -Inoltre in questo caso non esiste una modalità semplice per ottenere una -operazione di pausa atomica (cioè mandare in sleep un processo fino all'arrivo -di un segnale), dato che ci sono casi in cui un segnale può arrivare quando il -programma non è in grado di accorgersene. - -In caso di segnali \textit{reliable} invece il signal handler resta installato -quando viene chiamato e i problemi precedenti sono evitati. Inoltre alcune -chiamate di sistema possono essere fatte ripartire automaticamente e si può -ottenere un'operazione di pausa atomica (usando la funzione POSIX -\texttt{sigsuspend}). - - -\subsubsection{Tipi di segnali} +Quando un processo riceve un segnale il kernel esegue una azione di default o +una apposita routine di gestione (il cosiddetto \textit{signal handler} o +\textsl{manipolatore}) che può essere specificata dall'utente (nel qual caso +si dice che si \textsl{intercetta} il segnale). Negli anni il comportamento +del sistema in risposta ai segnali è stato modificato in vari modi nelle +differenti implementazioni di unix. Si possono individuare due tipologie +fondamentali di comportamento dei segnali (dette semantiche) che vengono +chiamate rispettivamente \textit{reliable} e \textit{unreliable}. + +Nella semantica \textit{unreliable} (quella implementata dalle prime versioni +di unix) la routine di gestione del segnale specificata dall'utente non resta +installata una volta chiamata; è perciò a carico dell'utente stesso ripetere +l'installazione all'interno della routine di gestione stessa in tutti i casi +in cui si vuole che il signal handler esterno resti attivo. + +In questo caso è possibile una situazione in cui i segnali possono essere +perduti; si consideri il seguente segmento di codice in cui la prima +operazione del manipolatore è quella di reinstallare se stesso: +\footnotesize +\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} + int sig_handler(); /* handler function */ + ... + signal(SIGINT, sig_handler); /* establish handler */ + ... + +int sig_handler() +{ + signal(SIGINT, sig_handler); /* restablish handler */ + ... /* process signal */ +} +\end{lstlisting} +\normalsize +se un secondo segnale arriva prima che il manipolatore invocato dal primo +abbia eseguito la re-installazione di se stesso il segnale può essere perso o +causare il comportamento originale assegnato al segnale (in genere la +terminazione del processo). + +Questa è la ragione per cui l'implementazione dei segnali secondo questa +semantica viene chiamata \textit{inaffidabile}, in quanto la ricezione del +segnale e la reinstallazione del suo manipolatore non sono operazioni +atomiche. + +Un'altro problema è che in questa semantica è che non esiste un modo per +bloccare i segnali quando non si vuole che arrivino; i processi possono si +ignorare il segnale, ma non è possibile istruire il sistema a non fare nulla +in occasione di un segnale, pur mantenendo memoria del fatto che è avvenuto. + +Un caso classico, riportato da Stevens, in cui si incontra questo problema, è +quello in cui si usa il manipolatore per settare un flag che riporta al +processo l'occorrenza del segnale. Si consideri il seguente segmento di +codice il cui scopo sarebbe quello di fermare il processo fino all'occorrenza +di un opportuno segnale: +\footnotesize +\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} +int signal_flag = 0; +main () +{ + int sig_handler(); /* handler function */ + ... + signal(SIGINT, sig_handler); /* establish handler */ + ... + while(signal_flag == 0) { /* while flag is zero */ + pause(); /* go to sleep */ + } + ... +} +int sig_handler() +{ + signal(SIGINT, sig_handler); /* restablish handler */ + signal_flag = 1; /* set flag */ +} +\end{lstlisting} +\normalsize +l'idea è che quando il processo trova il flag a zero viene messo in sleep e +verrà risvegliato solo dalla ricezione di un segnale. Il manipolatore si +limita in questo caso a settare il flag a uno; all'uscita dal manipolatore la +chiamata a \func{pause} è interrotta ed il processo viene risvegliato e +riprende l'esecuzione all'istruzione successiva, ma essendo cambiato il flag +la condizione non è più soddisfatta e il programma prosegue. + +Il problema con l'implementazione inaffidabile è che niente ci garantisce che +il segnale arrivi fra la valutazione della condizione del \func{while} e la +chiamata a \func{pause}, nel qual caso, se il segnale non viene più generato, +il processo resterà in sleep permanentemente. + +% Un'altra caratteristica della implementazione inaffidabile è che le chiamate +% di sistema non sono fatte ripartire automaticamente quando sono interrotte da +% un segnale, per questo un programma deve controllare lo stato di uscita della +% chiamata al sistema e riperterla nel caso l'errore riportato da \texttt{errno} +% sia \texttt{EINTR}. + +Questo ci mostra ad esempio come con la semantica inaffidabile non esista una +modalità semplice per ottenere una operazione di pausa atomica (cioè mandare +in sleep un processo fino all'arrivo di un segnale). + +Nella semantica \textit{reliable} (quella utilizzata da Linux e da ogni Unix +moderno) invece il signal handler una volta installato resta attivo e non si +hanno tutti i problemi precedenti. In questa semantica i segnali vengono +\textsl{generati} dal kernel per un processo all'occorrenza dell'evento che +causa il segnale. In genere questo viene fatto dal kernel settando un flag +nella process table del processo. + +Si dice che il segnale viene \textsl{consegnato} al processo (dall'inglese +\textit{delivered}) quando viene eseguita l'azione per esso prevista, mentre +per tutto il tempo che passa fra la generazione del segnale e la sua consegna +esso è detto \textsl{pendente}. In genere questa procedura viene effettuata +dal kernel quando, riprendendo l'esecuzione del processo in questione, verifica +la presenza del flag del segnale nella process table. + +In questa semantica un processo ha la possibilità di bloccare la consegna dei +segnali, in questo caso se l'azione per il suddetto segnale non è quella di +ignorarlo, il segnale resta \textsl{pendente} fintanto che il processo non lo +sblocca (nel qual caso viene consegnato) o setta l'azione di default per +ignorarlo. + +Si tenga presente kernel stabilisce cosa fare con un segnale che è stato +bloccato al momento della consegna, non quando viene generato; questo consente +di cambiare l'azione per il segnale prima che esso venga consegnato, e si può +usare la funzione \func{sigpending} (vedi \secref{sec:sig_sigpending}) per +determinare quali segnali sono bloccati e quali sono pendenti. + + +\subsection{Tipi di segnali} \label{sec:sig_types} In generale gli eventi che generano i segnali si possono dividere in tre @@ -142,8 +224,9 @@ segnale. Per alcuni segnali (\texttt{SIGKILL} e \texttt{SIGSTOP}) questa azione specificare una scelta fra le tre seguenti: \begin{itemize} -\item ignorare il segnale -\item utilizzare il manipolatore (\textit{signal handler}) specificato +\item ignorare il segnale. +\item catturare il segnale, ed utilizzare il manipolatore (\textit{signal + handler}) specificato. \item accettare l'azione di default per quel segnale. \end{itemize} @@ -193,47 +276,48 @@ sono standardizzati e 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 \texttt{signal.h}. -Il numero totale di segnali presenti è dato dalla macro \texttt{NSIG}, e dato +Il numero totale di segnali presenti è dato dalla macro \macro{NSIG}, e dato che i numeri dei segnali sono allocati progressivamente, essa corrisponde anche al successivo del valore numerico assegnato all'ultimo segnale definito. In \ntab\ si è riportato l'elenco completo dei segnali definiti in Linux (estratto dalle man page), comparati con quelli definiti in vari standard. - \begin{table}[htb] + \footnotesize \centering - \begin{tabular}[c]{|l|c|c|c||c|l|} + \begin{tabular}[c]{|l|c|c|c||c|p{6cm}|} \hline - Segnale & POSIX.1 & SUSv2 & Linux &Azione & Descrizione \\ + Segnale & POSIX.1 & SUSv2 & Linux &Azione & Descrizione \\ \hline \hline - SIGHUP &$\bullet$&&$\bullet$& A & Hangup \\ - SIGINT &$\bullet$&&$\bullet$& A & Interrupt from keyboard \\ - SIGQUIT &$\bullet$&&$\bullet$& C & Quit from keyboard \\ - SIGILL &$\bullet$&&$\bullet$& C & Illegal Instruction \\ - SIGABRT &$\bullet$&&$\bullet$& C & Abort signal from abort(3) \\ - SIGFPE &$\bullet$&&$\bullet$& C & Floating point exception \\ - SIGKILL &$\bullet$&&$\bullet$& AEF & Kill signal \\ - SIGSEGV &$\bullet$&&$\bullet$& C & Invalid memory reference \\ - SIGPIPE &$\bullet$&&$\bullet$& A & Broken pipe \\ - SIGALRM &$\bullet$&&$\bullet$& A & Timer signal from alarm(2) \\ - SIGTERM &$\bullet$&&$\bullet$& A & Termination signal \\ - SIGUSR1 &$\bullet$&&$\bullet$& A & User-defined signal 1 \\ - SIGUSR2 &$\bullet$&&$\bullet$& A & User-defined signal 2 \\ - SIGCHLD &$\bullet$&&$\bullet$& B & Child stopped or terminated \\ - SIGCONT &$\bullet$&&$\bullet$& & Continue if stopped \\ - SIGSTOP &$\bullet$&&$\bullet$& DEF & Stop process \\ - SIGTSTP &$\bullet$&&$\bullet$& D & Stop typed at tty \\ - SIGTTIN &$\bullet$&&$\bullet$& D & tty input for background process \\ - SIGTTOU &$\bullet$&&$\bullet$& D & tty output for background process \\ - SIGBUS &&$\bullet$&$\bullet$& C & Bus error (bad memory access) \\ - SIGPOLL &&$\bullet$&$\bullet$& A & Pollable event (Sys V). Synonym of SIGIO\\ - SIGPROF &&$\bullet$&$\bullet$& A & Profiling timer expired \\ - SIGSYS &&$\bullet$&$\bullet$& C & Bad argument to routine (SVID) \\ - SIGTRAP &&$\bullet$&$\bullet$& C & Trace/breakpoint trap \\ - SIGURG &&$\bullet$&$\bullet$& B & Urgent condition on socket (4.2 BSD) \\ - SIGVTALRM &&$\bullet$&$\bullet$& A & Virtual alarm clock (4.2 BSD) \\ - SIGXCPU &&$\bullet$&$\bullet$& C & CPU time limit exceeded (4.2 BSD) \\ - SIGXFSZ &&$\bullet$&$\bullet$& C & File size limit exceeded (4.2 BSD) \\ + SIGHUP &$\bullet$&&$\bullet$& A & Hangup o + fine del processo di controllo \\ + SIGINT &$\bullet$&&$\bullet$& A & Interrupt da tastiera (\cmd{C-c})\\ + SIGQUIT &$\bullet$&&$\bullet$& C & Quit da tastiera (\cmd{C-y}) \\ + SIGILL &$\bullet$&&$\bullet$& C & Istruzione illegale\\ + SIGABRT &$\bullet$&&$\bullet$& C & Segnale di Abort da \func{abort} \\ + SIGFPE &$\bullet$&&$\bullet$& C & Errore aritmetico\\ + SIGKILL &$\bullet$&&$\bullet$& AEF & Segnale di terminazione forzata \\ + SIGSEGV &$\bullet$&&$\bullet$& C & Errore di accesso in memoria\\ + SIGPIPE &$\bullet$&&$\bullet$& A & Pipe spezzata\\ + SIGALRM &$\bullet$&&$\bullet$& A & Segnale del timer da \func{alarm} \\ + SIGTERM &$\bullet$&&$\bullet$& A & Segnale di terminazione \verb|C-\|\\ + SIGUSR1 &$\bullet$&&$\bullet$& A & User-defined signal 1\\ + SIGUSR2 &$\bullet$&&$\bullet$& A & User-defined signal 2\\ + SIGCHLD &$\bullet$&&$\bullet$& B & Child stopped or terminated\\ + SIGCONT &$\bullet$&&$\bullet$& & Continue if stopped\\ + SIGSTOP &$\bullet$&&$\bullet$& DEF & Stop process\\ + SIGTSTP &$\bullet$&&$\bullet$& D & Stop typed at tty \\ + SIGTTIN &$\bullet$&&$\bullet$& D & tty input for background process \\ + SIGTTOU &$\bullet$&&$\bullet$& D & tty output for background process \\ + SIGBUS &&$\bullet$&$\bullet$& C & Bus error (bad memory access) \\ + SIGPOLL &&$\bullet$&$\bullet$& A & Pollable event (Sys V). Synonym of SIGIO\\ + SIGPROF &&$\bullet$&$\bullet$& A & Profiling timer expired \\ + SIGSYS &&$\bullet$&$\bullet$& C & Bad argument to routine (SVID)\\ + SIGTRAP &&$\bullet$&$\bullet$& C & Trace/breakpoint trap \\ + SIGURG &&$\bullet$&$\bullet$& B & Urgent condition on socket (4.2 BSD)\\ + SIGVTALRM &&$\bullet$&$\bullet$& A & Virtual alarm clock (4.2 BSD) \\ + SIGXCPU &&$\bullet$&$\bullet$& C & CPU time limit exceeded (4.2 BSD) \\ + SIGXFSZ &&$\bullet$&$\bullet$& C & File size limit exceeded (4.2 BSD)\\ SIGIOT &&&$\bullet$& C & IOT trap. A synonym for SIGABRT \\ SIGEMT &&&$\bullet$& & \\ SIGSTKFLT &&&$\bullet$& A & Stack fault on coprocessor \\ @@ -249,11 +333,24 @@ In \ntab\ si \caption{Lista dei segnali in Linux} \label{tab:sig_signal_list} \end{table} -in \curtab\ si sono riportate anche le caratteristiche di ciascun segnale, -indicate con una lettera nel campo azione, la cui legenda è: +in \curtab\ si sono riportate le azioni di default di ciascun segnale +(riassunte con delle lettere, la cui legenda completa è in \ntab), quando +nessun manipolatore è installato un segnale può essere ignorato o causare la +terminazione del processo. + +In alcuni casi alla terminazione del processo è associata la creazione di un +file (posto nella directory corrente del processo e chiamato \file{core}) su +cui viene salvata un'immagine della memoria del processo (il cosiddetto +\textit{core dump}), che può essere usata da un debugger per esaminare lo +stato dello stack e delle variabili al momento della ricezione del segnale. + \begin{table}[htb] \centering - \begin{tabular}[c]{c p{6cm}} + \begin{tabular}[c]{|c|p{8cm}|} + \hline + Sigla & Significato \\ + \hline + \hline A & L'azione di default è terminare il processo. \\ B & L'azione di default è ignorare il segnale. \\ C & L'azione di default è terminare il processo e scrivere un \textit{core @@ -261,17 +358,18 @@ indicate con una lettera nel campo azione, la cui legenda D & L'azione di default è fermare il processo. \\ E & Il segnale non può essere intercettato. \\ F & Il segnale non può essere ignorato.\\ + \hline \end{tabular} \caption{Legenda delle caratteristiche dei segnali riportate in \tabref{tab:sig_signal_list}. } \label{tab:sig_action_leg} \end{table} -la descrizione dettagliata del significato dei vari segnali, raggruppati per -tipologia, è a seguire; una descrizione dettagliata del significato delle -varie azioni si trova invece in \secred{sec:sig_handlers}. + +La descrizione dettagliata del significato dei vari segnali, raggruppati per +tipologia, verrà affrontate nel seguito. -\subsubsection{Segnali di errore di programma} +\subsection{Segnali di errore di programma} \label{sec:sig_prog_error} Questi segnali sono generati quando il sistema, o in certi casi direttamente @@ -292,13 +390,13 @@ non ci fosse stato. L'azione di default per tutti questi segnali è causare la terminazione del processo che li ha causati. In genere oltre a questo il segnale provoca pure la registrazione su disco di un file di \textit{core dump} che viene scritto -in un file \texttt{core} nella directory corrente del processo al momento +in un file \file{core} nella directory corrente del processo al momento dell'errore, che il debugger può usare per ricostruire lo stato del programma al momento della terminazione. Questi segnali sono: \begin{description} -\item \texttt{SIGFPE} Riporta un errore aritmetico fatale. Benché il nome +\item \macro{SIGFPE} Riporta un errore aritmetico fatale. Benché il nome derivi da \textit{floating point exception} si applica a tutti gli errori aritmetici compresa la divisione per zero e l'overflow. @@ -307,7 +405,7 @@ Questi segnali sono: % standard IEEE per le operazioni in virgola mobile definisce vaire eccezioni % aritmetiche e richiede che esse siano notificate. -\item \texttt{SIGILL} Il nome deriva da \textit{illegal instruction}, +\item \macro{SIGILL} Il nome deriva da \textit{illegal instruction}, significa che il programma sta cercando di eseguire una istruzione privilegiata o inesistente, in generale del codice illegale. Poiché il compilatore del C genera del codice valido si ottiene questo segnale se il @@ -317,7 +415,7 @@ Questi segnali sono: una variabile locale, andando a corrompere lo stack. Lo stesso segnale viene generato in caso di overflow dello stack o di problemi nell'esecuzione di di un signal handler. -\item \texttt{SIGSEGV} Il nome deriva da \textit{segment violation}, e +\item \macro{SIGSEGV} Il nome deriva da \textit{segment violation}, e significa che il programma sta cercando di leggere o scrivere in una zona di memoria protetta al di fuori di quella che gli è stata riservata dal sistema. In genere è il meccanismo della protezione della memoria che si @@ -325,17 +423,20 @@ Questi segnali sono: È tipico ottenere questo segnale dereferenziando un puntatore nullo o non inizializzato leggendo al di la della fine di un vettore. -\item \texttt{SIGBUS} In maniera analoga a \texttt{SIGSEGV} questo è un - segnale che viene generato di solito quando si dereferenzia un puntatore non - inzializzato, la differenza con con \texttt{SIGSEGV} è che questo indica un - accesso non valido su un indirizzo esistente (tipo fuori dallo heap o dallo - stack), mentre \texttt{SIGBUS} indica l'accesso ad un indirizzo non valido, - come nel caso di un puntatore non allineato. -\item \texttt{SIGABRT} Il segnale indica che il programma stesso ha rilevato - un errore che viene riportato chiamando la funzione \texttt{abort} che - genera questo segnale. -\item \texttt{SIGTRAP} -\item \texttt{SIGSYS} Sta ad indicare che si è eseguta una istruzione che +\item \macro{SIGBUS} Il nome deriva da \textit{bus error}. Come + \macro{SIGSEGV} questo è un segnale che viene generato di solito quando si + dereferenzia un puntatore non inzializzato, la differenza è che + \macro{SIGSEGV} indica un accesso non permesso su un indirizzo esistente + (tipo fuori dallo heap o dallo stack), mentre \macro{SIGBUS} indica + l'accesso ad un indirizzo non valido, come nel caso di un puntatore non + allineato. +\item \macro{SIGABRT} Il nome deriva da \textit{abort}. Il segnale indica che + il programma stesso ha rilevato un errore che viene riportato chiamando la + funzione \func{abort} che genera questo segnale. +\item \macro{SIGTRAP} È il segnale generato da un'istruzione di breakpoint o + dall'attivazione del tracciamento per il processo. È usato dai programmi per + il debugging e se un programma normale non dovrebbe ricevere questo segnale. +\item \macro{SIGSYS} Sta ad indicare che si è eseguita una istruzione che richiede l'esecuzione di una system call, ma si è fornito un codice sbagliato per quest'ultima. \end{description} @@ -358,25 +459,70 @@ periferica). L'azione di default di questi segnali è di terminare il processo, questi segnali sono: \begin{description} -\item \texttt{SIGTERM} -\item \texttt{SIGINT} -\item \texttt{SIGQUIT} -\item \texttt{SIGKILL} -\item \texttt{SIGHUP} +\item \macro{SIGTERM} Il nome sta per \textit{terminate}. È un segnale + generico usato per causare la conclusione di un programma. Al contrario di + \macro{SIGKILL} può essere intercettato, ignorato, bloccato. In genere lo si + usa per chiedere in maniera ``educata'' ad un processo di concludersi. +\item \macro{SIGINT} Il nome sta per \textit{interrupt}. È il segnale di + interruzione per il programma. È quello che viene generato di default dal + comando \cmd{kill} o dall'invio sul terminale del carattere di controllo + INTR (interrupt, generato dalla sequenza \macro{C-c}). +\item \macro{SIGQUIT} È analogo a \macro{SIGINT} con la differenze che è + controllato da un'altro carattere di controllo, QUIT, corrispondente alla + sequenza \macro{C-\\}. A differenza del precedente l'azione di default, + oltre alla terminazione del processo, comporta anche la creazione di un core + dump. + + In genere lo si può pensare come corrispondente ad una condizione di + errore del programma rilevata dall'utente. Per questo motivo non è opportuno + fare eseguire al manipolatore di questo segnale le operazioni di pulizia + normalmente previste (tipo la cancellazione di file temporanei), dato che in + certi casi esse possono eliminare informazioni utili nell'esame dei core + dump. +\item \macro{SIGKILL} Il nome è utilizzato per terminare in maniera immediata + qualunque programma. Questo segnale non può essere né intercettato, né + ignorato, né bloccato, per cui causa comunque la terminazione del processo. + In genere esso viene generato solo per richiesta esplicita dell'utente dal + comando (o tramite la funzione) \cmd{kill}. Dato che non lo si può + intercettare è sempre meglio usarlo come ultima risorsa quando metodi meno + brutali, come \macro{SIGTERM} o \macro{C-c} non funzionano. + + Se un processo non risponde a nessun altro segnale \macro{SIGKILL} ne causa + sempre la terminazione (in effetti il fallimento della terminazione di un + processo da parte di \macro{SIGKILL} costituirebbe un funzionamento del + kernel). Talvolta è il sistema stesso che può generare questo segnale quando + per condizioni particolari il processo non può più essere eseguito neanche + per eseguire il manipolatore. +\item \macro{SIGHUP} Il nome sta per \textit{hang-up}. Segnala che il + terminale dell'utente si è disconnesso (ad esempio perché si è interrotta la + rete). Viene usato anche per riportare la terminazione del processo di + controllo di un terminale a tutti i processi della sessione, in modo che + essi possano disconnettersi dal relativo terminale. + + Viene inoltre usato in genere per segnalare ai demoni (che non hanno un + terminale di controllo) la necessità di reinizializzarsi e rileggere il/i + file di configurazione. \end{description} \subsection{I segnali di allarme} \label{sec:sig_alarm} -Questi segnali sono generati dalla scadenza di un temporizzatore. Il loro -comportamento di default è quello di causare la terminazione del programma, ma -nessun default ha una utlità avrebbe una utilità particolare, in quanto l'uso -di questi segnali presuppone quasi sempre la necessità di un -manipolatore. Questi segnali sono: +Questi segnali sono generati dalla scadenza di un timer. Il loro comportamento +di default è quello di causare la terminazione del programma, ma con questi +segnali la scelta di default è irrilevante, in quanto il loro uso presuppone +sempre la necessità di un manipolatore. Questi segnali sono: \begin{description} -\item \texttt{SIGALRM} -\item \texttt{SIGVTALRM} -\item \texttt{SIGPROF} +\item \macro{SIGALRM} Il nome sta per \textit{alarm}. Segnale la scadenza di + un timer misurato sul tempo reale o sull'orologio di sistema. È normalmente + usato dalla funzione \func{alarm}. +\item \macro{SIGVTALRM} Il nome sta per \textit{virtual alarm}. È analogo al + precedente ma segnala la scadenza di un timer sul tempo di CPU usato dal + processo. +\item \macro{SIGPROF} Il nome sta per \textit{profiling}. Indica la scadenza + di un timer che misura sia il tempo di CPU speso direttamente dal processo + che quello che il sistema ha speso per conto di quest'ultimo. In genere + viene usato dai tool che servono a fare il profilo d'uso della CPU da parte + del processo. \end{description} @@ -389,24 +535,55 @@ generare questi segnali. L'azione di default è di essere ignorati. Questi segnali sono: \begin{description} -\item \texttt{SIGIO} -\item \texttt{SIGURG} -\item \texttt{SIGPOLL} +\item \macro{SIGIO} Questo segnale viene inviato quando un file descriptor è + pronto per eseguire dell'input/output. In molti sistemi solo i socket e i + terminali possono generare questo segnale, in Linux questo può essere usato + anche per i file, posto che la \func{fcntl} abbia avuto successo. +\item \macro{SIGURG} Questo segnale è inviato quando arrivano dei dati + urgenti o \textit{out of band} su di un socket; per maggiori dettagli al + proposito si veda \secref{sec:xxx_urgent_data}. +\item \macro{SIGPOLL} Questo segnale è equivalente a \macro{SIGIO}, è + definito solo per compatibilità con i sistemi System V. \end{description} \subsection{I segnali per il controllo di sessione} \label{sec:sig_job_control} -Questi sono i segnali usati dal controllo di sessione, il loro uso è specifico -per questo argomento e verrà trattato quando lo affronteremo. -Questi segnali sono: -\begin{description} -\item \texttt{SIGCHLD} -\item \texttt{SIGCONT} -\item \texttt{SIGSTOP} -\item \texttt{SIGTSTP} -\item \texttt{SIGTTIN} -\item \texttt{SIGTTOU} +Questi sono i segnali usati dal controllo delle sessioni e dei processi, il +loro uso è specifico e viene trattato in maniera specifica nelle sezioni in +cui si trattano gli argomenti relativi. Questi segnali sono: +\begin{description} +\item \macro{SIGCHLD} Questo è il segnale mandato al processo padre quando un + figlio termina o viene fermato. L'azione di default è di ignorare il + segnale, la sua gestione è trattata in \secref{sec:proc_wait}. +\item \macro{SIGCLD} Per Linux questo è solo un segnale identico al + precedente, il nome è obsoleto e andrebbe evitato. +\item \macro{SIGCONT} Il nome sta per \textit{continue}. Il segnale viene + usato per fare ripartire un programma precedentemente fermato da + \macro{SIGSTOP}. Questo segnale ha un comportamento speciale, e fa sempre + ripartire il processo prima della sua consegna. Il comportamento di default + è di fare solo questo; il segnale non può essere bloccato. Si può anche + installare un manipolatore, ma il segnale provoca comunque il riavvio del + processo. + + La maggior pare dei programmi non hanno necessità di intercettare il + segnale, in quanto esso è completamente trasparente rispetto all'esecuzione + che riparte senza che il programma noti niente. Si possono installare dei + manipolatori per far si che un programma produca una qualche azione speciale + se viene fermato e riavviato, come per esempio riscrivere un prompt, o + inviare un avviso. +\item \macro{SIGSTOP} Il segnale ferma un processo (lo porta in uno stato di + sleep); il segnale non può essere né intercettato, né ignorato, né bloccato. +\item \macro{SIGTSTP} Il nome sta per \textit{interactive stop}. Il segnale + ferma il processo interattivamente, ed è generato dal carattere SUSP + (prodotto dalla combinazione \macro{C-z}), ed al contrario di + \macro{SIGSTOP} può essere intercettato e ignorato. In genere un programma + installa un manipolatore per questo segnale quando vuole lasciare il sistema + o il terminale in uno stato definito prima di fermarsi; se per esempio un + programma ha disabilitato l'eco sul terminale può installare un manipolatore + per riabilitarlo prima di fermarsi. +\item \macro{SIGTTIN} +\item \macro{SIGTTOU} \end{description} \subsection{I segnali di operazioni errate} @@ -420,10 +597,16 @@ resto del sistema. L'azione di default di questi segnali è di terminare il processo, questi segnali sono: \begin{description} -\item \texttt{SIGPIPE} -\item \texttt{SIGLOST} -\item \texttt{SIGXCPU} -\item \texttt{SIGXFSZ} +\item \macro{SIGPIPE} Sta per \textit{Broken pipe}. Se si usano delle pipe o + delle FIFO è necessario che, prima che un processo inizi a scrivere su di + essa, un'altro abbia aperto la pipe in lettura (si veda + \secref{sec:ipc_pipes}). Se il processo in lettura non è partito o è + terminato inavvertitamente alla scrittura sulla pipe il kernel genera questo + segnale. Se il segnale è bloccato, intercettato o ignorato la chiamata che + lo ha causato fallisce restituendo l'errore \macro{EPIPE} +\item \macro{SIGLOST} Sta per \textit{Resource lost}. +\item \macro{SIGXCPU} Sta per \textit{CPU time limit exceeded}. +\item \macro{SIGXFSZ} Sta per \textit{File size limit exceeded}. \end{description} @@ -433,12 +616,45 @@ segnali sono: Raccogliamo qui infine usa serie di segnali che hanno scopi differenti non classificabili in maniera omogenea. Questi segnali sono: \begin{description} -\item \texttt{SIGUSR1} e \texttt{SIGUSR2} -\item \texttt{SIGWINCH} -\item \texttt{SIGINFO} +\item \macro{SIGUSR1} e \macro{SIGUSR2} Sono due segnali a disposizione + dell'utente che li può usare per quello che vuole. Possono essere utili per + implementare una comunicazione elementare fra processi diversi, o per + eseguire a richiesta una operazione utilizzando un manipolatore. L'azione di + default è terminare il processo. +\item \macro{SIGWINCH} Il nome sta per \textit{window (size) change} ed è + generato da molti sistemi (GNU/Linux compreso) quando le dimensioni (in + righe e colonne) di un terminale vengono cambiate. Viene usato da alcuni + programmi testuali per riformattare l'uscita su schermo quando si cambia + dimensione a quest'ultimo. L'azione di default è di essere ignorato. +\item \macro{SIGINFO} Il segnale indica una richiesta di informazioni. È + usato con il controllo di sessione, causa la stampa di informazioni da parte + del processo leader del gruppo associato al terminale di controllo, gli + altri processi lo ignorano. \end{description} +\subsection{Le funzioni \func{strsignal} e \func{psignal}} +\label{sec:sig_strsignal} + +Per la descrizione dei segnali il sistema mette a disposizione due funzioni +che stampano un messaggio di descrizione dato il numero. In genere si usano +quando si vuole notificare all'utente il segnale avvenuto (nel caso di +terminazione di un processo figlio o di un manipolatore che gestisce più +segnali); la prima funzione è una estensione GNU ed è analoga alla funzione +\func{strerr} per gli errori: +\begin{prototype}{string.h}{char * strsignal (int signum)} + Ritorna il puntatore ad una stringa allocata staticamente che contiene la + descrizione del segnale \var{signum}. +\end{prototype} + +Dato che la stringa è allocata staticamente non se ne deve modificare il +contenuto, che resta valido solo fino alla successiva chiamata di +\func{strsignal}; nel caso si debba mantenere traccia del messaggio sarà +necessario copiarlo. + +La seconda funzione deriva da BSD ed è analoga alla funzione \func{perror} +descritta in \secref{sec:intro_strerror}. + \section{La gestione dei segnali} \label{sec:sig_handlers} @@ -450,14 +666,56 @@ 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. -In questa sezione vedremo allora come si gestiscono i segnali, partendo dalla -descrizione di cosa fanno le azioni di default citate in precedenza, per poi -esaminare le funzioni usate per personalizzare la gestione dei segnali, -analizzando tutte le problematiche relative alla gestione di eventi asincroni -di questo tipo. - - - -\subsection{Le azioni di default} -\label{sec:sig_default_acttion} +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. + + +\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 +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}. + + 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 \func{void (*signal(int signum, void + (*handler)(int)))int)}, e che è sostanzialmente equivalente alla +definizione: +\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 +manipolatore \param{handler} invece, oltre all'indirizzo della funzione da +chiamare all'occorrenza del segnale, può assumere anche i 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). + + +\subsection{Funzioni rientranti e default dei segnali} +\label{sec:sig_reentrant}