From ca90fc9480e327dbf716d34888b7e21f213e921c Mon Sep 17 00:00:00 2001 From: Simone Piccardi Date: Sat, 20 Apr 2002 23:18:21 +0000 Subject: [PATCH] Correzioni varie, finito esempio sleep --- prochand.tex | 10 ++-- signal.tex | 120 ++++++++++++++++++++++++++++++++++++++--------- sources/Sleep.c | 70 +++++++++++++++++++++++++++ sources/sleep1.c | 36 +++++++------- 4 files changed, 190 insertions(+), 46 deletions(-) create mode 100644 sources/Sleep.c diff --git a/prochand.tex b/prochand.tex index 474b759..d4260c1 100644 --- a/prochand.tex +++ b/prochand.tex @@ -1858,11 +1858,11 @@ semplicemente l'allocazione della risorsa \textsl{tempo di esecuzione}, la cui assegnazione sarà governata dai meccanismi di scelta delle priorità che restano gli stessi indipendentemente dal numero di processori. -I processi non devono solo eseguire del codice, ad esempio molto spesso -saranno impegnati in operazioni di I/O, possono venire bloccati da un comando -dal terminale, sospesi per un certo periodo di tempo. In tutti questi casi la -CPU diventa disponibile ed è compito dello kernel provvedere a mettere in -esecuzione un altro processo. +Si tenga conto poi che i processi non devono solo eseguire del codice: ad +esempio molto spesso saranno impegnati in operazioni di I/O, o portranno +venire bloccati da un comando dal terminale, o sospesi per un certo periodo di +tempo. In tutti questi casi la CPU diventa disponibile ed è compito dello +kernel provvedere a mettere in esecuzione un altro processo. Tutte queste possibilità sono caratterizzate da un diverso \textsl{stato} del processo, in Linux un processo può trovarsi in uno degli stati riportati in diff --git a/signal.tex b/signal.tex index df7197a..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 @@ -2001,8 +2002,81 @@ l'esempio di implementazione di \code{sleep}. Abbiamo accennato in 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 /* 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} diff --git a/sources/Sleep.c b/sources/Sleep.c new file mode 100644 index 0000000..ce5e416 --- /dev/null +++ b/sources/Sleep.c @@ -0,0 +1,70 @@ +/* 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 /* 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) { + /* just return to interrupt sigsuspend */ + return; +} diff --git a/sources/sleep1.c b/sources/sleep1.c index 158e505..2225c96 100644 --- a/sources/sleep1.c +++ b/sources/sleep1.c @@ -28,26 +28,10 @@ /* * Include needed headers */ +#define _GNU_SOURCE #include /* unix standard library */ +#include /* 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 */ @@ -57,3 +41,19 @@ void alarm_hand(int sig) { 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); +} -- 2.30.2