/* * 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)(int); 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); } #ifdef DOC /*? Get the signal that is handled by this signal handler. ?*/ int CcuBaseSignalHandler :: GetSignal () { } #endif /* DOC */ /*?hidden?*/ void CcuBaseSignalHandler :: Install () { struct sigaction act; act.sa_handler = (void(*)(int)) 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 () { } /*?hidden?*/ 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 () { // protect this function against alarms CcuSignalBlocker b (SigAlrm); ... } \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); }