~ubuntu-branches/ubuntu/precise/ghc/precise

« back to all changes in this revision

Viewing changes to rts/posix/Signals.c

  • Committer: Bazaar Package Importer
  • Author(s): Joachim Breitner
  • Date: 2011-01-17 12:49:24 UTC
  • Revision ID: james.westby@ubuntu.com-20110117124924-do1pym1jlf5o636m
Tags: upstream-7.0.1
ImportĀ upstreamĀ versionĀ 7.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -----------------------------------------------------------------------------
 
2
 *
 
3
 * (c) The GHC Team, 1998-2005
 
4
 *
 
5
 * Signal processing / handling.
 
6
 *
 
7
 * ---------------------------------------------------------------------------*/
 
8
 
 
9
#include "PosixSource.h" 
 
10
#include "Rts.h"
 
11
 
 
12
#include "Schedule.h"
 
13
#include "RtsSignals.h"
 
14
#include "Signals.h"
 
15
#include "RtsUtils.h"
 
16
#include "Prelude.h"
 
17
#include "Stable.h"
 
18
 
 
19
#ifdef alpha_HOST_ARCH
 
20
# if defined(linux_HOST_OS)
 
21
#  include <asm/fpu.h>
 
22
# else
 
23
#  include <machine/fpu.h>
 
24
# endif
 
25
#endif
 
26
 
 
27
#ifdef HAVE_UNISTD_H
 
28
# include <unistd.h>
 
29
#endif
 
30
 
 
31
#ifdef HAVE_SIGNAL_H
 
32
# include <signal.h>
 
33
#endif
 
34
 
 
35
#ifdef HAVE_ERRNO_H
 
36
# include <errno.h>
 
37
#endif
 
38
 
 
39
#ifdef HAVE_EVENTFD_H
 
40
# include <sys/eventfd.h>
 
41
#endif
 
42
 
 
43
#include <stdlib.h>
 
44
#include <string.h>
 
45
 
 
46
/* This curious flag is provided for the benefit of the Haskell binding
 
47
 * to POSIX.1 to control whether or not to include SA_NOCLDSTOP when
 
48
 * installing a SIGCHLD handler. 
 
49
 */
 
50
HsInt nocldstop = 0;
 
51
 
 
52
/* -----------------------------------------------------------------------------
 
53
 * The table of signal handlers
 
54
 * -------------------------------------------------------------------------- */
 
55
 
 
56
#if defined(RTS_USER_SIGNALS)
 
57
 
 
58
/* SUP: The type of handlers is a little bit, well, doubtful... */
 
59
StgInt *signal_handlers = NULL; /* Dynamically grown array of signal handlers */
 
60
static StgInt nHandlers = 0;    /* Size of handlers array */
 
61
 
 
62
static nat n_haskell_handlers = 0;
 
63
 
 
64
/* -----------------------------------------------------------------------------
 
65
 * Allocate/resize the table of signal handlers.
 
66
 * -------------------------------------------------------------------------- */
 
67
 
 
68
static void
 
69
more_handlers(int sig)
 
70
{
 
71
    StgInt i;
 
72
 
 
73
    if (sig < nHandlers)
 
74
        return;
 
75
 
 
76
    if (signal_handlers == NULL)
 
77
        signal_handlers = (StgInt *)stgMallocBytes((sig + 1) * sizeof(StgInt), "more_handlers");
 
78
    else
 
79
        signal_handlers = (StgInt *)stgReallocBytes(signal_handlers, (sig + 1) * sizeof(StgInt), "more_handlers");
 
80
 
 
81
    for(i = nHandlers; i <= sig; i++)
 
82
        // Fill in the new slots with default actions
 
83
        signal_handlers[i] = STG_SIG_DFL;
 
84
 
 
85
    nHandlers = sig + 1;
 
86
}
 
87
 
 
88
// Here's the pipe into which we will send our signals
 
89
static int io_manager_wakeup_fd = -1;
 
90
static int io_manager_control_fd = -1;
 
91
 
 
92
#define IO_MANAGER_WAKEUP 0xff
 
93
#define IO_MANAGER_DIE    0xfe
 
94
#define IO_MANAGER_SYNC   0xfd
 
95
 
 
96
void
 
97
setIOManagerWakeupFd (int fd)
 
98
{
 
99
    // only called when THREADED_RTS, but unconditionally
 
100
    // compiled here because System.Event.Control depends on it.
 
101
    io_manager_wakeup_fd = fd;
 
102
}
 
103
 
 
104
void
 
105
setIOManagerControlFd (int fd)
 
106
{
 
107
    // only called when THREADED_RTS, but unconditionally
 
108
    // compiled here because System.Event.Control depends on it.
 
109
    io_manager_control_fd = fd;
 
110
}
 
111
 
 
112
void
 
113
ioManagerWakeup (void)
 
114
{
 
115
    int r;
 
116
    // Wake up the IO Manager thread by sending a byte down its pipe
 
117
    if (io_manager_wakeup_fd >= 0) {
 
118
#if defined(HAVE_EVENTFD)
 
119
        StgWord64 n = (StgWord64)IO_MANAGER_WAKEUP;
 
120
        r = write(io_manager_wakeup_fd, (char *) &n, 8);
 
121
#else
 
122
        StgWord8 byte = (StgWord8)IO_MANAGER_WAKEUP;
 
123
        r = write(io_manager_wakeup_fd, &byte, 1);
 
124
#endif
 
125
        if (r == -1) { sysErrorBelch("ioManagerWakeup: write"); }
 
126
    }
 
127
}
 
128
 
 
129
#if defined(THREADED_RTS)
 
130
void
 
131
ioManagerDie (void)
 
132
{
 
133
    int r;
 
134
    // Ask the IO Manager thread to exit
 
135
    if (io_manager_control_fd >= 0) {
 
136
        StgWord8 byte = (StgWord8)IO_MANAGER_DIE;
 
137
        r = write(io_manager_control_fd, &byte, 1);
 
138
        if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
 
139
        io_manager_control_fd = -1;
 
140
        io_manager_wakeup_fd = -1;
 
141
    }
 
142
}
 
143
 
 
144
Capability *
 
145
ioManagerStartCap (Capability *cap)
 
146
{
 
147
    return rts_evalIO(
 
148
        cap,&base_GHCziConcziIO_ensureIOManagerIsRunning_closure,NULL);
 
149
}
 
150
 
 
151
void
 
152
ioManagerStart (void)
 
153
{
 
154
    // Make sure the IO manager thread is running
 
155
    Capability *cap;
 
156
    if (io_manager_control_fd < 0 || io_manager_wakeup_fd < 0) {
 
157
        cap = rts_lock();
 
158
        cap = ioManagerStartCap(cap);
 
159
        rts_unlock(cap);
 
160
    }
 
161
}
 
162
#endif
 
163
 
 
164
#if !defined(THREADED_RTS)
 
165
 
 
166
#define N_PENDING_HANDLERS 16
 
167
 
 
168
siginfo_t pending_handler_buf[N_PENDING_HANDLERS];
 
169
siginfo_t *next_pending_handler = pending_handler_buf;
 
170
 
 
171
#endif /* THREADED_RTS */
 
172
 
 
173
/* -----------------------------------------------------------------------------
 
174
 * Low-level signal handler
 
175
 *
 
176
 * Places the requested handler on a stack of pending handlers to be
 
177
 * started up at the next context switch.
 
178
 * -------------------------------------------------------------------------- */
 
179
 
 
180
static void
 
181
generic_handler(int sig USED_IF_THREADS,
 
182
                siginfo_t *info,
 
183
                void *p STG_UNUSED)
 
184
{
 
185
#if defined(THREADED_RTS)
 
186
 
 
187
    if (io_manager_control_fd != -1)
 
188
    {
 
189
        StgWord8 buf[sizeof(siginfo_t) + 1];
 
190
        int r;
 
191
 
 
192
        buf[0] = sig;
 
193
 
 
194
        if (info == NULL) {
 
195
            // info may be NULL on Solaris (see #3790)
 
196
            memset(buf+1, 0, sizeof(siginfo_t));
 
197
        } else {
 
198
            memcpy(buf+1, info, sizeof(siginfo_t));
 
199
        }
 
200
 
 
201
        r = write(io_manager_control_fd, buf, sizeof(siginfo_t)+1);
 
202
        if (r == -1 && errno == EAGAIN)
 
203
        {
 
204
            errorBelch("lost signal due to full pipe: %d\n", sig);
 
205
        }
 
206
    }
 
207
    // If the IO manager hasn't told us what the FD of the write end
 
208
    // of its pipe is, there's not much we can do here, so just ignore
 
209
    // the signal..
 
210
 
 
211
#else /* not THREADED_RTS */
 
212
 
 
213
    /* Can't call allocate from here.  Probably can't call malloc
 
214
       either.  However, we have to schedule a new thread somehow.
 
215
 
 
216
       It's probably ok to request a context switch and allow the
 
217
       scheduler to  start the handler thread, but how do we
 
218
       communicate this to the scheduler?
 
219
 
 
220
       We need some kind of locking, but with low overhead (i.e. no
 
221
       blocking signals every time around the scheduler).
 
222
       
 
223
       Signal Handlers are atomic (i.e. they can't be interrupted), and
 
224
       we can make use of this.  We just need to make sure the
 
225
       critical section of the scheduler can't be interrupted - the
 
226
       only way to do this is to block signals.  However, we can lower
 
227
       the overhead by only blocking signals when there are any
 
228
       handlers to run, i.e. the set of pending handlers is
 
229
       non-empty.
 
230
    */
 
231
       
 
232
    /* We use a stack to store the pending signals.  We can't
 
233
       dynamically grow this since we can't allocate any memory from
 
234
       within a signal handler.
 
235
 
 
236
       Hence unfortunately we have to bomb out if the buffer
 
237
       overflows.  It might be acceptable to carry on in certain
 
238
       circumstances, depending on the signal.  
 
239
    */
 
240
 
 
241
    memcpy(next_pending_handler, info, sizeof(siginfo_t));
 
242
 
 
243
    next_pending_handler++;
 
244
 
 
245
    // stack full?
 
246
    if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
 
247
        errorBelch("too many pending signals");
 
248
        stg_exit(EXIT_FAILURE);
 
249
    }
 
250
    
 
251
    contextSwitchCapability(&MainCapability);
 
252
 
 
253
#endif /* THREADED_RTS */
 
254
}
 
255
 
 
256
/* -----------------------------------------------------------------------------
 
257
 * Blocking/Unblocking of the user signals
 
258
 * -------------------------------------------------------------------------- */
 
259
 
 
260
static sigset_t userSignals;
 
261
static sigset_t savedSignals;
 
262
 
 
263
void
 
264
initUserSignals(void)
 
265
{
 
266
    sigemptyset(&userSignals);
 
267
#ifndef THREADED_RTS
 
268
    getStablePtr((StgPtr)&base_GHCziConcziSignal_runHandlers_closure);
 
269
    // needed to keep runHandler alive
 
270
#endif
 
271
}
 
272
 
 
273
void
 
274
blockUserSignals(void)
 
275
{
 
276
    sigprocmask(SIG_BLOCK, &userSignals, &savedSignals);
 
277
}
 
278
 
 
279
void
 
280
unblockUserSignals(void)
 
281
{
 
282
    sigprocmask(SIG_SETMASK, &savedSignals, NULL);
 
283
}
 
284
 
 
285
rtsBool
 
286
anyUserHandlers(void)
 
287
{
 
288
    return n_haskell_handlers != 0;
 
289
}
 
290
 
 
291
#if !defined(THREADED_RTS)
 
292
void
 
293
awaitUserSignals(void)
 
294
{
 
295
    while (!signals_pending() && sched_state == SCHED_RUNNING) {
 
296
        pause();
 
297
    }
 
298
}
 
299
#endif
 
300
 
 
301
/* -----------------------------------------------------------------------------
 
302
 * Install a Haskell signal handler.
 
303
 *
 
304
 * We should really do this in Haskell in GHC.Conc, and share the
 
305
 * signal_handlers array with the one there.
 
306
 *
 
307
 * -------------------------------------------------------------------------- */
 
308
 
 
309
int
 
310
stg_sig_install(int sig, int spi, void *mask)
 
311
{
 
312
    sigset_t signals, osignals;
 
313
    struct sigaction action;
 
314
    StgInt previous_spi;
 
315
 
 
316
    // Block the signal until we figure out what to do
 
317
    // Count on this to fail if the signal number is invalid
 
318
    if (sig < 0 || sigemptyset(&signals) ||
 
319
        sigaddset(&signals, sig) || sigprocmask(SIG_BLOCK, &signals, &osignals)) {
 
320
        return STG_SIG_ERR;
 
321
    }
 
322
    
 
323
    more_handlers(sig);
 
324
 
 
325
    previous_spi = signal_handlers[sig];
 
326
 
 
327
    action.sa_flags = 0;
 
328
    
 
329
    switch(spi) {
 
330
    case STG_SIG_IGN:
 
331
        action.sa_handler = SIG_IGN;
 
332
        break;
 
333
 
 
334
    case STG_SIG_DFL:
 
335
        action.sa_handler = SIG_DFL;
 
336
        break;
 
337
 
 
338
    case STG_SIG_RST:
 
339
        action.sa_flags |= SA_RESETHAND;
 
340
        /* fall through */
 
341
    case STG_SIG_HAN:
 
342
        action.sa_sigaction = generic_handler;
 
343
        action.sa_flags |= SA_SIGINFO;
 
344
        break;
 
345
 
 
346
    default:
 
347
        barf("stg_sig_install: bad spi");
 
348
    }
 
349
 
 
350
    if (mask != NULL)
 
351
        action.sa_mask = *(sigset_t *)mask;
 
352
    else
 
353
        sigemptyset(&action.sa_mask);
 
354
 
 
355
    action.sa_flags |= sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
 
356
 
 
357
    if (sigaction(sig, &action, NULL))
 
358
    {
 
359
        errorBelch("sigaction");
 
360
        return STG_SIG_ERR;
 
361
    }
 
362
 
 
363
    signal_handlers[sig] = spi;
 
364
 
 
365
    switch(spi) {
 
366
    case STG_SIG_RST:
 
367
    case STG_SIG_HAN:
 
368
        sigaddset(&userSignals, sig);
 
369
        if (previous_spi != STG_SIG_HAN && previous_spi != STG_SIG_RST) {
 
370
            n_haskell_handlers++;
 
371
        }
 
372
        break;
 
373
 
 
374
    default:
 
375
        sigdelset(&userSignals, sig);
 
376
        if (previous_spi == STG_SIG_HAN || previous_spi == STG_SIG_RST) {
 
377
            n_haskell_handlers--;
 
378
        }
 
379
        break;
 
380
    }
 
381
 
 
382
    if (sigprocmask(SIG_SETMASK, &osignals, NULL))
 
383
    {
 
384
        errorBelch("sigprocmask");
 
385
        return STG_SIG_ERR;
 
386
    }
 
387
 
 
388
    return previous_spi;
 
389
}
 
390
 
 
391
/* -----------------------------------------------------------------------------
 
392
 * Creating new threads for signal handlers.
 
393
 * -------------------------------------------------------------------------- */
 
394
 
 
395
#if !defined(THREADED_RTS)
 
396
void
 
397
startSignalHandlers(Capability *cap)
 
398
{
 
399
  siginfo_t *info;
 
400
  int sig;
 
401
 
 
402
  blockUserSignals();
 
403
  
 
404
  while (next_pending_handler != pending_handler_buf) {
 
405
 
 
406
    next_pending_handler--;
 
407
 
 
408
    sig = next_pending_handler->si_signo;
 
409
    if (signal_handlers[sig] == STG_SIG_DFL) {
 
410
        continue; // handler has been changed.
 
411
    }
 
412
 
 
413
    info = stgMallocBytes(sizeof(siginfo_t), "startSignalHandlers"); 
 
414
           // freed by runHandler
 
415
    memcpy(info, next_pending_handler, sizeof(siginfo_t));
 
416
 
 
417
    scheduleThread (cap,
 
418
        createIOThread(cap,
 
419
                       RtsFlags.GcFlags.initialStkSize, 
 
420
                       rts_apply(cap,
 
421
                                 rts_apply(cap,
 
422
                                           &base_GHCziConcziSignal_runHandlers_closure,
 
423
                                           rts_mkPtr(cap, info)),
 
424
                                 rts_mkInt(cap, info->si_signo))));
 
425
  }
 
426
 
 
427
  unblockUserSignals();
 
428
}
 
429
#endif
 
430
 
 
431
/* ----------------------------------------------------------------------------
 
432
 * Mark signal handlers during GC.
 
433
 * -------------------------------------------------------------------------- */
 
434
 
 
435
void
 
436
markSignalHandlers (evac_fn evac STG_UNUSED, void *user STG_UNUSED)
 
437
{
 
438
    // nothing to do
 
439
}
 
440
 
 
441
#else /* !RTS_USER_SIGNALS */
 
442
StgInt 
 
443
stg_sig_install(StgInt sig STG_UNUSED,
 
444
                StgInt spi STG_UNUSED,
 
445
                void* mask STG_UNUSED)
 
446
{
 
447
  //barf("User signals not supported");
 
448
  return STG_SIG_DFL;
 
449
}
 
450
 
 
451
#endif
 
452
 
 
453
#if defined(RTS_USER_SIGNALS)
 
454
/* -----------------------------------------------------------------------------
 
455
 * SIGINT handler.
 
456
 *
 
457
 * We like to shutdown nicely after receiving a SIGINT, write out the
 
458
 * stats, write profiling info, close open files and flush buffers etc.
 
459
 * -------------------------------------------------------------------------- */
 
460
static void
 
461
shutdown_handler(int sig STG_UNUSED)
 
462
{
 
463
    // If we're already trying to interrupt the RTS, terminate with
 
464
    // extreme prejudice.  So the first ^C tries to exit the program
 
465
    // cleanly, and the second one just kills it.
 
466
    if (sched_state >= SCHED_INTERRUPTING) {
 
467
        stg_exit(EXIT_INTERRUPTED);
 
468
    } else {
 
469
        interruptStgRts();
 
470
    }
 
471
}
 
472
 
 
473
/* -----------------------------------------------------------------------------
 
474
 * An empty signal handler, currently used for SIGPIPE
 
475
 * -------------------------------------------------------------------------- */
 
476
static void
 
477
empty_handler (int sig STG_UNUSED)
 
478
{
 
479
    // nothing
 
480
}
 
481
 
 
482
/* -----------------------------------------------------------------------------
 
483
 * Install default signal handlers.
 
484
 *
 
485
 * The RTS installs a default signal handler for catching
 
486
 * SIGINT, so that we can perform an orderly shutdown.
 
487
 *
 
488
 * Haskell code may install their own SIGINT handler, which is
 
489
 * fine, provided they're so kind as to put back the old one
 
490
 * when they de-install.
 
491
 *
 
492
 * In addition to handling SIGINT, the RTS also handles SIGFPE
 
493
 * by ignoring it.  Apparently IEEE requires floating-point
 
494
 * exceptions to be ignored by default, but alpha-dec-osf3
 
495
 * doesn't seem to do so.
 
496
 * -------------------------------------------------------------------------- */
 
497
void
 
498
initDefaultHandlers(void)
 
499
{
 
500
    struct sigaction action,oact;
 
501
 
 
502
    // install the SIGINT handler
 
503
    action.sa_handler = shutdown_handler;
 
504
    sigemptyset(&action.sa_mask);
 
505
    action.sa_flags = 0;
 
506
    if (sigaction(SIGINT, &action, &oact) != 0) {
 
507
        sysErrorBelch("warning: failed to install SIGINT handler");
 
508
    }
 
509
 
 
510
#if defined(HAVE_SIGINTERRUPT)
 
511
    siginterrupt(SIGINT, 1);    // isn't this the default? --SDM
 
512
#endif
 
513
 
 
514
    // install the SIGFPE handler
 
515
 
 
516
    // In addition to handling SIGINT, also handle SIGFPE by ignoring it.
 
517
    // Apparently IEEE requires floating-point exceptions to be ignored by
 
518
    // default, but alpha-dec-osf3 doesn't seem to do so.
 
519
 
 
520
    // Commented out by SDM 2/7/2002: this causes an infinite loop on
 
521
    // some architectures when an integer division by zero occurs: we
 
522
    // don't recover from the floating point exception, and the
 
523
    // program just generates another one immediately.
 
524
#if 0
 
525
    action.sa_handler = SIG_IGN;
 
526
    sigemptyset(&action.sa_mask);
 
527
    action.sa_flags = 0;
 
528
    if (sigaction(SIGFPE, &action, &oact) != 0) {
 
529
        sysErrorBelch("warning: failed to install SIGFPE handler");
 
530
    }
 
531
#endif
 
532
 
 
533
#ifdef alpha_HOST_ARCH
 
534
    ieee_set_fp_control(0);
 
535
#endif
 
536
 
 
537
    // ignore SIGPIPE; see #1619
 
538
    // actually, we use an empty signal handler rather than SIG_IGN,
 
539
    // so that SIGPIPE gets reset to its default behaviour on exec.
 
540
    action.sa_handler = empty_handler;
 
541
    sigemptyset(&action.sa_mask);
 
542
    action.sa_flags = 0;
 
543
    if (sigaction(SIGPIPE, &action, &oact) != 0) {
 
544
        sysErrorBelch("warning: failed to install SIGPIPE handler");
 
545
    }
 
546
}
 
547
 
 
548
void
 
549
resetDefaultHandlers(void)
 
550
{
 
551
    struct sigaction action;
 
552
 
 
553
    action.sa_handler = SIG_DFL;
 
554
    sigemptyset(&action.sa_mask);
 
555
    action.sa_flags = 0;
 
556
 
 
557
    // restore SIGINT
 
558
    if (sigaction(SIGINT, &action, NULL) != 0) {
 
559
        sysErrorBelch("warning: failed to uninstall SIGINT handler");
 
560
    }
 
561
    // restore SIGPIPE
 
562
    if (sigaction(SIGPIPE, &action, NULL) != 0) {
 
563
        sysErrorBelch("warning: failed to uninstall SIGPIPE handler");
 
564
    }
 
565
}
 
566
 
 
567
void
 
568
freeSignalHandlers(void) {
 
569
    if (signal_handlers != NULL) {
 
570
        stgFree(signal_handlers);
 
571
    }
 
572
}
 
573
 
 
574
#endif /* RTS_USER_SIGNALS */