1 /* -----------------------------------------------------------------------------
3 * (c) The GHC Team, 1998-2005
5 * Signal processing / handling.
7 * ---------------------------------------------------------------------------*/
9 /* This is non-Posix-compliant.
10 #include "PosixSource.h"
15 #include "RtsSignals.h"
16 #include "posix/Signals.h"
20 #include "ThrIOManager.h"
22 #ifdef alpha_HOST_ARCH
23 # if defined(linux_HOST_OS)
26 # include <machine/fpu.h>
45 /* This curious flag is provided for the benefit of the Haskell binding
46 * to POSIX.1 to control whether or not to include SA_NOCLDSTOP when
47 * installing a SIGCHLD handler.
51 /* -----------------------------------------------------------------------------
52 * The table of signal handlers
53 * -------------------------------------------------------------------------- */
55 #if defined(RTS_USER_SIGNALS)
57 /* SUP: The type of handlers is a little bit, well, doubtful... */
58 StgInt *signal_handlers = NULL; /* Dynamically grown array of signal handlers */
59 static StgInt nHandlers = 0; /* Size of handlers array */
61 static nat n_haskell_handlers = 0;
63 /* -----------------------------------------------------------------------------
64 * Allocate/resize the table of signal handlers.
65 * -------------------------------------------------------------------------- */
68 more_handlers(int sig)
75 if (signal_handlers == NULL)
76 signal_handlers = (StgInt *)stgMallocBytes((sig + 1) * sizeof(StgInt), "more_handlers");
78 signal_handlers = (StgInt *)stgReallocBytes(signal_handlers, (sig + 1) * sizeof(StgInt), "more_handlers");
80 for(i = nHandlers; i <= sig; i++)
81 // Fill in the new slots with default actions
82 signal_handlers[i] = STG_SIG_DFL;
87 // Here's the pipe into which we will send our signals
88 static int io_manager_pipe = -1;
90 #define IO_MANAGER_WAKEUP 0xff
91 #define IO_MANAGER_DIE 0xfe
94 setIOManagerPipe (int fd)
96 // only called when THREADED_RTS, but unconditionally
97 // compiled here because GHC.Conc depends on it.
101 #if defined(THREADED_RTS)
103 ioManagerWakeup (void)
106 // Wake up the IO Manager thread by sending a byte down its pipe
107 if (io_manager_pipe >= 0) {
108 StgWord8 byte = (StgWord8)IO_MANAGER_WAKEUP;
109 r = write(io_manager_pipe, &byte, 1);
110 if (r == -1) { sysErrorBelch("ioManagerWakeup: write"); }
118 // Ask the IO Manager thread to exit
119 if (io_manager_pipe >= 0) {
120 StgWord8 byte = (StgWord8)IO_MANAGER_DIE;
121 r = write(io_manager_pipe, &byte, 1);
122 if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
123 close(io_manager_pipe);
124 io_manager_pipe = -1;
129 ioManagerStart (void)
131 // Make sure the IO manager thread is running
133 if (io_manager_pipe < 0) {
135 cap = rts_evalIO(cap,&base_GHCziConc_ensureIOManagerIsRunning_closure,NULL);
141 #if !defined(THREADED_RTS)
143 #define N_PENDING_HANDLERS 16
145 siginfo_t pending_handler_buf[N_PENDING_HANDLERS];
146 siginfo_t *next_pending_handler = pending_handler_buf;
148 #endif /* THREADED_RTS */
150 /* -----------------------------------------------------------------------------
151 * Low-level signal handler
153 * Places the requested handler on a stack of pending handlers to be
154 * started up at the next context switch.
155 * -------------------------------------------------------------------------- */
158 generic_handler(int sig USED_IF_THREADS,
162 #if defined(THREADED_RTS)
164 if (io_manager_pipe != -1)
166 StgWord8 buf[sizeof(siginfo_t) + 1];
170 memcpy(buf+1, info, sizeof(siginfo_t));
171 r = write(io_manager_pipe, buf, sizeof(siginfo_t)+1);
172 if (r == -1 && errno == EAGAIN)
174 errorBelch("lost signal due to full pipe: %d\n", sig);
177 // If the IO manager hasn't told us what the FD of the write end
178 // of its pipe is, there's not much we can do here, so just ignore
181 #else /* not THREADED_RTS */
183 /* Can't call allocate from here. Probably can't call malloc
184 either. However, we have to schedule a new thread somehow.
186 It's probably ok to request a context switch and allow the
187 scheduler to start the handler thread, but how do we
188 communicate this to the scheduler?
190 We need some kind of locking, but with low overhead (i.e. no
191 blocking signals every time around the scheduler).
193 Signal Handlers are atomic (i.e. they can't be interrupted), and
194 we can make use of this. We just need to make sure the
195 critical section of the scheduler can't be interrupted - the
196 only way to do this is to block signals. However, we can lower
197 the overhead by only blocking signals when there are any
198 handlers to run, i.e. the set of pending handlers is
202 /* We use a stack to store the pending signals. We can't
203 dynamically grow this since we can't allocate any memory from
204 within a signal handler.
206 Hence unfortunately we have to bomb out if the buffer
207 overflows. It might be acceptable to carry on in certain
208 circumstances, depending on the signal.
211 memcpy(next_pending_handler, info, sizeof(siginfo_t));
213 next_pending_handler++;
216 if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
217 errorBelch("too many pending signals");
218 stg_exit(EXIT_FAILURE);
221 contextSwitchCapability(&MainCapability);
223 #endif /* THREADED_RTS */
226 /* -----------------------------------------------------------------------------
227 * Blocking/Unblocking of the user signals
228 * -------------------------------------------------------------------------- */
230 static sigset_t userSignals;
231 static sigset_t savedSignals;
234 initUserSignals(void)
236 sigemptyset(&userSignals);
238 getStablePtr((StgPtr)&base_GHCziConc_runHandlers_closure);
239 // needed to keep runHandler alive
244 blockUserSignals(void)
246 sigprocmask(SIG_BLOCK, &userSignals, &savedSignals);
250 unblockUserSignals(void)
252 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
256 anyUserHandlers(void)
258 return n_haskell_handlers != 0;
261 #if !defined(THREADED_RTS)
263 awaitUserSignals(void)
265 while (!signals_pending() && sched_state == SCHED_RUNNING) {
271 /* -----------------------------------------------------------------------------
272 * Install a Haskell signal handler.
274 * We should really do this in Haskell in GHC.Conc, and share the
275 * signal_handlers array with the one there.
277 * -------------------------------------------------------------------------- */
280 stg_sig_install(int sig, int spi, void *mask)
282 sigset_t signals, osignals;
283 struct sigaction action;
286 // Block the signal until we figure out what to do
287 // Count on this to fail if the signal number is invalid
288 if (sig < 0 || sigemptyset(&signals) ||
289 sigaddset(&signals, sig) || sigprocmask(SIG_BLOCK, &signals, &osignals)) {
295 previous_spi = signal_handlers[sig];
301 action.sa_handler = SIG_IGN;
305 action.sa_handler = SIG_DFL;
309 action.sa_flags |= SA_RESETHAND;
312 action.sa_sigaction = generic_handler;
313 action.sa_flags |= SA_SIGINFO;
317 barf("stg_sig_install: bad spi");
321 action.sa_mask = *(sigset_t *)mask;
323 sigemptyset(&action.sa_mask);
325 action.sa_flags |= sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
327 if (sigaction(sig, &action, NULL))
329 errorBelch("sigaction");
333 signal_handlers[sig] = spi;
338 sigaddset(&userSignals, sig);
339 if (previous_spi != STG_SIG_HAN && previous_spi != STG_SIG_RST) {
340 n_haskell_handlers++;
345 sigdelset(&userSignals, sig);
346 if (previous_spi == STG_SIG_HAN || previous_spi == STG_SIG_RST) {
347 n_haskell_handlers--;
352 if (sigprocmask(SIG_SETMASK, &osignals, NULL))
354 errorBelch("sigprocmask");
361 /* -----------------------------------------------------------------------------
362 * Creating new threads for signal handlers.
363 * -------------------------------------------------------------------------- */
365 #if !defined(THREADED_RTS)
367 startSignalHandlers(Capability *cap)
374 while (next_pending_handler != pending_handler_buf) {
376 next_pending_handler--;
378 sig = next_pending_handler->si_signo;
379 if (signal_handlers[sig] == STG_SIG_DFL) {
380 continue; // handler has been changed.
383 info = stgMallocBytes(sizeof(siginfo_t), "startSignalHandlers");
384 // freed by runHandler
385 memcpy(info, next_pending_handler, sizeof(siginfo_t));
389 RtsFlags.GcFlags.initialStkSize,
392 &base_GHCziConc_runHandlers_closure,
393 rts_mkPtr(cap, info)),
394 rts_mkInt(cap, info->si_signo))));
397 unblockUserSignals();
401 /* ----------------------------------------------------------------------------
402 * Mark signal handlers during GC.
403 * -------------------------------------------------------------------------- */
406 markSignalHandlers (evac_fn evac STG_UNUSED, void *user STG_UNUSED)
411 #else /* !RTS_USER_SIGNALS */
413 stg_sig_install(StgInt sig STG_UNUSED,
414 StgInt spi STG_UNUSED,
415 void* mask STG_UNUSED)
417 //barf("User signals not supported");
423 #if defined(RTS_USER_SIGNALS)
424 /* -----------------------------------------------------------------------------
427 * We like to shutdown nicely after receiving a SIGINT, write out the
428 * stats, write profiling info, close open files and flush buffers etc.
429 * -------------------------------------------------------------------------- */
431 shutdown_handler(int sig STG_UNUSED)
433 // If we're already trying to interrupt the RTS, terminate with
434 // extreme prejudice. So the first ^C tries to exit the program
435 // cleanly, and the second one just kills it.
436 if (sched_state >= SCHED_INTERRUPTING) {
437 stg_exit(EXIT_INTERRUPTED);
443 /* -----------------------------------------------------------------------------
444 * Install default signal handlers.
446 * The RTS installs a default signal handler for catching
447 * SIGINT, so that we can perform an orderly shutdown.
449 * Haskell code may install their own SIGINT handler, which is
450 * fine, provided they're so kind as to put back the old one
451 * when they de-install.
453 * In addition to handling SIGINT, the RTS also handles SIGFPE
454 * by ignoring it. Apparently IEEE requires floating-point
455 * exceptions to be ignored by default, but alpha-dec-osf3
456 * doesn't seem to do so.
457 * -------------------------------------------------------------------------- */
459 initDefaultHandlers(void)
461 struct sigaction action,oact;
463 // install the SIGINT handler
464 action.sa_handler = shutdown_handler;
465 sigemptyset(&action.sa_mask);
467 if (sigaction(SIGINT, &action, &oact) != 0) {
468 sysErrorBelch("warning: failed to install SIGINT handler");
471 #if defined(HAVE_SIGINTERRUPT)
472 siginterrupt(SIGINT, 1); // isn't this the default? --SDM
475 // install the SIGFPE handler
477 // In addition to handling SIGINT, also handle SIGFPE by ignoring it.
478 // Apparently IEEE requires floating-point exceptions to be ignored by
479 // default, but alpha-dec-osf3 doesn't seem to do so.
481 // Commented out by SDM 2/7/2002: this causes an infinite loop on
482 // some architectures when an integer division by zero occurs: we
483 // don't recover from the floating point exception, and the
484 // program just generates another one immediately.
486 action.sa_handler = SIG_IGN;
487 sigemptyset(&action.sa_mask);
489 if (sigaction(SIGFPE, &action, &oact) != 0) {
490 sysErrorBelch("warning: failed to install SIGFPE handler");
494 #ifdef alpha_HOST_ARCH
495 ieee_set_fp_control(0);
498 // ignore SIGPIPE; see #1619
499 action.sa_handler = SIG_IGN;
500 sigemptyset(&action.sa_mask);
502 if (sigaction(SIGPIPE, &action, &oact) != 0) {
503 sysErrorBelch("warning: failed to install SIGPIPE handler");
508 resetDefaultHandlers(void)
510 struct sigaction action;
512 action.sa_handler = SIG_DFL;
513 sigemptyset(&action.sa_mask);
517 if (sigaction(SIGINT, &action, NULL) != 0) {
518 sysErrorBelch("warning: failed to uninstall SIGINT handler");
521 if (sigaction(SIGPIPE, &action, NULL) != 0) {
522 sysErrorBelch("warning: failed to uninstall SIGPIPE handler");
527 freeSignalHandlers(void) {
528 if (signal_handlers != NULL) {
529 stgFree(signal_handlers);
533 #endif /* RTS_USER_SIGNALS */