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 ioManagerStart (void)
130 // Make sure the IO manager thread is running
132 if (io_manager_pipe < 0) {
134 cap = rts_evalIO(cap,&base_GHCziConc_ensureIOManagerIsRunning_closure,NULL);
140 #if !defined(THREADED_RTS)
142 #define N_PENDING_HANDLERS 16
144 siginfo_t pending_handler_buf[N_PENDING_HANDLERS];
145 siginfo_t *next_pending_handler = pending_handler_buf;
147 #endif /* THREADED_RTS */
149 /* -----------------------------------------------------------------------------
150 * Low-level signal handler
152 * Places the requested handler on a stack of pending handlers to be
153 * started up at the next context switch.
154 * -------------------------------------------------------------------------- */
157 generic_handler(int sig USED_IF_THREADS,
161 #if defined(THREADED_RTS)
163 if (io_manager_pipe != -1)
165 StgWord8 buf[sizeof(siginfo_t) + 1];
169 memcpy(buf+1, info, sizeof(siginfo_t));
170 r = write(io_manager_pipe, buf, sizeof(siginfo_t)+1);
171 if (r == -1 && errno == EAGAIN)
173 errorBelch("lost signal due to full pipe: %d\n", sig);
176 // If the IO manager hasn't told us what the FD of the write end
177 // of its pipe is, there's not much we can do here, so just ignore
180 #else /* not THREADED_RTS */
182 /* Can't call allocate from here. Probably can't call malloc
183 either. However, we have to schedule a new thread somehow.
185 It's probably ok to request a context switch and allow the
186 scheduler to start the handler thread, but how do we
187 communicate this to the scheduler?
189 We need some kind of locking, but with low overhead (i.e. no
190 blocking signals every time around the scheduler).
192 Signal Handlers are atomic (i.e. they can't be interrupted), and
193 we can make use of this. We just need to make sure the
194 critical section of the scheduler can't be interrupted - the
195 only way to do this is to block signals. However, we can lower
196 the overhead by only blocking signals when there are any
197 handlers to run, i.e. the set of pending handlers is
201 /* We use a stack to store the pending signals. We can't
202 dynamically grow this since we can't allocate any memory from
203 within a signal handler.
205 Hence unfortunately we have to bomb out if the buffer
206 overflows. It might be acceptable to carry on in certain
207 circumstances, depending on the signal.
210 memcpy(next_pending_handler, info, sizeof(siginfo_t));
212 next_pending_handler++;
215 if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
216 errorBelch("too many pending signals");
217 stg_exit(EXIT_FAILURE);
220 contextSwitchCapability(&MainCapability);
222 #endif /* THREADED_RTS */
225 /* -----------------------------------------------------------------------------
226 * Blocking/Unblocking of the user signals
227 * -------------------------------------------------------------------------- */
229 static sigset_t userSignals;
230 static sigset_t savedSignals;
233 initUserSignals(void)
235 sigemptyset(&userSignals);
237 getStablePtr((StgPtr)&base_GHCziConc_runHandlers_closure);
238 // needed to keep runHandler alive
243 blockUserSignals(void)
245 sigprocmask(SIG_BLOCK, &userSignals, &savedSignals);
249 unblockUserSignals(void)
251 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
255 anyUserHandlers(void)
257 return n_haskell_handlers != 0;
260 #if !defined(THREADED_RTS)
262 awaitUserSignals(void)
264 while (!signals_pending() && sched_state == SCHED_RUNNING) {
270 /* -----------------------------------------------------------------------------
271 * Install a Haskell signal handler.
273 * We should really do this in Haskell in GHC.Conc, and share the
274 * signal_handlers array with the one there.
276 * -------------------------------------------------------------------------- */
279 stg_sig_install(int sig, int spi, void *mask)
281 sigset_t signals, osignals;
282 struct sigaction action;
285 // Block the signal until we figure out what to do
286 // Count on this to fail if the signal number is invalid
287 if (sig < 0 || sigemptyset(&signals) ||
288 sigaddset(&signals, sig) || sigprocmask(SIG_BLOCK, &signals, &osignals)) {
294 previous_spi = signal_handlers[sig];
300 action.sa_handler = SIG_IGN;
304 action.sa_handler = SIG_DFL;
308 action.sa_flags |= SA_RESETHAND;
311 action.sa_sigaction = generic_handler;
312 action.sa_flags |= SA_SIGINFO;
316 barf("stg_sig_install: bad spi");
320 action.sa_mask = *(sigset_t *)mask;
322 sigemptyset(&action.sa_mask);
324 action.sa_flags |= sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
326 if (sigaction(sig, &action, NULL))
328 errorBelch("sigaction");
332 signal_handlers[sig] = spi;
337 sigaddset(&userSignals, sig);
338 if (previous_spi != STG_SIG_HAN && previous_spi != STG_SIG_RST) {
339 n_haskell_handlers++;
344 sigdelset(&userSignals, sig);
345 if (previous_spi == STG_SIG_HAN || previous_spi == STG_SIG_RST) {
346 n_haskell_handlers--;
351 if (sigprocmask(SIG_SETMASK, &osignals, NULL))
353 errorBelch("sigprocmask");
360 /* -----------------------------------------------------------------------------
361 * Creating new threads for signal handlers.
362 * -------------------------------------------------------------------------- */
364 #if !defined(THREADED_RTS)
366 startSignalHandlers(Capability *cap)
373 while (next_pending_handler != pending_handler_buf) {
375 next_pending_handler--;
377 sig = next_pending_handler->si_signo;
378 if (signal_handlers[sig] == STG_SIG_DFL) {
379 continue; // handler has been changed.
382 info = stgMallocBytes(sizeof(siginfo_t), "startSignalHandlers");
383 // freed by runHandler
384 memcpy(info, next_pending_handler, sizeof(siginfo_t));
388 RtsFlags.GcFlags.initialStkSize,
391 &base_GHCziConc_runHandlers_closure,
392 rts_mkPtr(cap, info)),
393 rts_mkInt(cap, info->si_signo))));
396 unblockUserSignals();
400 /* ----------------------------------------------------------------------------
401 * Mark signal handlers during GC.
402 * -------------------------------------------------------------------------- */
405 markSignalHandlers (evac_fn evac STG_UNUSED, void *user STG_UNUSED)
410 #else /* !RTS_USER_SIGNALS */
412 stg_sig_install(StgInt sig STG_UNUSED,
413 StgInt spi STG_UNUSED,
414 void* mask STG_UNUSED)
416 //barf("User signals not supported");
422 #if defined(RTS_USER_SIGNALS)
423 /* -----------------------------------------------------------------------------
426 * We like to shutdown nicely after receiving a SIGINT, write out the
427 * stats, write profiling info, close open files and flush buffers etc.
428 * -------------------------------------------------------------------------- */
430 shutdown_handler(int sig STG_UNUSED)
432 // If we're already trying to interrupt the RTS, terminate with
433 // extreme prejudice. So the first ^C tries to exit the program
434 // cleanly, and the second one just kills it.
435 if (sched_state >= SCHED_INTERRUPTING) {
436 stg_exit(EXIT_INTERRUPTED);
442 /* -----------------------------------------------------------------------------
443 * Install default signal handlers.
445 * The RTS installs a default signal handler for catching
446 * SIGINT, so that we can perform an orderly shutdown.
448 * Haskell code may install their own SIGINT handler, which is
449 * fine, provided they're so kind as to put back the old one
450 * when they de-install.
452 * In addition to handling SIGINT, the RTS also handles SIGFPE
453 * by ignoring it. Apparently IEEE requires floating-point
454 * exceptions to be ignored by default, but alpha-dec-osf3
455 * doesn't seem to do so.
456 * -------------------------------------------------------------------------- */
458 initDefaultHandlers(void)
460 struct sigaction action,oact;
462 // install the SIGINT handler
463 action.sa_handler = shutdown_handler;
464 sigemptyset(&action.sa_mask);
466 if (sigaction(SIGINT, &action, &oact) != 0) {
467 sysErrorBelch("warning: failed to install SIGINT handler");
470 #if defined(HAVE_SIGINTERRUPT)
471 siginterrupt(SIGINT, 1); // isn't this the default? --SDM
474 // install the SIGFPE handler
476 // In addition to handling SIGINT, also handle SIGFPE by ignoring it.
477 // Apparently IEEE requires floating-point exceptions to be ignored by
478 // default, but alpha-dec-osf3 doesn't seem to do so.
480 // Commented out by SDM 2/7/2002: this causes an infinite loop on
481 // some architectures when an integer division by zero occurs: we
482 // don't recover from the floating point exception, and the
483 // program just generates another one immediately.
485 action.sa_handler = SIG_IGN;
486 sigemptyset(&action.sa_mask);
488 if (sigaction(SIGFPE, &action, &oact) != 0) {
489 sysErrorBelch("warning: failed to install SIGFPE handler");
493 #ifdef alpha_HOST_ARCH
494 ieee_set_fp_control(0);
497 // ignore SIGPIPE; see #1619
498 action.sa_handler = SIG_IGN;
499 sigemptyset(&action.sa_mask);
501 if (sigaction(SIGPIPE, &action, &oact) != 0) {
502 sysErrorBelch("warning: failed to install SIGPIPE handler");
507 resetDefaultHandlers(void)
509 struct sigaction action;
511 action.sa_handler = SIG_DFL;
512 sigemptyset(&action.sa_mask);
516 if (sigaction(SIGINT, &action, NULL) != 0) {
517 sysErrorBelch("warning: failed to uninstall SIGINT handler");
520 if (sigaction(SIGPIPE, &action, NULL) != 0) {
521 sysErrorBelch("warning: failed to uninstall SIGPIPE handler");
526 freeSignalHandlers(void) {
527 if (signal_handlers != NULL) {
528 stgFree(signal_handlers);
532 #endif /* RTS_USER_SIGNALS */