summaryrefslogtreecommitdiff
path: root/utils/Signal.cc
blob: d03ff65b682dedf66996a9d4d5cdab70e9f6b27a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
/*
 *	CENA C++ Utilities
 *
 *	by Stephane Chatty
 *
 *	Copyright 1992
 *	Centre d'Etudes de la Navigation Aerienne (CENA)
 *
 *	Signal handling
 *
 *	$Id$
 *	$CurLog$
 */

#ifdef __GNUG__
#pragma implementation "Signal.h"
#endif

#include "Signal.h"
#include "List.h"
#if defined(sun) && !defined (__svr4__)
/* 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)(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 <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;
#ifdef SIGEMT
const int SigEmt = SIGEMT;
#endif
const int SigFpe = SIGFPE;
const int SigKill = SIGKILL;
const int SigBus = SIGBUS;
const int SigSegv = SIGSEGV;
#ifdef SIGSYS
const int SigSys = SIGSYS;
#endif
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;
#ifdef SIGLOST
const int SigLost = SIGLOST;
#endif

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;
#ifdef __sgi
	act.sa_handler = (SIG_PF) DoHandle;
#else
	act.sa_handler = DoHandle;
#endif
	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);
}