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
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 che non presenta neanche questa necessità.
+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 <unistd.h> /* unix standard library */
+#include <signal.h> /* 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}
--- /dev/null
+/* Sleep.c
+ *
+ * Copyright (C) 2002 Simone Piccardi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+/****************************************************************
+ *
+ * Program Sleep.c:
+ * Example implementation for sleep
+ *
+ * Author: Simone Piccardi
+ * Apr. 2002
+ *
+ ****************************************************************/
+/*
+ * Include needed headers
+ */
+#include <unistd.h> /* unix standard library */
+#include <signal.h> /* 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) {
+ /* just return to interrupt sigsuspend */
+ return;
+}
/*
* Include needed headers
*/
+#define _GNU_SOURCE
#include <unistd.h> /* unix standard library */
+#include <signal.h> /* signal standard library */
-unsigned int sleep(unsigned int seconds)
-{
-/*
- * Variables definition
- */
- signandler_t prev_handler;
-
- if ((prev_handler = signal(SIGALRM, alarm_hand)) == SIG_ERR) {
- printf("Cannot set handler for alarm\n");
- exit(1);
- }
- alarm(second);
- pause();
- /* 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 */
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);
+}