Signals.c 13.8 KB
Newer Older
1
/* -----------------------------------------------------------------------------
2
 *
3
 * (c) The GHC Team, 1998-2005
4
5
6
7
8
 *
 * Signal processing / handling.
 *
 * ---------------------------------------------------------------------------*/

9
/* This is non-Posix-compliant.
10
11
   #include "PosixSource.h" 
*/
12
13
#include "Rts.h"
#include "SchedAPI.h"
14
#include "Schedule.h"
15
16
#include "RtsSignals.h"
#include "posix/Signals.h"
17
18
#include "RtsUtils.h"
#include "RtsFlags.h"
19
#include "Prelude.h"
20
#include "ThrIOManager.h"
21

22
23
#ifdef alpha_HOST_ARCH
# if defined(linux_HOST_OS)
24
25
26
27
#  include <asm/fpu.h>
# else
#  include <machine/fpu.h>
# endif
ken's avatar
ken committed
28
29
#endif

30
31
32
33
34
35
36
37
38
39
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif

#ifdef HAVE_SIGNAL_H
# include <signal.h>
#endif

#include <stdlib.h>

sof's avatar
sof committed
40
41
42
43
/* This curious flag is provided for the benefit of the Haskell binding
 * to POSIX.1 to control whether or not to include SA_NOCLDSTOP when
 * installing a SIGCHLD handler. 
 */
Ian Lynagh's avatar
Ian Lynagh committed
44
HsInt nocldstop = 0;
sof's avatar
sof committed
45

46
47
48
49
/* -----------------------------------------------------------------------------
 * The table of signal handlers
 * -------------------------------------------------------------------------- */

sof's avatar
sof committed
50
#if defined(RTS_USER_SIGNALS)
51

52
/* SUP: The type of handlers is a little bit, well, doubtful... */
53
StgInt *signal_handlers = NULL; /* Dynamically grown array of signal handlers */
54
55
static StgInt nHandlers = 0;    /* Size of handlers array */

56
57
static nat n_haskell_handlers = 0;

58
/* -----------------------------------------------------------------------------
59
60
 * Allocate/resize the table of signal handlers.
 * -------------------------------------------------------------------------- */
61
62
63
64

static void
more_handlers(I_ sig)
{
65
    StgInt i;
66
67

    if (sig < nHandlers)
68
	return;
69

70
71
    if (signal_handlers == NULL)
	signal_handlers = (StgInt *)stgMallocBytes((sig + 1) * sizeof(StgInt), "more_handlers");
72
    else
73
	signal_handlers = (StgInt *)stgReallocBytes(signal_handlers, (sig + 1) * sizeof(StgInt), "more_handlers");
74
75

    for(i = nHandlers; i <= sig; i++)
76
	// Fill in the new slots with default actions
77
	signal_handlers[i] = STG_SIG_DFL;
78
79
80
81

    nHandlers = sig + 1;
}

82
83
84
85
/* -----------------------------------------------------------------------------
 * Pending Handlers
 *
 * The mechanism for starting handlers differs between the threaded
86
 * (THREADED_RTS) and non-threaded versions of the RTS.
87
88
89
90
91
 *
 * When the RTS is single-threaded, we just write the pending signal
 * handlers into a buffer, and start a thread for each one in the
 * scheduler loop.
 *
92
 * When THREADED_RTS, the problem is that signals might be
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
 * delivered to multiple threads, so we would need to synchronise
 * access to pending_handler_buf somehow.  Using thread
 * synchronisation from a signal handler isn't possible in general
 * (some OSs support it, eg. MacOS X, but not all).  So instead:
 *
 *   - the signal handler writes the signal number into the pipe
 *     managed by the IO manager thread (see GHC.Conc).
 *   - the IO manager picks up the signal number and calls
 *     startSignalHandler() to start the thread.
 *
 * This also has the nice property that we don't need to arrange to
 * wake up a worker task to start the signal handler: the IO manager
 * wakes up when we write into the pipe.
 *
 * -------------------------------------------------------------------------- */

// Here's the pipe into which we will send our signals
static int io_manager_pipe = -1;

112
113
114
#define IO_MANAGER_WAKEUP 0xff
#define IO_MANAGER_DIE    0xfe

115
116
117
void
setIOManagerPipe (int fd)
{
118
    // only called when THREADED_RTS, but unconditionally
119
120
121
122
    // compiled here because GHC.Conc depends on it.
    io_manager_pipe = fd;
}

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
#if defined(THREADED_RTS)
void
ioManagerWakeup (void)
{
    // Wake up the IO Manager thread by sending a byte down its pipe
    if (io_manager_pipe >= 0) {
	StgWord8 byte = (StgWord8)IO_MANAGER_WAKEUP;
	write(io_manager_pipe, &byte, 1);
    }
}

void
ioManagerDie (void)
{
    // Ask the IO Manager thread to exit
    if (io_manager_pipe >= 0) {
	StgWord8 byte = (StgWord8)IO_MANAGER_DIE;
	write(io_manager_pipe, &byte, 1);
    }
}

void
ioManagerStart (void)
{
    // Make sure the IO manager thread is running
    Capability *cap;
    if (io_manager_pipe < 0) {
	cap = rts_lock();
151
	rts_evalIO(cap,&base_GHCziConc_ensureIOManagerIsRunning_closure,NULL);
152
153
154
155
156
	rts_unlock(cap);
    }
}
#endif

157
#if !defined(THREADED_RTS)
158
159
160
161
162
163

#define N_PENDING_HANDLERS 16

StgPtr pending_handler_buf[N_PENDING_HANDLERS];
StgPtr *next_pending_handler = pending_handler_buf;

164
#endif /* THREADED_RTS */
165

166
167
168
169
170
171
/* -----------------------------------------------------------------------------
 * Low-level signal handler
 *
 * Places the requested handler on a stack of pending handlers to be
 * started up at the next context switch.
 * -------------------------------------------------------------------------- */
172
173
174
175
176
177

static void
generic_handler(int sig)
{
    sigset_t signals;

178
#if defined(THREADED_RTS)
179

180
181
182
183
184
185
    if (io_manager_pipe != -1)
    {
	// Write the signal number into the pipe as a single byte.  We
	// hope that signals fit into a byte...
	StgWord8 csig = (StgWord8)sig;
	write(io_manager_pipe, &csig, 1);
186
    }
187
188
189
190
    // If the IO manager hasn't told us what the FD of the write end
    // of its pipe is, there's not much we can do here, so just ignore
    // the signal..

191
#else /* not THREADED_RTS */
192

193
194
195
196
    /* Can't call allocate from here.  Probably can't call malloc
       either.  However, we have to schedule a new thread somehow.

       It's probably ok to request a context switch and allow the
197
       scheduler to  start the handler thread, but how do we
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
       communicate this to the scheduler?

       We need some kind of locking, but with low overhead (i.e. no
       blocking signals every time around the scheduler).
       
       Signal Handlers are atomic (i.e. they can't be interrupted), and
       we can make use of this.  We just need to make sure the
       critical section of the scheduler can't be interrupted - the
       only way to do this is to block signals.  However, we can lower
       the overhead by only blocking signals when there are any
       handlers to run, i.e. the set of pending handlers is
       non-empty.
    */
       
    /* We use a stack to store the pending signals.  We can't
       dynamically grow this since we can't allocate any memory from
       within a signal handler.

       Hence unfortunately we have to bomb out if the buffer
       overflows.  It might be acceptable to carry on in certain
       circumstances, depending on the signal.  
    */

221
    *next_pending_handler++ = deRefStablePtr((StgStablePtr)signal_handlers[sig]);
222

223
    // stack full?
224
    if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
225
	errorBelch("too many pending signals");
226
	stg_exit(EXIT_FAILURE);
227
228
    }
    
229
#endif /* THREADED_RTS */
230

231
    // re-establish the signal handler, and carry on
232
233
234
    sigemptyset(&signals);
    sigaddset(&signals, sig);
    sigprocmask(SIG_UNBLOCK, &signals, NULL);
235
236

    context_switch = 1;
237
238
239
}

/* -----------------------------------------------------------------------------
240
241
 * Blocking/Unblocking of the user signals
 * -------------------------------------------------------------------------- */
242
243
244
245
246
247
248
249
250
251
252
253
254

static sigset_t userSignals;
static sigset_t savedSignals;

void
initUserSignals(void)
{
    sigemptyset(&userSignals);
}

void
blockUserSignals(void)
{
255
    sigprocmask(SIG_BLOCK, &userSignals, &savedSignals);
256
257
258
259
260
261
262
263
}

void
unblockUserSignals(void)
{
    sigprocmask(SIG_SETMASK, &savedSignals, NULL);
}

264
265
266
267
268
269
rtsBool
anyUserHandlers(void)
{
    return n_haskell_handlers != 0;
}

270
#if !defined(THREADED_RTS)
271
272
273
void
awaitUserSignals(void)
{
274
    while (!signals_pending() && sched_state == SCHED_RUNNING) {
275
276
277
	pause();
    }
}
278
#endif
279
280

/* -----------------------------------------------------------------------------
281
282
 * Install a Haskell signal handler.
 * -------------------------------------------------------------------------- */
283

284
285
int
stg_sig_install(int sig, int spi, StgStablePtr *handler, void *mask)
286
{
287
    sigset_t signals, osignals;
288
289
290
    struct sigaction action;
    StgInt previous_spi;

291
292
293
    // Block the signal until we figure out what to do
    // Count on this to fail if the signal number is invalid
    if (sig < 0 || sigemptyset(&signals) ||
294
	sigaddset(&signals, sig) || sigprocmask(SIG_BLOCK, &signals, &osignals)) {
295
296
297
	return STG_SIG_ERR;
    }
    
298
299
    more_handlers(sig);

300
    previous_spi = signal_handlers[sig];
301

302
303
    action.sa_flags = 0;
    
304
305
    switch(spi) {
    case STG_SIG_IGN:
306
    	signal_handlers[sig] = STG_SIG_IGN;
307
308
309
310
311
	sigdelset(&userSignals, sig);
        action.sa_handler = SIG_IGN;
    	break;
    	
    case STG_SIG_DFL:
312
    	signal_handlers[sig] = STG_SIG_DFL;
313
314
315
	sigdelset(&userSignals, sig);
        action.sa_handler = SIG_DFL;
    	break;
316

317
    case STG_SIG_HAN:
318
    case STG_SIG_RST:
319
    	signal_handlers[sig] = (StgInt)*handler;
320
321
	sigaddset(&userSignals, sig);
    	action.sa_handler = generic_handler;
322
323
324
	if (spi == STG_SIG_RST) {
	    action.sa_flags = SA_RESETHAND;
	}
325
	n_haskell_handlers++;
326
    	break;
327

328
    default:
329
        barf("stg_sig_install: bad spi");
330
331
    }

332
333
    if (mask != NULL)
        action.sa_mask = *(sigset_t *)mask;
334
335
336
    else
	sigemptyset(&action.sa_mask);

337
    action.sa_flags |= sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
338
339

    if (sigaction(sig, &action, NULL) || 
340
	sigprocmask(SIG_SETMASK, &osignals, NULL)) 
341
    {
342
343
344
	// need to return an error code, so avoid a stable pointer leak
	// by freeing the previous handler if there was one.
	if (previous_spi >= 0) {
345
	    freeStablePtr(stgCast(StgStablePtr,signal_handlers[sig]));
346
	    n_haskell_handlers--;
347
348
	}
	return STG_SIG_ERR;
349
    }
sof's avatar
sof committed
350

351
352
353
354
355
356
357
    if (previous_spi == STG_SIG_DFL || previous_spi == STG_SIG_IGN
	|| previous_spi == STG_SIG_ERR) {
	return previous_spi;
    } else {
	*handler = (StgStablePtr)previous_spi;
	return STG_SIG_HAN;
    }
358
359
360
}

/* -----------------------------------------------------------------------------
361
 * Creating new threads for signal handlers.
362
 * -------------------------------------------------------------------------- */
363

364
#if !defined(THREADED_RTS)
365
void
366
startSignalHandlers(Capability *cap)
367
368
369
370
371
372
373
{
  blockUserSignals();
  
  while (next_pending_handler != pending_handler_buf) {

    next_pending_handler--;

374
375
    scheduleThread (cap,
	createIOThread(cap,
376
377
		       RtsFlags.GcFlags.initialStkSize, 
		       (StgClosure *) *next_pending_handler));
378
379
380
381
  }

  unblockUserSignals();
}
382
#endif
383

384
385
386
387
388
389
390
391
392
/* ----------------------------------------------------------------------------
 * Mark signal handlers during GC.
 *
 * We do this rather than trying to start all the signal handlers
 * prior to GC, because that requires extra heap for the new threads.
 * Signals must be blocked (see blockUserSignals() above) during GC to
 * avoid race conditions.
 * -------------------------------------------------------------------------- */

393
#if !defined(THREADED_RTS)
394
void
395
markSignalHandlers (evac_fn evac, void *user)
396
397
398
399
400
401
{
    StgPtr *p;

    p = next_pending_handler;
    while (p != pending_handler_buf) {
	p--;
402
	evac(user, (StgClosure **)p);
403
404
    }
}
405
406
#else
void
407
markSignalHandlers (evac_fn evac STG_UNUSED, void *user STG_UNUSED)
408
409
410
{
}
#endif
411

sof's avatar
sof committed
412
#else /* !RTS_USER_SIGNALS */
413
StgInt 
sof's avatar
sof committed
414
415
416
417
stg_sig_install(StgInt sig STG_UNUSED,
		StgInt spi STG_UNUSED,
		StgStablePtr* handler STG_UNUSED,
		void* mask STG_UNUSED)
418
{
sof's avatar
sof committed
419
420
  //barf("User signals not supported");
  return STG_SIG_DFL;
421
422
423
}

#endif
sof's avatar
sof committed
424

sof's avatar
sof committed
425
#if defined(RTS_USER_SIGNALS)
426
/* -----------------------------------------------------------------------------
427
428
429
430
431
 * SIGINT handler.
 *
 * We like to shutdown nicely after receiving a SIGINT, write out the
 * stats, write profiling info, close open files and flush buffers etc.
 * -------------------------------------------------------------------------- */
sof's avatar
sof committed
432
static void
433
shutdown_handler(int sig STG_UNUSED)
sof's avatar
sof committed
434
{
435
436
437
    // If we're already trying to interrupt the RTS, terminate with
    // extreme prejudice.  So the first ^C tries to exit the program
    // cleanly, and the second one just kills it.
438
    if (sched_state >= SCHED_INTERRUPTING) {
sof's avatar
sof committed
439
	stg_exit(EXIT_INTERRUPTED);
440
441
442
    } else {
	interruptStgRts();
    }
sof's avatar
sof committed
443
444
}

445
446
447
/* -----------------------------------------------------------------------------
 * Install default signal handlers.
 *
sof's avatar
sof committed
448
 * The RTS installs a default signal handler for catching
449
 * SIGINT, so that we can perform an orderly shutdown.
sof's avatar
sof committed
450
451
452
453
 *
 * Haskell code may install their own SIGINT handler, which is
 * fine, provided they're so kind as to put back the old one
 * when they de-install.
ken's avatar
ken committed
454
455
456
457
458
 *
 * In addition to handling SIGINT, the RTS also handles SIGFPE
 * by ignoring it.  Apparently IEEE requires floating-point
 * exceptions to be ignored by default, but alpha-dec-osf3
 * doesn't seem to do so.
459
 * -------------------------------------------------------------------------- */
sof's avatar
sof committed
460
void
461
initDefaultHandlers()
sof's avatar
sof committed
462
463
464
{
    struct sigaction action,oact;

465
    // install the SIGINT handler
sof's avatar
sof committed
466
467
468
469
    action.sa_handler = shutdown_handler;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    if (sigaction(SIGINT, &action, &oact) != 0) {
470
	sysErrorBelch("warning: failed to install SIGINT handler");
sof's avatar
sof committed
471
    }
472

sof's avatar
sof committed
473
#if defined(HAVE_SIGINTERRUPT)
474
    siginterrupt(SIGINT, 1);	// isn't this the default? --SDM
sof's avatar
sof committed
475
#endif
476
477

    // install the SIGFPE handler
478
479
480
481
482
483
484
485
486
487

    // In addition to handling SIGINT, also handle SIGFPE by ignoring it.
    // Apparently IEEE requires floating-point exceptions to be ignored by
    // default, but alpha-dec-osf3 doesn't seem to do so.

    // Commented out by SDM 2/7/2002: this causes an infinite loop on
    // some architectures when an integer division by zero occurs: we
    // don't recover from the floating point exception, and the
    // program just generates another one immediately.
#if 0
ken's avatar
ken committed
488
489
490
491
    action.sa_handler = SIG_IGN;
    sigemptyset(&action.sa_mask);
    action.sa_flags = 0;
    if (sigaction(SIGFPE, &action, &oact) != 0) {
492
	sysErrorBelch("warning: failed to install SIGFPE handler");
ken's avatar
ken committed
493
    }
494
495
#endif

496
#ifdef alpha_HOST_ARCH
ken's avatar
ken committed
497
498
    ieee_set_fp_control(0);
#endif
499
}
sof's avatar
sof committed
500

Ian Lynagh's avatar
Ian Lynagh committed
501
502
503
504
505
506
507
void
freeSignalHandlers(void) {
    if (signal_handlers != NULL) {
        stgFree(signal_handlers);
    }
}

sof's avatar
sof committed
508
#endif /* RTS_USER_SIGNALS */