X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=signal.tex;fp=signal.tex;h=60a7b52ace1367da2ca560dc171e98a0971797e5;hp=0000000000000000000000000000000000000000;hb=3d44c36183fe67ed64bff95a36596ad87f620683;hpb=d05c744fc23f1ba7ec85c8268abdc8ee8426d950 diff --git a/signal.tex b/signal.tex new file mode 100644 index 0000000..60a7b52 --- /dev/null +++ b/signal.tex @@ -0,0 +1,238 @@ +\chapter{I segnali} +\label{sec: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 +loro tipo, si tratta in sostanza di un'interruzione software portata ad un +processo. + +In genere i segnali vengono usati dal kernel per riportare situazioni +eccezionali (come errori di accesso, eccezioni atritmetiche, etc.) ma possono +anche essere usati come forma elementare di comunicazione fra processi (ad +esempio vengono usati per il controllo di sessione), per notificare eventi +(come la terminazione di un processo figlio), etc. + +\section{I concetti base} +\label{sec:sig_base} + +Come il nome stesso indica i segnali sono usati per notificare ad un processo +l'occorrenza di un evento eccezionale. Gli eventi che possono generare un +segnale sono vari; un breve elenco di possibile cause è il seguente: + +\begin{itemize} +\item un errore del programma, come una divisione per zero o un tentativo di + accesso alla memoria fuori dai limiti validi. +\item la terminazione di un processo figlio. +\item la scadenza di un timer o di un allarme. +\item il tentativo di effettuare un'operazione di input/output che non può + 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'. +\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. + + +\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 +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 il segnale arriva +prima che il suo manipolatore sia installato, nel qual caso il segnale può +essere perso o causare il comportamento originale (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 oiperazioni atomiche. + +In 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 sisteme possono essere fatte ripartire automaticamente e si può +ottenere un'operazione di pausa atomica (usando la funzione POSIX +\texttt{sigsuspend}). + + +\subsubsection{Tipi di segnali} +\label{sec:sig_types} + + +In generale gli eventi che generano i segnali si possono diviedere in tre +categorie principali: errori, eventi e richieste esplicite. + +Un errore significa che un programma ha fatto qualcosa di sbagliato e non può +continuare ad essere eseguito. Non tutti gli errori causano dei segnali, in +genere la condizione di errore più comune comporta la restituzione di un +codice di errore da parte di una funzione di libreria, sono gli errori che +possono avvenire ovunque in un programma che causano l'emissione di un +segnale, come le divisioni per zero o l'uso di indirizzi di memoria non validi. + +Un evento esterno ha in genere a che fare con l'I/O o con altri processi; +esempi di segnali di questo tipo sono quelli legati all'arrivo di dati di +input, scadenze di un timer, terminazione di processi figli. + +Una richiesta esplicita significa l'uso di una chiamata di sistema (come +\texttt{kill} o \texttt{raise}) per la generazione di un segnale, cosa che +viene fatta usualmente dalla shell quando l'utente invoca la sequenza di tasti +di stop o di suspend, ma può essere pure inserita all'interno di un programma. + +Si dice poi che i segnali possono essere \textit{asincroni} o +\textit{sincroni}. Un segnale sincrono è legato ad una azione specifica di un +programma ed è inviato (a meno che non sia bloccato) durante tale azione; +molti errori generano segnali sincroni, così come la richiesta esplicita da +parte del processo tramite le chiamate al sistema. Alcuni errori come la +divisione per zero non sono completamente sincroni e possono arrivare dopo +qualche istruzione. + +I segnali asincroni sono generati da eventi fuori dal controllo del processo +che li riceve e arrivano in tempi impredicibili nel corso dell'esecuzione del +programma. Eventi esterni come la terminazione di un processo figlio generano +segnali asincroni, così come le richieste di generazione di un segnale +effettuate da altri processi. + +In generale un tipo di segnale o è sincrono o è asincrono, salvo il caso in +cui esso sia generato attraverso una richiesta esplicita tramite chiamata al +sistema, nel qual caso qualunque tipo di segnale (quello scelto nella +chiamata) può diventare sincrono o asincrono a seconda che sia generato +internamente o esternamente al processo. + +\section{La notifica dei segnali} +\label{sec:sig_notification} + +Quando un segnale viene generato il kernel prende nota del fatto; si dice così +che diventa \textit{pending} (sospeso), e rimarrà tale fino al momento in cui +verrà notificato al processo a cui deve essere inviato. + +Normalmente l'invio al processo che deve ricevere il segnale è immediato, a +meno che il segnale in questione non sia stato bloccato (\textit{blocked}) nel +qual caso l'invio non avviene ed il segnale resta sospeso indefinitamente. Una +volta però che esso venga sbloccato il segnale sarà subito notificato. + +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 +segnale. Per alcuni segnali (\texttt{SIGKILL} e \texttt{SIGSTOP}) questa azione +è fissa e non può essere cambiata, ma per tutti gli altri il programma può +specificare una scelta fra le tre seguenti: + +\begin{itemize} +\item ignorare il segnale +\item utilizzare il manipolatore (\textit{signal handler}) specificato +\item accettare l'azione di default per quel segnale. +\end{itemize} + +Il programma può specificare queste scelte usano le due routine +\texttt{signal} e \texttt{sigaction}; se si è installato un manipalatore sarà +quest'ultimo a intercettare il segnale ed ad essere eseguito, e mentre viene +eseguito (onde evitare race conditions) il segnale viene bloccato. + +Se l'azione specificata per un certo tipo di segnale è quella di ignorarlo +questo sarà scartato immediatamente ogni volta che verrà generato, e questo +avverrà anche se in quel momento il segnale è bloccato. Per questo un segnale +ignorato non sarà mai notificato, anche se in seguito si sarà specificata una +diversa azione per lo stesso segnale. + +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 \ref{sec:sig_standard}) ma per la maggior parte essa comporta la +terminazione del processo, per alcuni che invece rappresentano eventi innoqui +l'azione standard è di non fare nulla. + +Quando un segnale termina un processo, il padre può determinare la causa della +terminazione esaminando il codice di stato riportato delle funzioni +\texttt{wait} e \texttt{waitpid} in cui è riportato anche se la causa è un +segnale e nel caso quale; questo è il modo in cui la shell determina i motivi +della terminazione di un programma e scrive un eventuale messaggio di errore. + +I segnali che rappresentano errori del programma (divisione per zero o +violazioni di accesso) hanno anche la caratteristica di scrivere un file +\textit{core dump} che registra lo stato del processo prima della terminazione +e può essere esaminato da un debugger per investigare sulla causa dell'errore. +Lo stesso avvine se i suddetti segnale vengono generati artificialmente con +una \texttt{kill}. + + + +\subsection{I segnali standard} +\label{sec:sig_standard} + +Esaminiamo ora i vari segnali disponibili e le loro caratteristiche. +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. + +Per questo ad ogni tipo di segnale viene associato un nome, che corrisponde +tramite una macro di preprocessore, al suddetto numero, e sono questi nomi, +che 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 +che i numeri dei segnali sono allocati progressivamente, essa corrisponde +anche al successivo del valore numerico assegnato al'ultimo segnale definito. + + +\subsubsection{Segnali di errore di programma} + +Questi segnali sono generati quando c'é un grave errore nel programma rilevato +dal sistema o dallo stesso hardware. In generale indicano che il programma ha +dei gravi problemi e l'esecuzione non può essere proseguita. + +Alcuni programmi usano questi segnali per riordinare le cose prima di uscire. +As esempio ripristinare i settaggi della console, o eliminare i file di lock. +In questo caso il manipolatore deve concludersi ripristinando l'azione di +default e rialzando il segnale, così che il programma possa concludersi come +se il manipolatore non ci fosse mai 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 \textit{core dump file} che viene scritto in +un file \texttt{core} nella directory corrente del processo al momento +dell'errore. + +Questi segnali sono: + +\begin{itemize} +\item \texttt{SIGFPE} Riporta un errore aritmetico fatale. Benchè il nome + derivi da \textit{floating point exception} si applica a tutti gli errori + aritmetici comprea la divisione per zero e l'overflow. + +% Per questo segnale le cose sono complicate dal fatto che possono esserci +% molte diverse eccezioni che \texttt{SIGFPE} non distingue, mentre lo +% standard IEEE per le operazioni in virgola mobile definisce vaire eccezioni +% aritmetiche e richiede che esse siano notificate. +\item \texttt{SIGFPE} Il nome deriva da \textit{illegal instruction} +\item \texttt{SIGILL} +\item \texttt{SIGSEGV} +\item \texttt{SIGBUS} +\item \texttt{SIGABRT} +\item \texttt{SIGTRAP} +\item \texttt{SIGSYS} + +\end{itemize} +