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).
definiti in Linux (estratto dalle man page), comparati con quelli definiti in
vari standard.
-
\begin{table}[htb]
\footnotesize
\centering
\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
\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
\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.
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
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
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
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 */
};
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;
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}
\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
\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
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
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}