From 3a4838bed13b767132cbdf06364b2658da6cc356 Mon Sep 17 00:00:00 2001 From: chatty Date: Tue, 15 Dec 1992 10:55:33 +0000 Subject: Initial revision --- utils/Signal.cc | 312 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 utils/Signal.cc (limited to 'utils/Signal.cc') diff --git a/utils/Signal.cc b/utils/Signal.cc new file mode 100644 index 0000000..ceb178b --- /dev/null +++ b/utils/Signal.cc @@ -0,0 +1,312 @@ +/* + * CENA C++ Utilities + * + * by Stephane Chatty + * + * Copyright 1992 + * Centre d'Etudes de la Navigation Aerienne (CENA) + * + * Signal handling + * + * $Id$ + * $CurLog$ + */ + +#include "Signal.h" +#include "List.h" +#ifdef sun +/* This should come from , but no available C++ headers on Suns know about POSIX */ +extern "C" { + typedef int sigset_t; + struct sigaction { + void (*sa_handler)(...); + sigset_t sa_mask; + int sa_flags; + }; + +# define NSIG 32 +# define SIGHUP 1 +# define SIGINT 2 +# define SIGQUIT 3 +# define SIGILL 4 +# define SIGTRAP 5 +# define SIGIOT 6 +# define SIGABRT 6 +# define SIGEMT 7 +# define SIGFPE 8 +# define SIGKILL 9 +# define SIGBUS 10 +# define SIGSEGV 11 +# define SIGSYS 12 +# define SIGPIPE 13 +# define SIGALRM 14 +# define SIGTERM 15 +# define SIGURG 16 +# define SIGSTOP 17 +# define SIGTSTP 18 +# define SIGCONT 19 +# define SIGCHLD 20 +# define SIGCLD 20 +# define SIGTTIN 21 +# define SIGTTOU 22 +# define SIGIO 23 +# define SIGPOLL SIGIO +# define SIGXCPU 24 +# define SIGXFSZ 25 +# define SIGVTALRM 26 +# define SIGPROF 27 +# define SIGWINCH 28 +# define SIGLOST 29 +# define SIGUSR1 30 +# define SIGUSR2 31 + +# define SIG_DFL 0 +# define SIG_BLOCK 0x0001 +# define SIG_UNBLOCK 0x0002 +# define SIG_SETMASK 0x0004 + int sigaction (int, const struct sigaction*, struct sigaction*); + int sigemptyset (sigset_t*); + int sigfillset (sigset_t*); + int sigaddset (sigset_t*, int); + int sigprocmask (int, const sigset_t*, sigset_t*); +} +#else +#include +#endif + + +/*?class CcuBaseSignalHandler +The class \typ{CcuBaseSignalHandler} is provided as a base class for signal handlers. +It comes with a derived class \typ{CcuSignalHandler} that can be used as is, without +any derivation. +A signal handler is created for a specific signal, identified by a numeric value. +The following constants are defined: \var{AllSigs, SigHup, SigInt, SigQuit, SigIll, SigTrap, +SigAbrt, SigEmt, SigFpe, SigKill, SigBus, SigSegv, SigSys, SigPipe, SigAlrm, SigTerm, SigUsr1, +SigUsr2, SigChld, SigVtalrm, SigIo, SigStop, SigTstp, SigCont, SigTtin, SigTtou, SigUrg,} +and \var{SigLost}. The value \var{AllSigs} is not meaningful to signal handlers. + +When a signal is received by the program and a signal handler was created for that +signal, its method \fun{Handle} is called. This method should be redefined in derived +classes of \var{CcuBaseSignalHandler}. + +Several signal handlers can be created for the same signal. However, only one is +active at a time. A stack of signal handlers is maintained for every signal, so that +the latest created signal handler is the active one, until its destruction. At that time, +the previous signal handler, if there was one, is activated again. +?*/ + +const int NumSigs = NSIG-1; + +const int AllSigs = -1; +const int SigHup = SIGHUP; +const int SigInt = SIGINT; +const int SigQuit = SIGQUIT; +const int SigIll = SIGILL; +const int SigTrap = SIGTRAP; +const int SigAbrt = SIGABRT; +const int SigEmt = SIGEMT; +const int SigFpe = SIGFPE; +const int SigKill = SIGKILL; +const int SigBus = SIGBUS; +const int SigSegv = SIGSEGV; +const int SigSys = SIGSYS; +const int SigPipe = SIGPIPE; +const int SigAlrm = SIGALRM; +const int SigTerm = SIGTERM; +const int SigUsr1 = SIGUSR1; +const int SigUsr2 = SIGUSR2; +const int SigChld = SIGCHLD; +const int SigVtalrm = SIGVTALRM; +const int SigIo = SIGIO; +const int SigStop = SIGSTOP; +const int SigTstp = SIGTSTP; +const int SigCont = SIGCONT; +const int SigTtin = SIGTTIN; +const int SigTtou = SIGTTOU; +const int SigUrg = SIGURG; +const int SigLost = SIGLOST; + + +CcuList* CcuBaseSignalHandler::HandlerStacks = 0; + +/*?hidden?*/ +void +CcuBaseSignalHandler :: ClassInit () +{ + HandlerStacks = new CcuList [NumSigs]; +} + +/*? +Create a signal handler for the signal \var{sig}. +?*/ +CcuBaseSignalHandler :: CcuBaseSignalHandler (int sig) +: Signal (sig) +{ + CcuSignalBlocker b (sig); + if (!HandlerStacks) + ClassInit (); + HandlerStacks [Signal-1].Prepend (this); + Install (); +} + +/*?nodoc?*/ +CcuBaseSignalHandler :: ~CcuBaseSignalHandler () +{ + CcuSignalBlocker b (Signal); + CcuList& stack = HandlerStacks [Signal-1]; + if (stack.First () == this) { + stack.RemoveFirst (); + if (stack.IsEmpty ()) + InstallNone (Signal); + else + ((CcuBaseSignalHandler*) stack.First ())->Install (); + } else + stack.Remove (this, 1); +} + +/*?hidden?*/ +void +CcuBaseSignalHandler :: Install () +{ + struct sigaction act; + act.sa_handler = (void(*)(...)) DoHandle; + sigemptyset (&act.sa_mask); + act.sa_flags = 0; + sigaction (Signal, &act, 0); +} + +/*?hidden?*/ +void +CcuBaseSignalHandler :: InstallNone (int sig) +{ + struct sigaction act; + act.sa_handler = SIG_DFL; + sigemptyset (&act.sa_mask); + act.sa_flags = 0; + sigaction (sig, &act, 0); +} + +/*?hidden?*/ +void +CcuBaseSignalHandler :: DoHandle (int sig) +{ + CcuBaseSignalHandler* s = (CcuBaseSignalHandler*) HandlerStacks [sig-1].First (); + if (s) + s->Handle (); +} + +/*? +This virtual function should be redefined in derived classes. It is called +when this handler is the currently active one and a signal is received. +?*/ +void +CcuBaseSignalHandler :: Handle () +{ +} + +/*?class CcuSignalHandler +The class \typ{CcuSignalHandler} is a derived class of \typ{CcuBaseSignalHandler} that +can be used without deriving a new class. +Each \typ{CcuSignalHandler} holds a pointer to a function which is called when a +signal is received. This function, which is passed to the constructor, must +take an \typ{int} argument and return \typ{void}. +?*/ + +/*? +Create a signal handler for signal \var{sig}. The function \var{handler} will be +called when a signal is received. +?*/ +CcuSignalHandler :: CcuSignalHandler (int sig, void (*handler) (int)) +: CcuBaseSignalHandler (sig), + Handler (handler) +{ +} + +/*?nodoc?*/ +CcuSignalHandler :: ~CcuSignalHandler () +{ +} + +/*?nodoc?*/ +void +CcuSignalHandler :: Handle () +{ + (*Handler) (Signal); +} + +/*?class CcuSignalBlocker +The class \typ{CcuSignalBlocker} provides protection against signals. +When a \typ{CcuSignalBlocker} is created for a signal type, the program will +be protected against such signals during the lifetime of the signal blocker. +Signal blockers are often used as follows: +\begin{ccode} + void + sensitive_function () + { + CcuSignalBlocker b (SigAlrm); // protect this function against alarms + ... + } +\end{ccode} + +Some signals, such as \var{SIGKILL}, actually cannot be blocked. Creating +a signal blocker for such a signal is ineffective. +Please note that signal numbers currently cannot be combined. If you wish +to protect a function against two signals, you must create two signal blockers. +However, the special value \var{AllSigs} allows the creation of signal blockers +that protect against all kinds of signals. +?*/ + +int CcuSignalBlocker::BlockCounts [NumSigs]; + + +/*? +Create a signal blocker for the signal \var{sig}. If \var{sig} is \var{AllSigs}, +all signals will be blocked. +?*/ +CcuSignalBlocker :: CcuSignalBlocker (int sig) +: Signal (sig) +{ + int all = sig < 1 || sig > NumSigs; + sigset_t set; + if (all) { + sigfillset (&set); + } else { + sigemptyset (&set); + sigaddset (&set, Signal); + } + + /* inhibit interrupts before registering inhibitions */ + sigprocmask (SIG_BLOCK, &set, 0); + + if (all) { + for (int s = 0; s < NumSigs; s++) + BlockCounts [s]++; + } else { + BlockCounts [Signal-1]++; + } +} + +/*?nodoc?*/ +CcuSignalBlocker :: ~CcuSignalBlocker () +{ + int all = Signal < 1 || Signal > NumSigs; + int change = 0; + sigset_t set; + sigemptyset (&set); + + if (all) { + for (int s = 0; s < NumSigs; s++) { + if (!--BlockCounts [s]) { + sigaddset (&set, s+1); + change = 1; + } + } + } else if (!--BlockCounts [Signal-1]) { + sigaddset (&set, Signal); + change = 1; + } + + if (change) + sigprocmask (SIG_UNBLOCK, &set, 0); +} + -- cgit v1.1