1 /* -----------------------------------------------------------------------------
3 * (c) The GHC Team, 1998-2005
5 * Signal processing / handling.
7 * ---------------------------------------------------------------------------*/
9 #include "PosixSource.h"
13 #include "RtsSignals.h"
19 #ifdef alpha_HOST_ARCH
20 # if defined(linux_HOST_OS)
23 # include <machine/fpu.h>
40 # include <sys/eventfd.h>
50 /* This curious flag is provided for the benefit of the Haskell binding
51 * to POSIX.1 to control whether or not to include SA_NOCLDSTOP when
52 * installing a SIGCHLD handler.
56 /* -----------------------------------------------------------------------------
57 * The table of signal handlers
58 * -------------------------------------------------------------------------- */
60 #if defined(RTS_USER_SIGNALS)
62 /* SUP: The type of handlers is a little bit, well, doubtful... */
63 StgInt *signal_handlers = NULL; /* Dynamically grown array of signal handlers */
64 static StgInt nHandlers = 0; /* Size of handlers array */
66 static nat n_haskell_handlers = 0;
68 /* -----------------------------------------------------------------------------
69 * Allocate/resize the table of signal handlers.
70 * -------------------------------------------------------------------------- */
73 more_handlers(int sig)
80 if (signal_handlers == NULL)
81 signal_handlers = (StgInt *)stgMallocBytes((sig + 1) * sizeof(StgInt), "more_handlers");
83 signal_handlers = (StgInt *)stgReallocBytes(signal_handlers, (sig + 1) * sizeof(StgInt), "more_handlers");
85 for(i = nHandlers; i <= sig; i++)
86 // Fill in the new slots with default actions
87 signal_handlers[i] = STG_SIG_DFL;
92 // Here's the pipe into which we will send our signals
93 static int io_manager_wakeup_fd = -1;
94 static int io_manager_control_fd = -1;
96 #define IO_MANAGER_WAKEUP 0xff
97 #define IO_MANAGER_DIE 0xfe
98 #define IO_MANAGER_SYNC 0xfd
101 setIOManagerWakeupFd (int fd)
103 // only called when THREADED_RTS, but unconditionally
104 // compiled here because GHC.Event.Control depends on it.
105 io_manager_wakeup_fd = fd;
109 setIOManagerControlFd (int fd)
111 // only called when THREADED_RTS, but unconditionally
112 // compiled here because GHC.Event.Control depends on it.
113 io_manager_control_fd = fd;
117 ioManagerWakeup (void)
120 // Wake up the IO Manager thread by sending a byte down its pipe
121 if (io_manager_wakeup_fd >= 0) {
122 #if defined(HAVE_EVENTFD)
123 StgWord64 n = (StgWord64)IO_MANAGER_WAKEUP;
124 r = write(io_manager_wakeup_fd, (char *) &n, 8);
126 StgWord8 byte = (StgWord8)IO_MANAGER_WAKEUP;
127 r = write(io_manager_wakeup_fd, &byte, 1);
129 if (r == -1) { sysErrorBelch("ioManagerWakeup: write"); }
133 #if defined(THREADED_RTS)
138 // Ask the IO Manager thread to exit
139 if (io_manager_control_fd >= 0) {
140 StgWord8 byte = (StgWord8)IO_MANAGER_DIE;
141 r = write(io_manager_control_fd, &byte, 1);
142 if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
143 io_manager_control_fd = -1;
144 io_manager_wakeup_fd = -1;
149 ioManagerStartCap (Capability *cap)
152 cap,&base_GHCziConcziIO_ensureIOManagerIsRunning_closure,NULL);
156 ioManagerStart (void)
158 // Make sure the IO manager thread is running
160 if (io_manager_control_fd < 0 || io_manager_wakeup_fd < 0) {
162 cap = ioManagerStartCap(cap);
168 #if !defined(THREADED_RTS)
170 #define N_PENDING_HANDLERS 16
172 siginfo_t pending_handler_buf[N_PENDING_HANDLERS];
173 siginfo_t *next_pending_handler = pending_handler_buf;
175 #endif /* THREADED_RTS */
177 /* -----------------------------------------------------------------------------
178 * Low-level signal handler
180 * Places the requested handler on a stack of pending handlers to be
181 * started up at the next context switch.
182 * -------------------------------------------------------------------------- */
185 generic_handler(int sig USED_IF_THREADS,
189 #if defined(THREADED_RTS)
191 if (io_manager_control_fd != -1)
193 StgWord8 buf[sizeof(siginfo_t) + 1];
199 // info may be NULL on Solaris (see #3790)
200 memset(buf+1, 0, sizeof(siginfo_t));
202 memcpy(buf+1, info, sizeof(siginfo_t));
205 r = write(io_manager_control_fd, buf, sizeof(siginfo_t)+1);
206 if (r == -1 && errno == EAGAIN)
208 errorBelch("lost signal due to full pipe: %d\n", sig);
211 // If the IO manager hasn't told us what the FD of the write end
212 // of its pipe is, there's not much we can do here, so just ignore
215 #else /* not THREADED_RTS */
217 /* Can't call allocate from here. Probably can't call malloc
218 either. However, we have to schedule a new thread somehow.
220 It's probably ok to request a context switch and allow the
221 scheduler to start the handler thread, but how do we
222 communicate this to the scheduler?
224 We need some kind of locking, but with low overhead (i.e. no
225 blocking signals every time around the scheduler).
227 Signal Handlers are atomic (i.e. they can't be interrupted), and
228 we can make use of this. We just need to make sure the
229 critical section of the scheduler can't be interrupted - the
230 only way to do this is to block signals. However, we can lower
231 the overhead by only blocking signals when there are any
232 handlers to run, i.e. the set of pending handlers is
236 /* We use a stack to store the pending signals. We can't
237 dynamically grow this since we can't allocate any memory from
238 within a signal handler.
240 Hence unfortunately we have to bomb out if the buffer
241 overflows. It might be acceptable to carry on in certain
242 circumstances, depending on the signal.
245 memcpy(next_pending_handler, info, sizeof(siginfo_t));
247 next_pending_handler++;
250 if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
251 errorBelch("too many pending signals");
252 stg_exit(EXIT_FAILURE);
255 contextSwitchCapability(&MainCapability);
257 #endif /* THREADED_RTS */
260 /* -----------------------------------------------------------------------------
261 * Blocking/Unblocking of the user signals
262 * -------------------------------------------------------------------------- */
264 static sigset_t userSignals;
265 static sigset_t savedSignals;
268 initUserSignals(void)
270 sigemptyset(&userSignals);
272 getStablePtr((StgPtr)&base_GHCziConcziSignal_runHandlers_closure);
273 // needed to keep runHandler alive
278 blockUserSignals(void)
280 sigprocmask(SIG_BLOCK, &userSignals, &savedSignals);
284 unblockUserSignals(void)
286 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
290 anyUserHandlers(void)
292 return n_haskell_handlers != 0;
295 #if !defined(THREADED_RTS)
297 awaitUserSignals(void)
299 while (!signals_pending() && sched_state == SCHED_RUNNING) {
305 /* -----------------------------------------------------------------------------
306 * Install a Haskell signal handler.
308 * We should really do this in Haskell in GHC.Conc, and share the
309 * signal_handlers array with the one there.
311 * -------------------------------------------------------------------------- */
314 stg_sig_install(int sig, int spi, void *mask)
316 sigset_t signals, osignals;
317 struct sigaction action;
320 // Block the signal until we figure out what to do
321 // Count on this to fail if the signal number is invalid
322 if (sig < 0 || sigemptyset(&signals) ||
323 sigaddset(&signals, sig) || sigprocmask(SIG_BLOCK, &signals, &osignals)) {
329 previous_spi = signal_handlers[sig];
335 action.sa_handler = SIG_IGN;
339 action.sa_handler = SIG_DFL;
343 action.sa_flags |= SA_RESETHAND;
346 action.sa_sigaction = generic_handler;
347 action.sa_flags |= SA_SIGINFO;
351 barf("stg_sig_install: bad spi");
355 action.sa_mask = *(sigset_t *)mask;
357 sigemptyset(&action.sa_mask);
359 action.sa_flags |= sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
361 if (sigaction(sig, &action, NULL))
363 errorBelch("sigaction");
367 signal_handlers[sig] = spi;
372 sigaddset(&userSignals, sig);
373 if (previous_spi != STG_SIG_HAN && previous_spi != STG_SIG_RST) {
374 n_haskell_handlers++;
379 sigdelset(&userSignals, sig);
380 if (previous_spi == STG_SIG_HAN || previous_spi == STG_SIG_RST) {
381 n_haskell_handlers--;
386 if (sigprocmask(SIG_SETMASK, &osignals, NULL))
388 errorBelch("sigprocmask");
395 /* -----------------------------------------------------------------------------
396 * Creating new threads for signal handlers.
397 * -------------------------------------------------------------------------- */
399 #if !defined(THREADED_RTS)
401 startSignalHandlers(Capability *cap)
408 while (next_pending_handler != pending_handler_buf) {
410 next_pending_handler--;
412 sig = next_pending_handler->si_signo;
413 if (signal_handlers[sig] == STG_SIG_DFL) {
414 continue; // handler has been changed.
417 info = stgMallocBytes(sizeof(siginfo_t), "startSignalHandlers");
418 // freed by runHandler
419 memcpy(info, next_pending_handler, sizeof(siginfo_t));
423 RtsFlags.GcFlags.initialStkSize,
426 &base_GHCziConcziSignal_runHandlers_closure,
427 rts_mkPtr(cap, info)),
428 rts_mkInt(cap, info->si_signo))));
431 unblockUserSignals();
435 /* ----------------------------------------------------------------------------
436 * Mark signal handlers during GC.
437 * -------------------------------------------------------------------------- */
440 markSignalHandlers (evac_fn evac STG_UNUSED, void *user STG_UNUSED)
445 #else /* !RTS_USER_SIGNALS */
447 stg_sig_install(StgInt sig STG_UNUSED,
448 StgInt spi STG_UNUSED,
449 void* mask STG_UNUSED)
451 //barf("User signals not supported");
457 #if defined(RTS_USER_SIGNALS)
458 /* -----------------------------------------------------------------------------
461 * We like to shutdown nicely after receiving a SIGINT, write out the
462 * stats, write profiling info, close open files and flush buffers etc.
463 * -------------------------------------------------------------------------- */
465 shutdown_handler(int sig STG_UNUSED)
467 // If we're already trying to interrupt the RTS, terminate with
468 // extreme prejudice. So the first ^C tries to exit the program
469 // cleanly, and the second one just kills it.
470 if (sched_state >= SCHED_INTERRUPTING) {
471 stg_exit(EXIT_INTERRUPTED);
477 /* -----------------------------------------------------------------------------
478 * An empty signal handler, currently used for SIGPIPE
479 * -------------------------------------------------------------------------- */
481 empty_handler (int sig STG_UNUSED)
486 /* -----------------------------------------------------------------------------
489 When a process is suspeended with ^Z and resumed again, the shell
490 makes no attempt to save and restore the terminal settings. So on
491 resume, any terminal setting modificaions we made (e.g. turning off
492 ICANON due to hSetBuffering NoBuffering) may well be lost. Hence,
493 we arrange to save and restore the terminal settings ourselves.
497 - in the handler, kill(getpid(),SIGTSTP)
498 - when this returns, restore the TTY settings
499 This means we don't have to catch SIGCONT too.
501 -------------------------------------------------------------------------- */
503 static void sigtstp_handler(int sig);
504 static void set_sigtstp_action (rtsBool handle);
507 sigtstp_handler (int sig)
510 struct termios ts[3];
512 // save the current TTY state for TTYs we modified
513 for (fd = 0; fd <= 2; fd++) {
514 if (__hscore_get_saved_termios(fd) != NULL) {
515 tcgetattr(fd,&ts[fd]);
519 // de-install the SIGTSTP handler
520 set_sigtstp_action(rtsFalse);
522 // really stop the process now
526 sigaddset(&mask, sig);
527 sigprocmask(SIG_UNBLOCK, &mask, NULL);
531 // on return, restore the TTY state
532 for (fd = 0; fd <= 2; fd++) {
533 if (__hscore_get_saved_termios(fd) != NULL) {
534 tcsetattr(0,TCSANOW,&ts[fd]);
538 set_sigtstp_action(rtsTrue);
542 set_sigtstp_action (rtsBool handle)
546 sa.sa_handler = sigtstp_handler;
548 sa.sa_handler = SIG_DFL;
551 sigemptyset(&sa.sa_mask);
552 sigaction(SIGTSTP, &sa, NULL);
555 /* -----------------------------------------------------------------------------
556 * Install default signal handlers.
558 * The RTS installs a default signal handler for catching
559 * SIGINT, so that we can perform an orderly shutdown.
561 * Haskell code may install their own SIGINT handler, which is
562 * fine, provided they're so kind as to put back the old one
563 * when they de-install.
565 * In addition to handling SIGINT, the RTS also handles SIGFPE
566 * by ignoring it. Apparently IEEE requires floating-point
567 * exceptions to be ignored by default, but alpha-dec-osf3
568 * doesn't seem to do so.
569 * -------------------------------------------------------------------------- */
571 initDefaultHandlers(void)
573 struct sigaction action,oact;
575 // install the SIGINT handler
576 action.sa_handler = shutdown_handler;
577 sigemptyset(&action.sa_mask);
579 if (sigaction(SIGINT, &action, &oact) != 0) {
580 sysErrorBelch("warning: failed to install SIGINT handler");
583 #if defined(HAVE_SIGINTERRUPT)
584 siginterrupt(SIGINT, 1); // isn't this the default? --SDM
587 // install the SIGFPE handler
589 // In addition to handling SIGINT, also handle SIGFPE by ignoring it.
590 // Apparently IEEE requires floating-point exceptions to be ignored by
591 // default, but alpha-dec-osf3 doesn't seem to do so.
593 // Commented out by SDM 2/7/2002: this causes an infinite loop on
594 // some architectures when an integer division by zero occurs: we
595 // don't recover from the floating point exception, and the
596 // program just generates another one immediately.
598 action.sa_handler = SIG_IGN;
599 sigemptyset(&action.sa_mask);
601 if (sigaction(SIGFPE, &action, &oact) != 0) {
602 sysErrorBelch("warning: failed to install SIGFPE handler");
606 #ifdef alpha_HOST_ARCH
607 ieee_set_fp_control(0);
610 // ignore SIGPIPE; see #1619
611 // actually, we use an empty signal handler rather than SIG_IGN,
612 // so that SIGPIPE gets reset to its default behaviour on exec.
613 action.sa_handler = empty_handler;
614 sigemptyset(&action.sa_mask);
616 if (sigaction(SIGPIPE, &action, &oact) != 0) {
617 sysErrorBelch("warning: failed to install SIGPIPE handler");
620 set_sigtstp_action(rtsTrue);
624 resetDefaultHandlers(void)
626 struct sigaction action;
628 action.sa_handler = SIG_DFL;
629 sigemptyset(&action.sa_mask);
633 if (sigaction(SIGINT, &action, NULL) != 0) {
634 sysErrorBelch("warning: failed to uninstall SIGINT handler");
637 if (sigaction(SIGPIPE, &action, NULL) != 0) {
638 sysErrorBelch("warning: failed to uninstall SIGPIPE handler");
641 set_sigtstp_action(rtsFalse);
645 freeSignalHandlers(void) {
646 if (signal_handlers != NULL) {
647 stgFree(signal_handlers);
651 #endif /* RTS_USER_SIGNALS */