summaryrefslogtreecommitdiff
path: root/utils/Signal.cc
diff options
context:
space:
mode:
Diffstat (limited to 'utils/Signal.cc')
-rw-r--r--utils/Signal.cc312
1 files changed, 312 insertions, 0 deletions
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 <signal.h>, 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 <signal.h>
+#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);
+}
+