X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=signal.tex;h=940b921157b4a58fa89d7b1a09fc2931fc30dccf;hp=be01dc4ec8304c0b992281a202f3c5aa056a6633;hb=b25e834fc936d6fb1208333563af924068a5a74b;hpb=f6c4cb8cabe3c33f7057e937d66c8dad6d017086 diff --git a/signal.tex b/signal.tex index be01dc4..940b921 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 @@ -1617,18 +1614,60 @@ 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. È per questo motivo che occorrono funzioni più sofisticate della semplice \func{signal} che -permettano di gestire in maniera più completa +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} +Per i limiti che hanno le funzioni originarie dei primi Unix nella gestione +dei segnali, evidenziati al paragrafo precedente, lo standard POSIX ha +introdotto una interfaccia di gestione completamente diversa, che prevede +tutta una serie di nuove funzioni la principale delle quali è +\func{sigaction}, che lo standard raccomanda come sostituta di \func{signal} +(che da essa infatti può essere ottenuta); il suo 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 struttura \var{sigaction} è anch'essa definita dallo standard POSIX, che +prevede abbia la forma: +\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{Le funzioni \func{sigprocmask} e \func{sigpending}} +\label{sec:sig_sigpending} -\subsection{La funzione \func{sigaction}} -\label{sec:sig_sigaction}