From: Simone Piccardi Date: Tue, 26 Jun 2001 22:35:34 +0000 (+0000) Subject: Scritta un'altra po' di roba sui segnali. X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=commitdiff_plain;h=4bb6358695e10cb2c505af11d2b96626ae7d885c;p=gapil.git Scritta un'altra po' di roba sui segnali. --- diff --git a/macro.tex b/macro.tex index c2ef967..e20120d 100644 --- a/macro.tex +++ b/macro.tex @@ -115,10 +115,12 @@ tab.~\thechapter.\theusercount} % Wrapper for shell command, functions, filenames, links, % variables, macros, and everything can be useul, % -\newcommand{\cmd}[1]{\texttt{#1}} -\newcommand{\func}[1]{\texttt{#1}} -\newcommand{\macro}[1]{\texttt{#1}} -\newcommand{\var}[1]{\texttt{#1}} -\newcommand{\file}[1]{\texttt{#1}} -\newcommand{\link}[1]{\texttt{#1}} +\newcommand{\cmd}[1]{\texttt{#1}} % shell command +\newcommand{\func}[1]{\texttt{#1}} % library function (or system call) +\newcommand{\macro}[1]{\texttt{#1}} % macro constant +\newcommand{\var}[1]{\texttt{#1}} % variable +\newcommand{\file}[1]{\texttt{#1}} % file name +\newcommand{\link}[1]{\texttt{#1}} % html link +\newcommand{\type}[1]{\texttt{#1}} % variable type +\newcommand{\param}[1]{\texttt{#1}} % function parameter diff --git a/signal.tex b/signal.tex index 4fb155d..c192362 100644 --- a/signal.tex +++ b/signal.tex @@ -41,13 +41,14 @@ 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. Si -possono individuare due tipologie fondamentali di comportamento dei segnali -(dette semantiche) che vengono chiamate rispettivamente \textit{reliable} e -\textit{unreliable}. +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 @@ -55,10 +56,26 @@ installata una volta chiamata; 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. In questo caso il segnale può essere perso o causare il comportamento -originale assegnato al segnale (in genere la terminazione del processo). +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: +\begin{lstlisting}{showlines=false} + + int sig_handler(); /* handler function */ + ... + signal(SIGINT, sig_handler); /* establish handler */ + ... + +int sig_handler() +{ + signal(SIGINT, sig_handler); /* restablish handler */ + ... /* process signal */ +} +\end{lstlisting} +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 @@ -66,15 +83,16 @@ 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 +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, se si considera il seguente segmento di -codice: -\begin{lstlisting} +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: +\begin{lstlisting}{} int signal_flag = 0; main () { @@ -82,8 +100,9 @@ main () ... signal(SIGINT, sig_handler); /* establish handler */ ... - while(signal_flag == 0) /* while flag is zero */ + while(signal_flag == 0) { /* while flag is zero */ pause(); /* go to sleep */ + } ... } int sig_handler() @@ -92,13 +111,17 @@ int sig_handler() signal_flag = 1; /* set flag */ } \end{lstlisting} - - -% non supporta l'ultima delle due ma vale la pena parlarne -% dato che è stata la prima ad essere stata implementata (e se ne trovano -% conseguenze in alcuni programmi e funzioni di libreria) ed illustra bene -% alcune delle caratteristiche dei segnali. - +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 @@ -106,10 +129,9 @@ int sig_handler() % 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. +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 @@ -125,16 +147,20 @@ esso 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 può bloccare i segnali +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. -% Torneremo su -% questo più avanti in \secref{sec:sig_linux_sematic}. -% 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} @@ -256,39 +282,40 @@ In \ntab\ si (estratto dalle man page), comparati con quelli definiti in vari standard. \begin{table}[htb] \centering - \begin{tabular}[c]{|l|c|c|c||c|l|} + \begin{tabular}[c]{|l|c|c|c||c|p{8cm}|} \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) \\ + SIGHUP &$\bullet$&&$\bullet$& A & Hangup sul terminale o + morte 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) \\ + 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 \\ @@ -527,13 +554,48 @@ 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 semantica dei segnali in Linux} -\label{sec:sig_linux_semantic} - - - \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 puntatarore 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 i valori costanti +\macro{SIG\_IGN} per ignorare il segnale e \macro{SIG\_DFL} per installare +l'azione di di default (si ricordi però che \macro{SIGKILL} e \macro{SIGSTOP} +non possono essere ignorati né intercettati). +