X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=signal.tex;h=98e476eb52ef57e99ef2390f23b4b12bfd916482;hp=bbfea4f851f101561bc6adecfae0aaddd5b0f368;hb=fc4a31f12206bfd45aedae964058696121e7decf;hpb=e861c0f37f9eb16aed0f8bfbdb37afa04df1f685 diff --git a/signal.tex b/signal.tex index bbfea4f..98e476e 100644 --- a/signal.tex +++ b/signal.tex @@ -84,22 +84,8 @@ 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 +s +e un secondo segnale arriva prima che il manipolatore invocato dal primo abbia eseguito la reinstallazione di se stesso il segnale può essere perso o causare il comportamento originale assegnato al segnale (in genere la terminazione del processo). @@ -322,7 +308,6 @@ In \tabref{tab:sig_signal_list} si definiti in Linux (estratto dalle man page), comparati con quelli definiti in vari standard. - \begin{table}[htb] \footnotesize \centering @@ -966,43 +951,28 @@ manipolatore potr \func{raise}. Se invece si vuole inviare un segnale ad un altro processo occorre utilizzare -la funzione \func{kill}; il suo prototipo è: +la funzione \func{kill}; il cui prototipo è: \begin{functions} \headdecl{sys/types.h} \headdecl{signal.h} \funcdecl{int kill(pid\_t pid, int sig)} Invia il segnale \param{sig} al processo specificato con \param{pid}. - - \bodydesc{La funzione restituisce zero in caso di successo e -1 per un - errore, nel qual caso \var{errno} assumerà i valori: - \begin{errlist} - \item[\macro{EINVAL}] Si è specificato un numero di segnale invalido. - \item[\macro{EPERM}] Il processo non ha il permesso di inviare il segnale - alla destinazione specificata. - \item[\macro{ESRCH}] Il \acr{pid} o il process group indicati non - esistono. Gli zombie (vedi \ref{sec:proc_termination}) sono considerati come - processi esistenti. - \end{errlist}} \end{functions} -La funzione \code{raise(sig)} è 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. - -Lo standard POSIX poi prevede che il valore 0 sia usato per specificare il -segnale nullo. Se le funzioni vengono chiamate con questo valore non viene -inviato nessun segnale, ma viene eseguito il controllo degli errori, in tal -caso si otterrà un errore \macro{EPERM} se non si hanno i permessi necessari -ed un errore \macro{ESRCH} se il processo specificato non esiste. Si tenga -conto però che il sistema ricicla i \acr{pid} (come accennato in -\secref{sec:proc_pid}) per cui l'esistenza di un processo non significa che +Lo standard POSIX prevede che il valore 0 per \param{sig} sia usato per +specificare il segnale nullo. Se le funzioni vengono chiamate con questo +valore non viene inviato nessun segnale, ma viene eseguito il controllo degli +errori, in tal caso si otterrà un errore \macro{EPERM} se non si hanno i +permessi necessari ed un errore \macro{ESRCH} se il processo specificato non +esiste. Si tenga conto però che il sistema ricicla i \acr{pid} (come accennato +in \secref{sec:proc_pid}) per cui l'esistenza di un processo non significa che 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}. \begin{table}[htb] + \footnotesize \centering \begin{tabular}[c]{|r|l|} \hline @@ -1023,6 +993,12 @@ riportati in \tabref{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. + Solo l'amministratore può inviare un segnale ad un processo qualunque, in tutti gli altri casi il \textit{real user id} o l'\textit{effective user id} del processo chiamante devono corrispondere al \textit{real user id} o al @@ -1045,9 +1021,10 @@ segnale al processo che ha effettuato la chiamata. \label{sec:sig_alarm_abort} Un caso particolare di segnali generati a richiesta è quello che riguarda i -segnali di temporizzazione e \macro{SIGABORT}, per i quali sono previste -funzioni specifiche che ne effettuino l'invio. La prima di queste è -\func{alarm} il cui prototipo è: +vari segnali di temporizzazione e \macro{SIGABORT}, per ciascuno di questi +segnali sono previste funzioni specifiche che ne effettuino l'invio. La più +comune delle funzioni usate per la temporizzazione è \func{alarm} il cui +prototipo è: \begin{prototype}{unistd.h}{unsigned int alarm(unsigned int seconds)} Predispone l'invio di \macro{SIGALARM} dopo \param{seconds} secondi. @@ -1055,22 +1032,25 @@ funzioni specifiche che ne effettuino l'invio. La prima di queste precedente allarme, o zero se non c'erano allarmi pendenti.} \end{prototype} -La funzione provvede un meccanismo che consente ad un processo di predisporre +La funzione fornisce un meccanismo che consente ad un processo di predisporre un'interruzione nel futuro, (ad esempio per effettuare una qualche operazione -dopo un certo periodo di tempo), programmando l'emissione di un segnale (in -genere \macro{SIGALARM}) dopo il numero di secondi specificato da +dopo un certo periodo di tempo), programmando l'emissione di un segnale (nel +caso in questione \macro{SIGALARM}) dopo il numero di secondi specificato da \param{seconds}. Se si specifica per \param{seconds} un valore nullo non verrà inviato nessun segnale; siccome alla chiamata viene cancellato ogni precedente allarme, -questo può essere usato per cancellare una programmazione precedente. La -funzione inoltre ritorna il numero di secondi rimanenti all'invio dell'allarme -precedentemente programmato, in modo che sia eventualmente possibile -effettuare delle scelte in caso di necessità di più interruzioni. +questo può essere usato per cancellare una programmazione precedente. + +La funzione inoltre ritorna il numero di secondi rimanenti all'invio +dell'allarme precedentemente programmato, in modo che sia possibile +controllare se non si cancella un precedente allarme ed eventualmente +predisporre le opportune misure per gestire il caso di necessità di più +interruzioni. In \secref{sec:sys_unix_time} abbiamo visto che ad ogni processo sono -associati tre tempi diversi: \textit{clock time}, \textit{user time} e -\textit{system time}. Per poterli calcolare il kernel mantiene per ciascun +associati tre tempi diversi: il \textit{clock time}, l'\textit{user time} ed +il \textit{system time}. Per poterli calcolare il kernel mantiene per ciascun processo tre diversi timer: \begin{itemize} \item un \textit{real-time timer} che calcola il tempo reale trascorso (che @@ -1111,6 +1091,7 @@ Il valore di \param{which} permette di specificare quale dei tre timer illustrati in precedenza usare; i possibili valori sono riportati in \tabref{tab:sig_setitimer_values}. \begin{table}[htb] + \footnotesize \centering \begin{tabular}[c]{|l|l|} \hline @@ -1130,7 +1111,7 @@ illustrati in precedenza usare; i possibili valori sono riportati in Il valore della struttura specificata \param{value} viene usato per settare il timer, se il puntatore \param{ovalue} non è nullo il precedente valore viene salvato qui. I valori dei timer devono essere indicati attraverso una -struttura \var{itimerval}, definita in \ref{fig:file_stat_struct}. +struttura \var{itimerval}, definita in \figref{fig:file_stat_struct}. La struttura è composta da due membri, il primo, \var{it\_interval} definisce il periodo del timer; il secondo, \var{it\_value} il tempo mancante alla @@ -1138,18 +1119,22 @@ scadenza. Entrambi esprimono i tempi tramite una struttura \var{timeval} che permette una precisione fino al microsecondo. Ciascun timer decrementa il valore di \var{it\_value} fino a zero, poi invia -il segnale e resetta \var{it\_value} al valore di \var{it\_interval}, -ripetendo il ciclo; se \var{it\_interval} è nullo il timer si ferma. +il segnale e resetta \var{it\_value} al valore di \var{it\_interval}, in +questo modo il ciclo verrà ripetuto; se invece il valore di \var{it\_interval} +è nullo il timer si ferma. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} -struct itimerval { + \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} +struct itimerval +{ struct timeval it_interval; /* next value */ struct timeval it_value; /* current value */ }; -struct timeval { + +struct timeval +{ long tv_sec; /* seconds */ long tv_usec; /* microseconds */ }; @@ -1165,12 +1150,13 @@ L'uso di \func{setitimer} consente dunque un controllo completo di tutte le caratteristiche dei timer, ed in effetti la stessa \func{alarm}, benché definita direttamente nello standard POSIX.1, può a sua volta essere espressa in termini di \func{setitimer}, come evidenziato dal manuale delle \acr{glibc} -\cite{glibc} che ne riporta la definizione in \figref{fig:sig_alarm_def}. +\cite{glibc} che ne riporta la definizione mostrata in +\figref{fig:sig_alarm_def}. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} + \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} unsigned int alarm(unsigned int seconds) { struct itimerval old, new; @@ -1178,10 +1164,12 @@ unsigned int alarm(unsigned int seconds) 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) + if (setitimer(ITIMER_REAL, &new, &old) < 0) { return 0; - else + } + else { return old.it_value.tv_sec; + } } \end{lstlisting} \end{minipage} @@ -1191,13 +1179,23 @@ unsigned int alarm(unsigned int seconds) \end{figure} Si deve comunque tenere presente che la precisione di queste funzioni è -limitata da quella del timer di sistema (in genere 10~ms). Il sistema assicura -comunque che il segnale non sarà mai generato prima della scadenza programmata -(l'arrotondamento cioè è sempre effettuato per eccesso). Una seconda causa di -potenziali ritardi è che il segnale viene generato alla scadenza del timer, -ma poi deve essere consegnato; se il processo è attivo (questo è sempre vero -per \macro{ITIMER\_VIRT}) la consegna è immediata, altrimenti può esserci un -ulteriore ritardo che può variare a seconda del carico del sistema. +limitata da quella della frequenza del timer di sistema (che nel caso dei PC +significa circa 10~ms). Il sistema assicura comunque che il segnale non sarà +mai generato prima della scadenza programmata (l'arrotondamento cioè è sempre +effettuato per eccesso). + +Una seconda causa di potenziali ritardi è che il segnale viene generato alla +scadenza del timer, ma poi deve essere consegnato al processo; se quest'ultimo +è attivo (questo è sempre vero per \macro{ITIMER\_VIRT}) la consegna è +immediata, altrimenti può esserci un ulteriore ritardo che può variare a +seconda del carico del sistema. + +Questo ha una conseguenza che può indurre ad errori molto subdoli, si tenga +conto poi che in caso di sistema molto carico, si può avere il caso patologico +in cui un timer scade prima che il segnale di una precedente scadenza sia +stato consegnato; in questo caso, per il comportamento dei segnali descritto +in \secref{sec:sig_sigchld}, un solo segnale sarà consegnato. + Dato che sia \func{alarm} che \func{setitimer} non consentono di leggere il valore corrente di un timer senza modificarlo, è possibile usare la funzione @@ -1333,22 +1331,6 @@ delle strutture di tipo \var{timespec}, la cui definizione \figref{fig:sig_timespec_def}, che permettono di specificare un tempo con una precisione (teorica) fino al nanosecondo. -\begin{figure}[!htb] - \footnotesize \centering - \begin{minipage}[c]{15cm} - \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} -struct timespec -{ - time_t tv_sec; /* seconds */ - long tv_nsec; /* nanoseconds */ -}; - \end{lstlisting} - \end{minipage} - \normalsize - \caption{La struttura \var{timespec} di \func{nanosleep}.} - \label{fig:sig_timespec_def} -\end{figure} - La funzione risolve anche il problema di proseguire l'attesa dopo l'interruzione dovuta ad un segnale; infatti in tal caso in \param{rem} viene restituito il tempo rimanente rispetto a quanto richiesto inizialmente, e @@ -1364,6 +1346,21 @@ sia scarico ed il processa venga immediatamente rimesso in esecuzione); per questo motivo il valore restituito in \param{rem} è sempre arrotondato al multiplo successivo di 1/\macro{HZ}. +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{} +struct timespec { + time_t tv_sec; /* seconds */ + long tv_nsec; /* nanoseconds */ +}; + \end{lstlisting} + \end{minipage} + \normalsize + \caption{La struttura \var{timespec} di \func{nanosleep}.} + \label{fig:sig_timespec_def} +\end{figure} + In realtà è possibile ottenere anche pause più precise del centesimo di secondo usando politiche di scheduling real time come \macro{SCHED\_FIFO} o \macro{SCHED\_RR}; in tal caso infatti il meccanismo di scheduling ordinario @@ -1443,42 +1440,41 @@ void Hand_CHLD(int sig) \end{figure} Il codice del manipolatore è di lettura immediata; come buona norma di -programmazione (si ricordi quanto accennato \secref{sec:sys_errno}) si comincia -(\texttt{\small 13}) con il salvare lo stato corrente di \var{errno}, in modo -da poterla ripristinare prima del ritorno del manipolatore (\texttt{\small - 23}). In questo modo si preserva il valore della variabile visto dal corso -di esecuzione principale del processo, che sarebbe altrimenti sarebbe -sovrascritto dal valore restituito nella successiva chiamata di \func{wait}. +programmazione (si ricordi quanto accennato \secref{sec:sys_errno}) si +comincia (\texttt{\small 12-13}) con il salvare lo stato corrente di +\var{errno}, in modo da poterlo ripristinare prima del ritorno del +manipolatore (\texttt{\small 22-23}). In questo modo si preserva il valore +della variabile visto dal corso di esecuzione principale del processo, che +sarebbe altrimenti sarebbe sovrascritto dal valore restituito nella successiva +chiamata di \func{wait}. Il compito principale del manipolatore è quello di ricevere lo stato di terminazione del processo, cosa che viene eseguita nel ciclo in -(\texttt{\small 15--21}). Il ciclo è necessario a causa di una caratteristica +(\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 manipolatore possa passare un -certo lasso di tempo; dato che questo lasso di tempo può dipendere da parecchi -fattori esterni, niente ci assicura che il manipolatore venga eseguito prima -della generazione di altri segnali dello stesso tipo. In questo caso -normalmente i segnali vengono ``fusi'' insieme ed al processo ne viene -recapitato soltanto uno. +certo lasso di tempo e niente ci assicura che il manipolatore 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 +processo ne viene recapitato soltanto uno. -Questo può essere un caso comune proprio con \macro{SIGCHLD}, quando molti -processi figli terminano in rapida successione. Esso comunque si presenta -tutte le volte che un segnale viene bloccato: per quanti siano i segnali -emessi durante il periodo di blocco, una volta che esso viene rimosso ne sarà -recapitato uno solo. +Questo può essere un caso comune proprio con \macro{SIGCHLD}, qualora capiti +che molti processi figli terminino in rapida successione. Esso inoltre si +presenta tutte le volte che un segnale viene bloccato: per quanti siano i +segnali emessi durante il periodo di blocco, una volta che quest'ultimo sarà +rimosso sarà recapitato un solo segnale. -Nel caso della terminazione dei processi figli, se si chiamasse \func{waitpid} -una sola volta, essa leggerebbe un solo stato di teminazione, anche se i -processi terminati sono più di uno, con relativa possibilità di avere zombie -che non vengono eliminati. +Allora nel caso della terminazione dei processi figli, se si chiamasse +\func{waitpid} una sola volta, essa leggerebbe lo stato di teminazione per un +solo processo, anche se i processi terminati sono più di uno, e gli altri +resterebbero in stato di zombie per un tempo indefinito. -Per questo si esegue un ciclo (\texttt{\small 15--21}) in cui ripete la -lettura fintanto che essa non restituisce un valore nullo (si veda -\secref{sec:proc_wait} per la sintassi della funzione) segno che non resta -nessun processo di cui si debba ancora ricevere lo stato di terminazione. Si -noti come la funzione viene invocata con il parametro \macro{WNOHANG} che -permette di evitare che essa si blocchi quando tutti gli stati di terminazione -sono stati ricevuti. +Per questo occorre ripetere la chiamata di \func{waitpid} fino a che essa non +ritorni un valore nullo, segno che non resta nessun processo di cui si debba +ancora ricevere lo stato di terminazione (si veda \secref{sec:proc_wait} per +la sintassi della funzione). Si noti anche come la funzione venga invocata con +il parametro \macro{WNOHANG} che permette di evitare il suo blocco quando +tutti gli stati di terminazione sono stati ricevuti. @@ -1503,15 +1499,20 @@ casistica ordinaria. Come accennato in \secref{sec:sig_pause_sleep} è possibile implementare \func{sleep} a partire da dall'uso di \func{pause} e \func{alarm}. A prima vista questo può sembrare di implementazione immediata; ad esempio una -semplice versione di \func{sleep} potrebbe essere la seguente quella -illustrata in \ref{fig:sig_sleep_wrong}. +semplice versione di \func{sleep} potrebbe essere quella illustrata in +\figref{fig:sig_sleep_wrong}. + -In questo caso si salva il precedente manipolatore in (\texttt{\small 15--21}) -per poi chiamare in sequenza \func{alarm} per specificare l'attesa e -\func{pause} per fermare il programma. Al ritorno di pause, causato dal -ritorno del manipolatore (\texttt{\small 15--21}) si ripristina il -manipolatore (\texttt{\small 15--21}) restituendo l'eventuale tempo rimanente -(\texttt{\small 15--21}). +Dato che è nostra intenzione utilizzare \macro{SIGALARM} il primo passo della +nostra implementazione di sarà quello di installare il relativo manipolatore +salvando il precedente (\texttt{\small 4-7}). Si effettuerà poi una chiamata +ad \func{alarm} per specificare il tempo d'attesa per l'invio del segnale a +cui segue la chiamata a \func{pause} per fermare il programma (\texttt{\small + 8-9}) fino alla sua ricezione. Al ritorno di \func{pause}, causato dal +ritorno del manipolatore (\texttt{\small 15-23}), si ripristina il +manipolatore originario (\texttt{\small 10-11}) restituendo l'eventuale tempo +rimanente (\texttt{\small 12-13}) che potrà essere diverso da zero qualora +l'interruzione di \func{pause} venisse causata da un altro segnale. \begin{figure}[!htb] \footnotesize \centering @@ -1543,22 +1544,25 @@ void alarm_hand(int sig) { \end{lstlisting} \end{minipage} \normalsize - \caption{Una implementazione pericolosamente sbagliata di \func{sleep}.} + \caption{Una implementazione pericolosa di \func{sleep}.} \label{fig:sig_sleep_wrong} \end{figure} -Ma questo codice, a parte il non gestire il caso in cui si è avuta una -precedente chiamata a \func{alarm}, presenta una pericolosa race condition. -Infatti se il processo viene interrotto fra la chiamata di \func{alarm} e -\func{pause} può capitare (ad esempio se il sistema è molto carico) che -quest'ultima possa essere eseguita dopo l'arrivo di \macro{SIGALRM}. In questo -caso ci si troverebbe di fronte ad un deadlock, in cui \func{pause} non -verrebbe mai più interrotta (se non in caso di un altro segnale). +Questo codice però, a parte il non gestire il caso in cui si è avuta una +precedente chiamata a \func{alarm} (che si è tralasciato per brevità), +presenta una pericolosa race condition. Infatti se il processo viene +interrotto fra la chiamata di \func{alarm} e \func{pause} può capitare (ad +esempio se il sistema è molto carico) che il tempo di attesa scada prima +dell'esecuzione quest'ultima, cosicchè essa sarebbe eseguita dopo l'arrivo di +\macro{SIGALRM}. In questo caso ci si troverebbe di fronte ad un deadlock, in +quanto \func{pause} non verrebbe mai più interrotta (se non in caso di un +altro segnale). Questo problema può essere risolto (ed è la modalità con cui veniva fatto in SVr2) usando la funzione \func{longjump} (vedi \secref{sec:proc_longjmp}) per -uscire dal manipolatore, in modo da sfruttare lo stato di uscita di -quest'ultima per evitare la chiamata a \func{pause}, con un codice del tipo: +uscire dal manipolatore; in questo modo, con una condizione sullo stato di +uscita di quest'ultima, si può evitare la chiamata a \func{pause}, usando un +codice del tipo di quello riportato in \figref{fig:sig_sleep_incomplete}. \begin{figure}[!htb] \footnotesize \centering @@ -1597,27 +1601,96 @@ void alarm_hand(int sig) { \label{fig:sig_sleep_incomplete} \end{figure} -In questo modo all'uscita dal manipolatore si eviterà comunque la chiamata di -\func{pause}, dato che in questo caso il valore di uscita di \func{setjmp} è -uno ed il condizionale in (\texttt{\small 15--21}) viene evitato. - +In questo caso il manipolatore (\texttt{\small 18-26}) non ritorna come in +\figref{fig:sig_sleep_wrong}, ma usa \func{longjmp} (\texttt{\small 24}) per +rientrare nel corpo principale del programma; dato che in questo caso il +valore di uscita di \func{setjmp} è 1 grazie alla condizione in +(\texttt{\small 9-12}) si evita comunque che \func{pause} sia chiamata a +vuoto. Ma anche questa implementazione comporta dei problemi; in questo caso infatti -non viene gestita correttamente l'interazione con altri segnali; se infatti il -segnale di allarme interrompe un altro manipolatore, in questo caso +non viene gestita correttamente l'interazione con gli altri segnali; se +infatti il segnale di allarme interrompe un altro manipolatore, in questo caso l'esecuzione non riprenderà nel manipolatore in questione, ma nel ciclo -principale, interrompendone inopportunamente l'esecuzione. +principale, interrompendone inopportunamente l'esecuzione. È per questo +motivo che occorrono funzioni più sofisticate della semplice \func{signal} che +permettano di gestire i segnali in maniera più completa. -\subsection{Le funzioni \func{sigprocmask} e \func{sigpending}} -\label{sec:sig_sigpending} +\subsection{La funzione \func{sigaction}} +\label{sec:sig_sigaction} + +Come evidenziato nel paragrafo precedente, le funzioni di gestione dei segnali +dei primi Unix, hanno dei limiti non superabili; per questo motivo lo standard +POSIX ha introdotto una interfaccia di gestione completamente nuova, che +permette un controllo molto più dettagliato. La funzione principale di questa +nuova interfaccia è \func{sigaction}; il cui prototipo è: + +\begin{prototype}{signal.h}{int sigaction(int signum, const struct sigaction + *act, struct sigaction *oldact)} + + Installa un nuovo manipolatore per il segnale \param{signum}. + + \bodydesc{La funzione restituisce zero in caso di successo e -1 per un + errore, nel qual caso \var{errno} assumerà i valori: + \begin{errlist} + \item[\macro{EINVAL}] Si è specificato un numero di segnale invalido o si è + cercato di installare il manipolatore per \macro{SIGKILL} o + \macro{SIGSTOP}. + \item[\macro{EFAULT}] Si sono specificati indirizzi non validi. + \end{errlist}} +\end{prototype} + +La funzione serve ad installare una nuova azione per il segnale +\param{signum}; si parla di azione e non di manipolatore come nel caso di +\func{signal}, in quanto la funzione consente di specificare le varie +caratteristiche della risposta al segnale, non solo la funzione del +manipolatore. Lo standard POSIX raccomanda di usare sempre questa funzione al +posto di \func{signal} (che in genere viene definita tramite essa), in quanto +offre un controllo completo, sia pure al prezzo di una maggiore complessità +d'uso. + +Se il puntatore \param{act} non è nullo la funzione installa la nuova azione +da esso specificata, se \param{oldact} non è nullo il valore dell'azione +corrente viene restituito indietro. Questo permette (specificando \param{act} +nullo e \param{oldact} non nullo) di superare uno dei limiti di \func{signal}, +che non consente di ottenere l'azione corrente senza installarne una nuova. + +Entrambi i puntatori fanno riferimento alla struttura \var{sigaction}, che +permette di descrivere tutte le caratteristiche dell'azione associata ad un +segnale. Anch'essa è descritta dallo standard POSIX ed in Linux è definita +secondo quanto riportato in \secref{fig:sig_sigaction}, il campo +\var{sa\_restorer}, non previsto dallo standard, è obsoleto e non deve essere +più usato. + +\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} + \end{minipage} + \normalsize + \caption{La struttura \var{sigaction}.} + \label{fig:sig_sigaction} +\end{figure} +\subsection{I \textit{signal set}} +\label{sec:sig_sigset} + + +\subsection{Le funzioni \func{sigpending} e \func{sigsuspend}} +\label{sec:sig_sigpending} -\subsection{La funzione \func{sigaction}} -\label{sec:sig_sigaction} @@ -1625,8 +1698,6 @@ principale, interrompendone inopportunamente l'esecuzione. \label{sec:sig_reentrant} -, affrontando inoltre le varie problematiche di programmazione che si devono -tenere presenti quando si ha a che fare con essi.