X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=signal.tex;h=31f4ee834aecd58194165c93c4f9e630988d389a;hp=540f0e27601886fa18d1922c5f0c3da28b3fb45a;hb=ca90fc9480e327dbf716d34888b7e21f213e921c;hpb=b3365b885a8c9da7ce8a39c1edcaae2a65a91810 diff --git a/signal.tex b/signal.tex index 540f0e2..31f4ee8 100644 --- a/signal.tex +++ b/signal.tex @@ -1513,43 +1513,44 @@ versione di \func{sleep} potrebbe essere quella illustrata in Dato che è nostra intenzione utilizzare \macro{SIGALRM} 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 +salvando il precedente (\texttt{\small 14-17}). 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 17-19}) fino alla sua ricezione. Al ritorno di \func{pause}, +causato dal ritorno del manipolatore (\texttt{\small 1-9}), si ripristina il +manipolatore originario (\texttt{\small 20-21}) restituendo l'eventuale tempo +rimanente (\texttt{\small 22-23}) che potrà essere diverso da zero qualora l'interruzione di \func{pause} venisse causata da un altro segnale. \begin{figure}[!htb] \footnotesize \centering \begin{minipage}[c]{15cm} \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) { - signandler_t prev_handler; + 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); + printf("Cannot set handler for alarm\n"); + exit(-1); } - alarm(second); + /* set alarm and go to sleep */ + alarm(seconds); pause(); /* restore previous signal handler */ signal(SIGALRM, prev_handler); - /* remove alarm, return remaining time */ + /* 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 { /* do nothing, just interrupt pause */ - return; - } -} \end{lstlisting} \end{minipage} \normalsize @@ -1981,7 +1982,6 @@ quest'ultima. Per poter effettuare atomicamente la modifica della maschera dei segnali (di solito attivandone uno specifico) insieme alla sospensione del processo lo standard POSIX ha previsto la funzione \func{sigsuspend}, il cui prototipo è: - \begin{prototype}{signal.h} {int sigsuspend(const sigset\_t *mask)} @@ -1995,7 +1995,88 @@ prototipo \end{errlist}} \end{prototype} +Come esempio dell'uso di queste funzioni proviamo a riscrivere un'altra volta +l'esempio di implementazione di \code{sleep}. Abbiamo accennato in +\secref{sec:sig_sigaction} come con \func{sigaction} sia possibile bloccare +\macro{SIGALRM} nell'installazione dei manipolatori degli altri segnali, per +poter usare l'implementazione vista in \secref{fig:sig_sleep_incomplete} senza +interferenze. Questo però comporta una precauzione ulteriore al semplice uso +della funzione, vediamo allora come usando la nuova interfaccia è possibile +ottenere un'implementazione, riportata in \figref{fig:sig_sleep_ok} che non +presenta neanche questa necessità. + +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15cm} + \begin{lstlisting}{} +#include /* unix standard library */ +#include /* POSIX signal library */ +void alarm_hand(int); +unsigned int sleep(unsigned int seconds) +{ +/* + * Variables definition + */ + 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); +} +/* + * Signal Handler for SIGALRM + */ +void alarm_hand(int sig) +{ + return; /* just return to interrupt sigsuspend */ +} + \end{lstlisting} + \end{minipage} + \normalsize + \caption{Una implementazione completa di \func{sleep}.} + \label{fig:sig_sleep_ok} +\end{figure} +Per evitare i problemi di interferenza con gli altri segnali in questo caso +non si è usato l'approccio di \figref{fig:sig_sleep_incomplete} evitando l'uso +di \func{longjmp}. Come in precedenza il manipolatore (\texttt{\small 35-37}) +non esegue nessuna operazione, limitandosi a ritornare per interrompere il +programma messo in attesa. + +La prima parte della funzione (\texttt{\small 11-15}) provvede ad installare +l'opportuno manipolatore per \macro{SIGALRM}, salvando quello originario, che +sarà ripristinato alla conclusione della stessa (\texttt{\small 28}); il passo +successivo è quello di bloccare \macro{SIGALRM} (\texttt{\small 17-19}) per +evitare che esso possa essere ricevuto dal processo fra l'esecuzione di +\func{alarm} (\texttt{\small 21}) e la sospensione dello stesso. Nel fare +questo si salva la maschera corrente dei segnali, che sarà ripristinata alla +fine (\texttt{\small 27}), e al contempo si prepara la maschera dei segnali +\var{sleep\_mask} per riattivare \macro{SIGALRM} all'esecuzione di +\func{sigsuspend}. In questo modo non sono più possibili race condition dato +che \macro{SIGALRM} viene disabilitato con \func{sigprocmask} fino alla +chiamata di \func{sigsuspend}. + + + +\subsection{Caratteristiche ulteriori} +\label{sec:sig_specific_features}