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>
42 /* This curious flag is provided for the benefit of the Haskell binding
43 * to POSIX.1 to control whether or not to include SA_NOCLDSTOP when
44 * installing a SIGCHLD handler.
48 /* -----------------------------------------------------------------------------
49 * The table of signal handlers
50 * -------------------------------------------------------------------------- */
52 #if defined(RTS_USER_SIGNALS)
54 /* SUP: The type of handlers is a little bit, well, doubtful... */
55 StgInt *signal_handlers = NULL; /* Dynamically grown array of signal handlers */
56 static StgInt nHandlers = 0; /* Size of handlers array */
58 static nat n_haskell_handlers = 0;
60 /* -----------------------------------------------------------------------------
61 * Allocate/resize the table of signal handlers.
62 * -------------------------------------------------------------------------- */
65 more_handlers(int sig)
72 if (signal_handlers == NULL)
73 signal_handlers = (StgInt *)stgMallocBytes((sig + 1) * sizeof(StgInt), "more_handlers");
75 signal_handlers = (StgInt *)stgReallocBytes(signal_handlers, (sig + 1) * sizeof(StgInt), "more_handlers");
77 for(i = nHandlers; i <= sig; i++)
78 // Fill in the new slots with default actions
79 signal_handlers[i] = STG_SIG_DFL;
84 // Here's the pipe into which we will send our signals
85 static int io_manager_pipe = -1;
87 #define IO_MANAGER_WAKEUP 0xff
88 #define IO_MANAGER_DIE 0xfe
91 setIOManagerPipe (int fd)
93 // only called when THREADED_RTS, but unconditionally
94 // compiled here because GHC.Conc depends on it.
95 if (io_manager_pipe < 0) {
100 #if defined(THREADED_RTS)
102 ioManagerWakeup (void)
105 // Wake up the IO Manager thread by sending a byte down its pipe
106 if (io_manager_pipe >= 0) {
107 StgWord8 byte = (StgWord8)IO_MANAGER_WAKEUP;
108 r = write(io_manager_pipe, &byte, 1);
109 if (r == -1) { sysErrorBelch("ioManagerWakeup: write"); }
117 // Ask the IO Manager thread to exit
118 if (io_manager_pipe >= 0) {
119 StgWord8 byte = (StgWord8)IO_MANAGER_DIE;
120 r = write(io_manager_pipe, &byte, 1);
121 if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
122 close(io_manager_pipe);
123 io_manager_pipe = -1;
128 ioManagerStartCap (Capability *cap)
130 return rts_evalIO(cap,&base_GHCziConc_ensureIOManagerIsRunning_closure,NULL);
134 ioManagerStart (void)
136 // Make sure the IO manager thread is running
138 if (io_manager_pipe < 0) {
140 cap = ioManagerStartCap(cap);
146 #if !defined(THREADED_RTS)
148 #define N_PENDING_HANDLERS 16
150 siginfo_t pending_handler_buf[N_PENDING_HANDLERS];
151 siginfo_t *next_pending_handler = pending_handler_buf;
153 #endif /* THREADED_RTS */
155 /* -----------------------------------------------------------------------------
156 * Low-level signal handler
158 * Places the requested handler on a stack of pending handlers to be
159 * started up at the next context switch.
160 * -------------------------------------------------------------------------- */
163 generic_handler(int sig USED_IF_THREADS,
167 #if defined(THREADED_RTS)
169 if (io_manager_pipe != -1)
171 StgWord8 buf[sizeof(siginfo_t) + 1];
175 memcpy(buf+1, info, sizeof(siginfo_t));
176 r = write(io_manager_pipe, buf, sizeof(siginfo_t)+1);
177 if (r == -1 && errno == EAGAIN)
179 errorBelch("lost signal due to full pipe: %d\n", sig);
182 // If the IO manager hasn't told us what the FD of the write end
183 // of its pipe is, there's not much we can do here, so just ignore
186 #else /* not THREADED_RTS */
188 /* Can't call allocate from here. Probably can't call malloc
189 either. However, we have to schedule a new thread somehow.
191 It's probably ok to request a context switch and allow the
192 scheduler to start the handler thread, but how do we
193 communicate this to the scheduler?
195 We need some kind of locking, but with low overhead (i.e. no
196 blocking signals every time around the scheduler).
198 Signal Handlers are atomic (i.e. they can't be interrupted), and
199 we can make use of this. We just need to make sure the
200 critical section of the scheduler can't be interrupted - the
201 only way to do this is to block signals. However, we can lower
202 the overhead by only blocking signals when there are any
203 handlers to run, i.e. the set of pending handlers is
207 /* We use a stack to store the pending signals. We can't
208 dynamically grow this since we can't allocate any memory from
209 within a signal handler.
211 Hence unfortunately we have to bomb out if the buffer
212 overflows. It might be acceptable to carry on in certain
213 circumstances, depending on the signal.
216 memcpy(next_pending_handler, info, sizeof(siginfo_t));
218 next_pending_handler++;
221 if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
222 errorBelch("too many pending signals");
223 stg_exit(EXIT_FAILURE);
226 contextSwitchCapability(&MainCapability);
228 #endif /* THREADED_RTS */
231 /* -----------------------------------------------------------------------------
232 * Blocking/Unblocking of the user signals
233 * -------------------------------------------------------------------------- */
235 static sigset_t userSignals;
236 static sigset_t savedSignals;
239 initUserSignals(void)
241 sigemptyset(&userSignals);
243 getStablePtr((StgPtr)&base_GHCziConc_runHandlers_closure);
244 // needed to keep runHandler alive
249 blockUserSignals(void)
251 sigprocmask(SIG_BLOCK, &userSignals, &savedSignals);
255 unblockUserSignals(void)
257 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
261 anyUserHandlers(void)
263 return n_haskell_handlers != 0;
266 #if !defined(THREADED_RTS)
268 awaitUserSignals(void)
270 while (!signals_pending() && sched_state == SCHED_RUNNING) {
276 /* -----------------------------------------------------------------------------
277 * Install a Haskell signal handler.
279 * We should really do this in Haskell in GHC.Conc, and share the
280 * signal_handlers array with the one there.
282 * -------------------------------------------------------------------------- */
285 stg_sig_install(int sig, int spi, void *mask)
287 sigset_t signals, osignals;
288 struct sigaction action;
291 // Block the signal until we figure out what to do
292 // Count on this to fail if the signal number is invalid
293 if (sig < 0 || sigemptyset(&signals) ||
294 sigaddset(&signals, sig) || sigprocmask(SIG_BLOCK, &signals, &osignals)) {
300 previous_spi = signal_handlers[sig];
306 action.sa_handler = SIG_IGN;
310 action.sa_handler = SIG_DFL;
314 action.sa_flags |= SA_RESETHAND;
317 action.sa_sigaction = generic_handler;
318 action.sa_flags |= SA_SIGINFO;
322 barf("stg_sig_install: bad spi");
326 action.sa_mask = *(sigset_t *)mask;
328 sigemptyset(&action.sa_mask);
330 action.sa_flags |= sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
332 if (sigaction(sig, &action, NULL))
334 errorBelch("sigaction");
338 signal_handlers[sig] = spi;
343 sigaddset(&userSignals, sig);
344 if (previous_spi != STG_SIG_HAN && previous_spi != STG_SIG_RST) {
345 n_haskell_handlers++;
350 sigdelset(&userSignals, sig);
351 if (previous_spi == STG_SIG_HAN || previous_spi == STG_SIG_RST) {
352 n_haskell_handlers--;
357 if (sigprocmask(SIG_SETMASK, &osignals, NULL))
359 errorBelch("sigprocmask");
366 /* -----------------------------------------------------------------------------
367 * Creating new threads for signal handlers.
368 * -------------------------------------------------------------------------- */
370 #if !defined(THREADED_RTS)
372 startSignalHandlers(Capability *cap)
379 while (next_pending_handler != pending_handler_buf) {
381 next_pending_handler--;
383 sig = next_pending_handler->si_signo;
384 if (signal_handlers[sig] == STG_SIG_DFL) {
385 continue; // handler has been changed.
388 info = stgMallocBytes(sizeof(siginfo_t), "startSignalHandlers");
389 // freed by runHandler
390 memcpy(info, next_pending_handler, sizeof(siginfo_t));
394 RtsFlags.GcFlags.initialStkSize,
397 &base_GHCziConc_runHandlers_closure,
398 rts_mkPtr(cap, info)),
399 rts_mkInt(cap, info->si_signo))));
402 unblockUserSignals();
406 /* ----------------------------------------------------------------------------
407 * Mark signal handlers during GC.
408 * -------------------------------------------------------------------------- */
411 markSignalHandlers (evac_fn evac STG_UNUSED, void *user STG_UNUSED)
416 #else /* !RTS_USER_SIGNALS */
418 stg_sig_install(StgInt sig STG_UNUSED,
419 StgInt spi STG_UNUSED,
420 void* mask STG_UNUSED)
422 //barf("User signals not supported");
428 #if defined(RTS_USER_SIGNALS)
429 /* -----------------------------------------------------------------------------
432 * We like to shutdown nicely after receiving a SIGINT, write out the
433 * stats, write profiling info, close open files and flush buffers etc.
434 * -------------------------------------------------------------------------- */
436 shutdown_handler(int sig STG_UNUSED)
438 // If we're already trying to interrupt the RTS, terminate with
439 // extreme prejudice. So the first ^C tries to exit the program
440 // cleanly, and the second one just kills it.
441 if (sched_state >= SCHED_INTERRUPTING) {
442 stg_exit(EXIT_INTERRUPTED);
448 /* -----------------------------------------------------------------------------
449 * Install default signal handlers.
451 * The RTS installs a default signal handler for catching
452 * SIGINT, so that we can perform an orderly shutdown.
454 * Haskell code may install their own SIGINT handler, which is
455 * fine, provided they're so kind as to put back the old one
456 * when they de-install.
458 * In addition to handling SIGINT, the RTS also handles SIGFPE
459 * by ignoring it. Apparently IEEE requires floating-point
460 * exceptions to be ignored by default, but alpha-dec-osf3
461 * doesn't seem to do so.
462 * -------------------------------------------------------------------------- */
464 initDefaultHandlers(void)
466 struct sigaction action,oact;
468 // install the SIGINT handler
469 action.sa_handler = shutdown_handler;
470 sigemptyset(&action.sa_mask);
472 if (sigaction(SIGINT, &action, &oact) != 0) {
473 sysErrorBelch("warning: failed to install SIGINT handler");
476 #if defined(HAVE_SIGINTERRUPT)
477 siginterrupt(SIGINT, 1); // isn't this the default? --SDM
480 // install the SIGFPE handler
482 // In addition to handling SIGINT, also handle SIGFPE by ignoring it.
483 // Apparently IEEE requires floating-point exceptions to be ignored by
484 // default, but alpha-dec-osf3 doesn't seem to do so.
486 // Commented out by SDM 2/7/2002: this causes an infinite loop on
487 // some architectures when an integer division by zero occurs: we
488 // don't recover from the floating point exception, and the
489 // program just generates another one immediately.
491 action.sa_handler = SIG_IGN;
492 sigemptyset(&action.sa_mask);
494 if (sigaction(SIGFPE, &action, &oact) != 0) {
495 sysErrorBelch("warning: failed to install SIGFPE handler");
499 #ifdef alpha_HOST_ARCH
500 ieee_set_fp_control(0);
503 // ignore SIGPIPE; see #1619
504 action.sa_handler = SIG_IGN;
505 sigemptyset(&action.sa_mask);
507 if (sigaction(SIGPIPE, &action, &oact) != 0) {
508 sysErrorBelch("warning: failed to install SIGPIPE handler");
513 resetDefaultHandlers(void)
515 struct sigaction action;
517 action.sa_handler = SIG_DFL;
518 sigemptyset(&action.sa_mask);
522 if (sigaction(SIGINT, &action, NULL) != 0) {
523 sysErrorBelch("warning: failed to uninstall SIGINT handler");
526 if (sigaction(SIGPIPE, &action, NULL) != 0) {
527 sysErrorBelch("warning: failed to uninstall SIGPIPE handler");
532 freeSignalHandlers(void) {
533 if (signal_handlers != NULL) {
534 stgFree(signal_handlers);
538 #endif /* RTS_USER_SIGNALS */