X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=signal.tex;h=7a680d40d0e77c7fed49f7185c8e054a1ea4dd6f;hp=2e30498aecd9e5eec86f9d9075989376f095f797;hb=d47f15496fa85c8ec22edcde608f2665ec5b95ae;hpb=fd86592a845b5f76ad43ba2374ca0b798ffca595 diff --git a/signal.tex b/signal.tex index 2e30498..7a680d4 100644 --- a/signal.tex +++ b/signal.tex @@ -1,4 +1,4 @@ -%% signal.tex +a%% signal.tex %% %% Copyright (C) 2000-2002 Simone Piccardi. Permission is granted to %% copy, distribute and/or modify this document under the terms of the GNU Free @@ -105,21 +105,7 @@ verr \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}{} -int sig_handler(); /* handler function */ -int main() -{ - ... - signal(SIGINT, sig_handler); /* establish handler */ - ... -} - -int sig_handler() -{ - signal(SIGINT, sig_handler); /* restablish handler */ - ... /* process signal */ -} - \end{lstlisting} + \includecodesample{listati/unreliable_sig.c} \end{minipage} \normalsize \caption{Esempio di codice di un gestore di segnale per la semantica @@ -518,7 +504,8 @@ segnali sono: \item[\const{SIGTERM}] Il nome sta per \textit{terminate}. È un segnale generico usato per causare la conclusione di un programma. Al contrario di \const{SIGKILL} può essere intercettato, ignorato, bloccato. In genere lo si - usa per chiedere in maniera ``educata'' ad un processo di concludersi. + usa per chiedere in maniera ``\textsl{educata}'' ad un processo di + concludersi. \item[\const{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 @@ -690,12 +677,14 @@ segnali sono: Raccogliamo qui infine usa serie di segnali che hanno scopi differenti non classificabili in maniera omogenea. Questi segnali sono: \begin{basedescript}{\desclabelwidth{2.0cm}} -\item[\const{SIGUSR1}] Vedi \const{SIGUSR2}. -\item[\const{SIGUSR2}] Insieme a \const{SIGUSR1} è un segnale 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 gestore. L'azione - predefinita è di terminare il processo. +\item[\const{SIGUSR1}] Insieme a \const{SIGUSR2} è un segnale a disposizione + dell'utente che lo può usare per quello che vuole. Viene generato solo + attraverso l'invocazione della funzione \func{kill}. Entrambi i segnali + possono essere utili per implementare una comunicazione elementare fra + processi diversi, o per eseguire a richiesta una operazione utilizzando un + gestore. L'azione predefinita è di terminare il processo. +\item[\const{SIGUSR2}] È il secondo segnale a dispozione degli utenti. Vedi + quanto appena detto per \const{SIGUSR1}. \item[\const{SIGWINCH}] Il nome sta per \textit{window (size) change} e viene generato in molti sistemi (GNU/Linux compreso) quando le dimensioni (in righe e colonne) di un terminale vengono cambiate. Viene usato da alcuni @@ -739,9 +728,7 @@ Una modalit \func{strsignal} e \func{psignal} è quello di fare usare la variabile \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} +\includecodesnip{listati/siglist.c} 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 @@ -804,7 +791,7 @@ gestore non comporta nessun inconveniente. In alcuni casi però alcune system call (che per questo motivo vengono chiamate \textsl{lente}) possono bloccarsi indefinitamente. In questo caso non si può -attendere la conclusione della sistem call, perché questo renderebbe +attendere la conclusione della system call, perché questo renderebbe impossibile una risposta pronta al segnale, per cui il gestore viene eseguito prima che la system call sia ritornata. Un elenco dei casi in cui si presenta questa situazione è il seguente: @@ -878,16 +865,12 @@ In questa definizione si una estensione GNU, definita dalle \acr{glibc}, che permette di riscrivere il prototipo di \func{signal} nella forma appena vista, molto più leggibile di quanto non sia la versione originaria, che di norma è definita come: -\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} - void (*signal(int signum, void (*handler)(int)))int) -\end{lstlisting} +\includecodesnip{listati/signal.c} 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{lstlisting}[labelstep=0,frame=,indent=1cm]{} - typedef void (* sighandler_t)(int) -\end{lstlisting} +\includecodesnip{listati/sighandler_t.c} e cioè un puntatore ad una funzione \ctyp{void} (cioè senza valore di ritorno) e che prende un argomento di tipo \ctyp{int}.\footnote{si devono usare le parentesi intorno al nome della funzione per via delle precedenze degli @@ -917,22 +900,28 @@ mai notificati. L'uso di \func{signal} è soggetto a problemi di compatibilità, dato che essa si comporta in maniera diversa per sistemi derivati da BSD o da System V. In questi ultimi infatti la funzione è conforme al comportamento originale dei -primi Unix in cui il gestore viene disinstallato alla sua chiamata, -secondo la semantica inaffidabile; Linux seguiva questa convenzione fino alle -\acr{libc5}. Al contrario BSD segue la semantica affidabile, non -disinstallando il gestore e bloccando il segnale durante l'esecuzione -dello stesso. Con l'utilizzo delle \acr{glibc} dalla versione 2 anche Linux è -passato a questo comportamento; quello della versione originale della -funzione, il cui uso è deprecato per i motivi visti in -\secref{sec:sig_semantics}, può essere ottenuto chiamando \func{sysv\_signal}. -In generale, per evitare questi problemi, tutti i nuovi programmi dovrebbero -usare \func{sigaction}. +primi Unix in cui il gestore viene disinstallato alla sua chiamata, secondo la +semantica inaffidabile; anche Linux seguiva questa convenzione con le vecchie +librerie del C come le \acr{libc4} e le \acr{libc5}.\footnote{nelle + \acr{libc5} esiste però la possibilità di includere \file{bsd/signal.h} al + posto di \file{signal.h}, nel qual caso la funzione \func{signal} viene + ridefinita per seguire la semantica affidabile usata da BSD.} + +Al contrario BSD segue la semantica affidabile, non disinstallando il gestore +e bloccando il segnale durante l'esecuzione dello stesso. Con l'utilizzo delle +\acr{glibc} dalla versione 2 anche Linux è passato a questo comportamento. Il +comportamento della versione originale della funzione, il cui uso è deprecato +per i motivi visti in \secref{sec:sig_semantics}, può essere ottenuto +chiamando \func{sysv\_signal}, uno volta che si sia definita la macro +\macro{\_XOPEN\_SOURCE}. In generale, per evitare questi problemi, l'uso di +\func{signal} (ed ogni eventuale ridefinizine della stessa) è da evitare; +tutti i nuovi programmi dovrebbero usare \func{sigaction}. È da tenere presente che, seguendo lo standard POSIX, il comportamento di un processo che ignora i segnali \const{SIGFPE}, \const{SIGILL}, o -\const{SIGSEGV} (qualora non originino da una \func{kill} o una \func{raise}) -è indefinito. Un gestore che ritorna da questi segnali può dare luogo ad -un ciclo infinito. +\const{SIGSEGV} (qualora questi non originino da una chiamata ad una +\func{kill} o ad una \func{raise}) è indefinito. Un gestore che ritorna da +questi segnali può dare luogo ad un ciclo infinito. \subsection{Le funzioni \func{kill} e \func{raise}} @@ -940,7 +929,7 @@ un ciclo infinito. Come accennato in \secref{sec:sig_types}, un segnale può essere generato direttamente da un processo attraverso una opportuna system call. Le funzioni -che si usano di solito per invare un segnale generico sono due, \func{raise} e +che si usano di solito per inviare un segnale generico sono due, \func{raise} e \func{kill}. La prima funzione è \funcd{raise}, che è definita dallo standard ANSI C, e @@ -997,6 +986,25 @@ esso sia realmente quello a cui si intendeva mandare il segnale. Il valore dell'argomento \param{pid} specifica il processo (o i processi) di destinazione a cui il segnale deve essere inviato e può assumere i valori riportati in \tabref{tab:sig_kill_values}. + +Si noti pertanto che la funzione \code{raise(sig)} può essere definita in +termini di \func{kill}, ed è sostanzialmente equivalente ad una +\code{kill(getpid(), sig)}. Siccome \func{raise}, che è definita nello +standard ISO C, non esiste in alcune vecchie versioni di Unix, in generale +l'uso di \func{kill} finisce per essere più portabile. + +Una seconda funzione che può essere definita in termini di \func{kill} è +\funcd{killpg}, che è sostanzialmente equivalente a +\code{kill(-pidgrp, signal)}; il suo prototipo è: +\begin{prototype}{signal.h}{int killpg(pid\_t pidgrp, int signal)} + + Invia il segnale \param{signal} al process group \param{pidgrp}. + \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di + errore, gli errori sono gli stessi di \func{kill}.} +\end{prototype} +\noindent e che permette di inviare un segnale a tutto un \textit{process + group} (vedi \secref{sec:sess_proc_group}). + \begin{table}[htb] \footnotesize \centering @@ -1018,24 +1026,6 @@ riportati in \tabref{tab:sig_kill_values}. \label{tab:sig_kill_values} \end{table} -Si noti pertanto che la funzione \code{raise(sig)} può essere definita in -termini di \func{kill}, ed è sostanzialmente equivalente ad una -\code{kill(getpid(), sig)}. Siccome \func{raise}, che è definita nello -standard ISO C, non esiste in alcune vecchie versioni di Unix, in generale -l'uso di \func{kill} finisce per essere più portabile. - -Una seconda funzione che può essere definita in termini di \func{kill} è -\funcd{killpg}, che è sostanzialmente equivalente a -\code{kill(-pidgrp, signal)}; il suo prototipo è: -\begin{prototype}{signal.h}{int killpg(pid\_t pidgrp, int signal)} - - Invia il segnale \param{signal} al process group \param{pidgrp}. - \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di - errore, gli errori sono gli stessi di \func{kill}.} -\end{prototype} -e che permette di inviare un segnale a tutto un \textit{process group} (vedi -\secref{sec:sess_proc_group}). - Solo l'amministratore può inviare un segnale ad un processo qualunque, in tutti gli altri casi l'user-ID reale o l'user-ID effettivo del processo chiamante devono corrispondere all'user-ID reale o all'user-ID salvato della @@ -1163,13 +1153,7 @@ questo modo il ciclo verr \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} -struct itimerval -{ - struct timeval it_interval; /* next value */ - struct timeval it_value; /* current value */ -}; - \end{lstlisting} + \includestruct{listati/itimerval.h} \end{minipage} \normalsize \caption{La struttura \structd{itimerval}, che definisce i valori dei timer @@ -1187,22 +1171,7 @@ in termini di \func{setitimer}, come evidenziato dal manuale delle \acr{glibc} \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} -unsigned int alarm(unsigned int seconds) -{ - struct itimerval old, new; - new.it_interval.tv_usec = 0; - new.it_interval.tv_sec = 0; - new.it_value.tv_usec = 0; - new.it_value.tv_sec = (long int) seconds; - if (setitimer(ITIMER_REAL, &new, &old) < 0) { - return 0; - } - else { - return old.it_value.tv_sec; - } -} - \end{lstlisting} + \includestruct{listati/alarm_def.c} \end{minipage} \normalsize \caption{Definizione di \func{alarm} in termini di \func{setitimer}.} @@ -1429,29 +1398,10 @@ di zombie\index{zombie}. % gestore per che è previsto ritornare, \begin{figure}[!htb] - \footnotesize - \begin{lstlisting}{} -void HandSigCHLD(int sig) -{ - int errno_save; - int status; - pid_t pid; - /* save errno current value */ - errno_save = errno; - /* loop until no */ - do { - errno = 0; - pid = waitpid(WAIT_ANY, &status, WNOHANG); - if (pid > 0) { - debug("child %d terminated with status %x\n", pid, status); - } - } while ((pid > 0) && (errno == EINTR)); - /* restore errno value */ - errno = errno_save; - /* return */ - return; -} - \end{lstlisting} + \footnotesize \centering + \begin{minipage}[c]{15cm} + \includecodesample{listati/hand_sigchild.c} + \end{minipage} \normalsize \caption{Codice di una funzione generica di gestione per il segnale \texttt{SIGCHLD}.} @@ -1471,10 +1421,10 @@ Il compito principale del gestore terminazione del processo, cosa che viene eseguita nel ciclo in (\texttt{\small 15-21}). Il ciclo è necessario a causa di una caratteristica fondamentale della gestione dei segnali: abbiamo già accennato come fra la -generazione di un segnale e l'esecuzione del gestore possa passare un -certo lasso di tempo e niente ci assicura che il gestore venga eseguito -prima della generazione di ulteriori segnali dello stesso tipo. In questo caso -normalmente i segnali segnali successivi vengono ``fusi'' col primo ed al +generazione di un segnale e l'esecuzione del gestore possa passare un certo +lasso di tempo e niente ci assicura che il gestore venga eseguito prima della +generazione di ulteriori segnali dello stesso tipo. In questo caso normalmente +i segnali segnali successivi vengono ``\textsl{fusi}'' col primo ed al processo ne viene recapitato soltanto uno. Questo può essere un caso comune proprio con \const{SIGCHLD}, qualora capiti @@ -1534,34 +1484,10 @@ rimanente (\texttt{\small 22-23}) che potr l'interruzione di \func{pause} venisse causata da un altro segnale. \begin{figure}[!htb] - \footnotesize - \begin{lstlisting}{} -void alarm_hand(int sig) { - /* check if the signal is the right one */ - if (sig != SIGALRM) { /* if not exit with error */ - printf("Something wrong, handler for SIGALRM\n"); - exit(1); - } else { /* do nothing, just interrupt pause */ - return; - } -} -unsigned int sleep(unsigned int seconds) -{ - sighandler_t prev_handler; - /* install and check new handler */ - if ((prev_handler = signal(SIGALRM, alarm_hand)) == SIG_ERR) { - printf("Cannot set handler for alarm\n"); - exit(-1); - } - /* set alarm and go to sleep */ - alarm(seconds); - pause(); - /* restore previous signal handler */ - signal(SIGALRM, prev_handler); - /* return remaining time */ - return alarm(0); -} - \end{lstlisting} + \footnotesize \centering + \begin{minipage}[c]{15cm} + \includecodesample{listati/sleep_danger.c} + \end{minipage} \normalsize \caption{Una implementazione pericolosa di \func{sleep}.} \label{fig:sig_sleep_wrong} @@ -1584,36 +1510,10 @@ uscita di quest'ultima, si pu codice del tipo di quello riportato in \figref{fig:sig_sleep_incomplete}. \begin{figure}[!htb] - \footnotesize - \begin{lstlisting}{} -static jmp_buff alarm_return; -unsigned int sleep(unsigned int seconds) -{ - signandler_t prev_handler; - if ((prev_handler = signal(SIGALRM, alarm_hand)) == SIG_ERR) { - printf("Cannot set handler for alarm\n"); - exit(1); - } - if (setjmp(alarm_return) == 0) { /* if not returning from handler */ - alarm(second); /* call alarm */ - pause(); /* then wait */ - } - /* restore previous signal handler */ - signal(SIGALRM, prev_handler); - /* remove alarm, return remaining time */ - return alarm(0); -} -void alarm_hand(int sig) -{ - /* check if the signal is the right one */ - if (sig != SIGALRM) { /* if not exit with error */ - printf("Something wrong, handler for SIGALRM\n"); - exit(1); - } else { /* return in main after the call to pause */ - longjump(alarm_return, 1); - } -} - \end{lstlisting} + \footnotesize \centering + \begin{minipage}[c]{15cm} + \includecodesample{listati/sleep_defect.c} + \end{minipage} \normalsize \caption{Una implementazione ancora malfunzionante di \func{sleep}.} \label{fig:sig_sleep_incomplete} @@ -1641,28 +1541,10 @@ programma (con un codice del tipo di quello riportato in \figref{fig:sig_event_wrong}). \begin{figure}[!htb] - \footnotesize - \begin{lstlisting}{} -sig_atomic_t flag; -int main() -{ - flag = 0; - ... - if (flag) { /* test if signal occurred */ - flag = 0; /* reset flag */ - do_response(); /* do things */ - } else { - do_other(); /* do other things */ - } - ... -} -void alarm_hand(int sig) -{ - /* set the flag - flag = 1; - return; -} - \end{lstlisting} + \footnotesize\centering + \begin{minipage}[c]{15cm} + \includecodesample{listati/sig_alarm.c} + \end{minipage} \normalsize \caption{Un esempio non funzionante del codice per il controllo di un evento generato da un segnale.} @@ -1692,13 +1574,11 @@ reagire alla ricezione di un segnale. \label{sec:sig_sigset} Come evidenziato nel paragrafo precedente, le funzioni di gestione dei segnali -dei primi Unix, nate con la semantica inaffidabile, hanno dei limiti non +originarie, nate con la semantica inaffidabile, hanno dei limiti non superabili; in particolare non è prevista nessuna funzione che permetta di gestire gestire il blocco dei segnali o di verificare lo stato dei segnali -pendenti. - -Per questo motivo lo standard POSIX.1, insieme alla nuova semantica dei -segnali ha introdotto una interfaccia di gestione completamente nuova, che +pendenti. Per questo motivo lo standard POSIX.1, insieme alla nuova semantica +dei segnali ha introdotto una interfaccia di gestione completamente nuova, che permette di ottenete un controllo molto più dettagliato. In particolare lo standard ha introdotto un nuovo tipo di dato \type{sigset\_t}, che permette di rappresentare un \textsl{insieme di segnali} (un \textit{signal set}, come @@ -1810,16 +1690,7 @@ pi \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} -struct sigaction -{ - void (*sa_handler)(int); - void (*sa_sigaction)(int, siginfo_t *, void *); - sigset_t sa_mask; - int sa_flags; - void (*sa_restorer)(void); -} - \end{lstlisting} + \includestruct{listati/sigaction.h} \end{minipage} \normalsize \caption{La struttura \structd{sigaction}.} @@ -1888,37 +1759,20 @@ permette\footnote{La possibilit 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{sigcontext}, che adesso è - deprecato.} di utilizzare due forme diverse di gestore, da -specificare, a seconda dell'uso o meno del flag \const{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 -gestore in grado di ricevere informazioni più dettagliate dal sistema, -attraverso la struttura \struct{siginfo\_t}, riportata in -\figref{fig:sig_siginfo_t}. + deprecato.} di utilizzare due forme diverse di gestore, da specificare, a +seconda dell'uso o meno del flag \const{SA\_SIGINFO}, rispettivamente +attraverso i campi \var{sa\_sigaction} o \var{sa\_handler},\footnote{i due + tipi devono essere usati in maniera alternativa, in certe implementazioni + questi campi vengono addirittura definiti come \ctyp{union}.} Quest'ultima +è quella classica usata anche con \func{signal}, mentre la prima permette di +usare un gestore più complesso, in grado di ricevere informazioni più +dettagliate dal sistema, attraverso la struttura \struct{siginfo\_t}, +riportata in \figref{fig:sig_siginfo_t}. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} -siginfo_t { - int si_signo; /* Signal number */ - int si_errno; /* An errno value */ - int si_code; /* Signal code */ - pid_t si_pid; /* Sending process ID */ - uid_t si_uid; /* Real user ID of sending process */ - int si_status; /* Exit value or signal */ - clock_t si_utime; /* User time consumed */ - clock_t si_stime; /* System time consumed */ - sigval_t si_value; /* Signal value */ - int si_int; /* POSIX.1b signal */ - void * si_ptr; /* POSIX.1b signal */ - void * si_addr; /* Memory location which caused fault */ - int si_band; /* Band event */ - int si_fd; /* File descriptor */ -} - \end{lstlisting} + \includestruct{listati/siginfo_t.h} \end{minipage} \normalsize \caption{La struttura \structd{siginfo\_t}.} @@ -1942,7 +1796,7 @@ specifica: ad esempio i vari segnali di errore (\const{SIGFPE}, maggiori dettagli riguardo l'errore (come il tipo di errore aritmetico, di istruzione illecita o di violazione di memoria) mentre alcuni segnali di controllo (\const{SIGCHLD}, \const{SIGTRAP} e \const{SIGPOLL}) forniscono -altre informazioni speecifiche. In tutti i casi il valore del campo è +altre informazioni specifiche. 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 pagina di manuale di di \func{sigaction}. @@ -1975,25 +1829,10 @@ meno che non si sia vincolati all'aderenza stretta allo standard ISO C, sempre il caso di evitare l'uso di \func{signal} a favore di \func{sigaction}. \begin{figure}[!htb] - \footnotesize - \begin{lstlisting}{} -typedef void SigFunc(int); -inline SigFunc * Signal(int signo, SigFunc *func) -{ - struct sigaction new_handl, old_handl; - new_handl.sa_handler = func; - /* clear signal mask: no signal blocked during execution of func */ - if (sigemptyset(&new_handl.sa_mask)!=0){ /* initialize signal set */ - return SIG_ERR; - } - new_handl.sa_flags=0; /* init to 0 all flags */ - /* change action for signo signal */ - if (sigaction(signo, &new_handl, &old_handl)){ - return SIG_ERR; - } - return (old_handl.sa_handler); -} - \end{lstlisting} + \footnotesize \centering + \begin{minipage}[c]{15.6cm} + \includecodesample{listati/Signal.c} + \end{minipage} \normalsize \caption{Una funzione equivalente a \func{signal} definita attraverso \func{sigaction}.} @@ -2139,39 +1978,10 @@ ottenere un'implementazione, riportata in \figref{fig:sig_sleep_ok} che non presenta neanche questa necessità. \begin{figure}[!htb] - \footnotesize - \begin{lstlisting}{} -void alarm_hand(int); -unsigned int sleep(unsigned int seconds) -{ - struct sigaction new_action, old_action; - sigset_t old_mask, stop_mask, sleep_mask; - /* set the signal handler */ - sigemptyset(&new_action.sa_mask); /* no signal blocked */ - new_action.sa_handler = alarm_hand; /* set handler */ - new_action.sa_flags = 0; /* no flags */ - sigaction(SIGALRM, &new_action, &old_action); /* install action */ - /* block SIGALRM to avoid race conditions */ - sigemptyset(&stop_mask); /* init mask to empty */ - sigaddset(&stop_mask, SIGALRM); /* add SIGALRM */ - sigprocmask(SIG_BLOCK, &stop_mask, &old_mask); /* add SIGALRM to blocked */ - /* send the alarm */ - alarm(seconds); - /* going to sleep enabling SIGALRM */ - sleep_mask = old_mask; /* take mask */ - sigdelset(&sleep_mask, SIGALRM); /* remove SIGALRM */ - sigsuspend(&sleep_mask); /* go to sleep */ - /* restore previous settings */ - sigprocmask(SIG_SETMASK, &old_mask, NULL); /* reset signal mask */ - sigaction(SIGALRM, &old_action, NULL); /* reset signal action */ - /* return remaining time */ - return alarm(0); -} -void alarm_hand(int sig) -{ - return; /* just return to interrupt sigsuspend */ -} - \end{lstlisting} + \footnotesize \centering + \begin{minipage}[c]{15.6cm} + \includecodesample{listati/sleep.c} + \end{minipage} \normalsize \caption{Una implementazione completa di \func{sleep}.} \label{fig:sig_sleep_ok} @@ -2199,13 +2009,13 @@ dato che \const{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\index{deadlock} dovuto all'arrivo del segnale prima dell'esecuzione @@ -2244,7 +2054,7 @@ sistema un altro stack (invece di quello relativo al processo, vedi \secref{sec:proc_mem_layout}) solo durante l'esecuzione di un gestore. L'uso di uno stack alternativo è del tutto trasparente ai gestori, 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 @@ -2253,18 +2063,20 @@ gestori, occorre per specificando il flag \const{SA\_ONSTACK} (vedi \tabref{tab:sig_sa_flag}) per dire al sistema di usare lo stack alternativo durante l'esecuzione del gestore. -\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, \const{SIGSTKSZ} e \const{MINSIGSTKSZ}, che possono essere utilizzate per allocare una quantità di spazio opportuna, in modo da evitare overflow. La prima delle due è la dimensione canonica per uno stack di segnali e di norma è -sufficiente per tutti gli usi normali. La seconda è lo spazio che occorre al -sistema per essere in grado di lanciare il gestore e la dimensione di uno -stack alternativo deve essere sempre maggiore di questo valore. Quando si -conosce esattamente quanto è lo spazio necessario al gestore gli si può -aggiungere questo valore per allocare uno stack di dimensione sufficiente. +sufficiente per tutti gli usi normali. + +La seconda è lo spazio che occorre al sistema per essere in grado di lanciare +il gestore e la dimensione di uno stack alternativo deve essere sempre +maggiore di questo valore. Quando si conosce esattamente quanto è lo spazio +necessario al gestore gli si può aggiungere questo valore per allocare uno +stack di dimensione sufficiente. Come accennato per poter essere usato lo stack per i segnali deve essere indicato al sistema attraverso la funzione \funcd{sigaltstack}; il suo @@ -2297,13 +2109,7 @@ successivo ripristino). \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} -typedef struct { - void *ss_sp; /* Base address of stack */ - int ss_flags; /* Flags */ - size_t ss_size; /* Number of bytes in stack */ -} stack_t; - \end{lstlisting} + \includestruct{listati/stack_t.h} \end{minipage} \normalsize \caption{La struttura \structd{stack\_t}.} @@ -2346,9 +2152,11 @@ modificarlo con \func{sigprocmask}. Resta quindi il problema di cosa succede alla maschera dei segnali quando si esce da un gestore usando questa funzione. Il comportamento dipende -dall'implementazione; in particolare BSD ripristina la maschera dei segnali -precedente l'invocazione, come per un normale ritorno, mentre System V no. Lo -standard POSIX.1 non specifica questo comportamento per \func{setjmp} e +dall'implementazione; in particolare BSD prevede che sia ripristinata la +maschera dei segnali precedente l'invocazione, come per un normale ritorno, +mentre System V no. + +Lo standard POSIX.1 non specifica questo comportamento per \func{setjmp} e \func{longjmp}, ed il comportamento delle \acr{glibc} dipende da quale delle caratteristiche si sono abilitate con le macro viste in \secref{sec:intro_gcc_glibc_std}. @@ -2395,30 +2203,28 @@ presenta dei significativi miglioramenti,\footnote{questa estensione 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} +\begin{basedescript}{\desclabelwidth{1cm}\desclabelstyle{\nextlinelabel}} \item[I segnali non sono accumulati] - se più segnali vengono generati prima dell'esecuzione di un gestore 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] - +\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} +\end{basedescript} 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: +vengono chiamati \textsl{segnali real-time}, in particolare le funzionalità +aggiunte sono: -\begin{itemize*} +\begin{enumerate} \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 gestore; si assicura così che il processo riceva un @@ -2426,20 +2232,20 @@ vengono chiamati \textsl{segnali real-time}, in particolare: \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 - gestore, attraverso l'uso di un campo apposito nella struttura - \struct{siginfo\_t} accessibile tramite gestori di tipo +\item è stata introdotta la possibilità di restituire dei dati al gestore, + attraverso l'uso di un apposito campo \var{si\_value} nella struttura + \struct{siginfo\_t}, accessibile tramite gestori di tipo \var{sa\_sigaction}. -\end{itemize*} +\end{enumerate} -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 \const{SIGRTMIN} -e \const{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. +Queste nuove funzionalità (eccetto l'ultima, che, come vedremo, è 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 \const{SIGRTMIN} e \const{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 @@ -2449,37 +2255,52 @@ tutti la stessa priorit 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 gestore, oltre ai -campi \var{si\_pid} e \var{si\_uid} di \struct{siginfo\_t} una struttura -\struct{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. +specifico, a meno di non utilizzarli in meccanismi di notifica come quelli per +l'I/O asincrono (vedi \secref{sec:file_asyncronous_io}) o per le code di +messaggi POSIX (vedi \secref{sec:ipc_posix_mq}); pertanto devono essere +inviati esplicitamente. + +Inoltre, per poter usufruire della capacità di restituire dei dati, i relativi +gestori devono essere installati con \func{sigaction}, specificando per +\var{sa\_flags} la modalità \const{SA\_SIGINFO} che permette di utilizzare la +forma estesa \var{sa\_sigaction} (vedi \secref{sec:sig_sigaction}). In questo +modo tutti i segnali real-time possono restituire al gestore una serie di +informazioni aggiuntive attraverso l'argomento \struct{siginfo\_t}, la cui +definizione abbiamo già visto in \figref{fig:sig_siginfo_t}, nella trattazione +dei gestori in forma estesa. + +In particolare i campi utilizzati dai segnali real-time sono \var{si\_pid} e +\var{si\_uid} in cui vengono memorizzati rispettivamente il \acr{pid} e +l'user-ID effettivo del processo che ha inviato il segnale, mentre per la +restituzione dei dati viene usato il campo \var{si\_value}. + +Questo è una \ctyp{union} di tipo \struct{sigval\_t} (la sua definizione è in +\figref{fig:sig_sigval}) in cui può essere memorizzato o un valore numerico, +se usata nella forma \var{sival\_int}, o un indirizzo, se usata nella forma +\var{sival\_ptr}. L'unione viene usata dai segnali real-time e da vari +meccanismi di notifica\footnote{un campo di tipo \struct{sigval\_t} è presente + anche nella struttura \struct{sigevent} che viene usata dai meccanismi di + notifica come quelli per l'I/O asincrono (vedi + \secref{sec:file_asyncronous_io}) o le code di messaggi POSIX (vedi + \secref{sec:ipc_posix_mq}).} per restituire dati al gestore del segnale; in +alcune definizioni essa viene identificata anche come \code{union sigval}. \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} + \includestruct{listati/sigval_t.h} \end{minipage} \normalsize - \caption{La struttura \structd{sigval}, usata dai segnali real time per - restituire dati al gestore.} + \caption{La unione \structd{sigval\_t}.} \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 \struct{sigval}; per questo motivo lo standard ha previsto una -nuova funzione, \funcd{sigqueue}, il cui prototipo è: +A causa delle loro caratteristiche, la funzione \func{kill} non è adatta ad +inviare segnali real-time, poichè non è in grado di fornire alcun valore +per \struct{sigval\_t}; per questo motivo lo standard ha previsto una nuova +funzione, \funcd{sigqueue}, il cui prototipo è: \begin{prototype}{signal.h} - {int sigqueue(pid\_t pid, int signo, const union sigval value)} + {int sigqueue(pid\_t pid, int signo, const sigval\_t value)} Invia il segnale \param{signo} al processo \param{pid}, restituendo al gestore il valore \param{value}. @@ -2487,7 +2308,7 @@ nuova funzione, \funcd{sigqueue}, il cui prototipo \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di errore, nel qual caso \var{errno} assumerà uno dei valori: \begin{errlist} - \item[\errcode{EAGAIN}] La coda è esarita, ci sono già \const{SIGQUEUE\_MAX} + \item[\errcode{EAGAIN}] La coda è esaurita, ci sono già \const{SIGQUEUE\_MAX} segnali in attesa si consegna. \item[\errcode{EPERM}] Non si hanno privilegi appropriati per inviare il segnale al processo specificato. @@ -2505,16 +2326,17 @@ di errore senza inviare nessun segnale. Se il segnale è bloccato la funzione ritorna immediatamente, se si è installato un gestore con \const{SA\_SIGINFO} e ci sono risorse disponibili, -vale a dire che c'è posto nella coda\footnote{la profondità della coda è - indicata dalla costante \const{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, \const{\_POSIX\_SIGQUEUE\_MAX}, è pari a 32.}, esso viene inserito -e diventa pendente; una volta consegnato riporterà nel campo \var{si\_code} di -\struct{siginfo} il valore \const{SI\_QUEUE} e il campo \var{si\_value} -riceverà quanto inviato con \param{value}. Se invece si è installato un -gestore nella forma classica il segnale sarà generato, ma tutte le -caratteristiche tipiche dei segnali real-time (priorità e coda) saranno perse. +(vale a dire che c'è posto\footnote{la profondità della coda è indicata dalla + costante \const{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, + \const{\_POSIX\_SIGQUEUE\_MAX}, è pari a 32.} nella coda dei segnali +real-time) esso viene inserito e diventa pendente; una volta consegnato +riporterà nel campo \var{si\_code} di \struct{siginfo\_t} il valore +\const{SI\_QUEUE} e il campo \var{si\_value} riceverà quanto inviato con +\param{value}. Se invece si è installato un gestore nella forma classica il +segnale sarà generato, ma tutte le caratteristiche tipiche dei segnali +real-time (priorità e coda) saranno perse. Lo standard POSIX.1b definisce inoltre delle nuove funzioni che permettono di gestire l'attesa di segnali specifici su una coda, esse servono in particolar @@ -2576,7 +2398,7 @@ relativi prototipi sono: \func{sigwait}, ai quali si aggiunge, per \func{sigtimedwait}: \begin{errlist} \item[\errcode{EAGAIN}] Si è superato il timeout senza che un segnale atteso - fosse emmesso. + fosse emesso. \end{errlist} } \end{functions} @@ -2591,11 +2413,10 @@ associato viene riportato in \var{si\_value}, che altrimenti La seconda è identica alla prima ma in più permette di specificare un timeout, scaduto il quale ritornerà con un errore. Se si specifica un puntatore nullo il comportamento sarà identico a \func{sigwaitinfo}, se si specifica un tempo -di timeout nullo, e non ci sono sengali pendenti la funzione ritornerà +di timeout nullo, e non ci sono segnali pendenti la funzione ritornerà immediatamente; in questo modo si può eliminare un segnale dalla coda senza dover essere bloccati qualora esso non sia presente. - L'uso di queste funzioni è principalmente associato alla gestione dei segnali com i thread. In genere esse vengono chiamate dal thread incaricato della gestione, che al ritorno della funzione esegue il codice che usualmente @@ -2606,7 +2427,9 @@ che, per evitare che venga eseguita l'azione predefinita, i segnali gestiti in questa maniera devono essere mascherati per tutti i thread, compreso quello dedicato alla gestione, che potrebbe riceverlo fra due chiamate successive. + %%% Local Variables: %%% mode: latex %%% TeX-master: "gapil" +%%% TeX-master: "gapil" %%% End: