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
89 #define IO_MANAGER_SYNC 0xfd
92 setIOManagerPipe (int fd)
94 // only called when THREADED_RTS, but unconditionally
95 // compiled here because GHC.Conc depends on it.
100 ioManagerWakeup (void)
103 // Wake up the IO Manager thread by sending a byte down its pipe
104 if (io_manager_pipe >= 0) {
105 StgWord8 byte = (StgWord8)IO_MANAGER_WAKEUP;
106 r = write(io_manager_pipe, &byte, 1);
107 if (r == -1) { sysErrorBelch("ioManagerWakeup: write"); }
115 // Wake up the IO Manager thread by sending a byte down its pipe
116 if (io_manager_pipe >= 0) {
117 StgWord8 byte = (StgWord8)IO_MANAGER_SYNC;
118 r = write(io_manager_pipe, &byte, 1);
119 if (r == -1) { sysErrorBelch("ioManagerSync: write"); }
123 #if defined(THREADED_RTS)
128 // Ask the IO Manager thread to exit
129 if (io_manager_pipe >= 0) {
130 StgWord8 byte = (StgWord8)IO_MANAGER_DIE;
131 r = write(io_manager_pipe, &byte, 1);
132 if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
133 close(io_manager_pipe);
134 io_manager_pipe = -1;
139 ioManagerStartCap (Capability *cap)
141 return rts_evalIO(cap,&base_GHCziConc_ensureIOManagerIsRunning_closure,NULL);
145 ioManagerStart (void)
147 // Make sure the IO manager thread is running
149 if (io_manager_pipe < 0) {
151 cap = ioManagerStartCap(cap);
157 #if !defined(THREADED_RTS)
159 #define N_PENDING_HANDLERS 16
161 siginfo_t pending_handler_buf[N_PENDING_HANDLERS];
162 siginfo_t *next_pending_handler = pending_handler_buf;
164 #endif /* THREADED_RTS */
166 /* -----------------------------------------------------------------------------
167 * Low-level signal handler
169 * Places the requested handler on a stack of pending handlers to be
170 * started up at the next context switch.
171 * -------------------------------------------------------------------------- */
174 generic_handler(int sig USED_IF_THREADS,
178 #if defined(THREADED_RTS)
180 if (io_manager_pipe != -1)
182 StgWord8 buf[sizeof(siginfo_t) + 1];
188 // info may be NULL on Solaris (see #3790)
189 memset(buf+1, 0, sizeof(siginfo_t));
191 memcpy(buf+1, info, sizeof(siginfo_t));
194 r = write(io_manager_pipe, buf, sizeof(siginfo_t)+1);
195 if (r == -1 && errno == EAGAIN)
197 errorBelch("lost signal due to full pipe: %d\n", sig);
200 // If the IO manager hasn't told us what the FD of the write end
201 // of its pipe is, there's not much we can do here, so just ignore
204 #else /* not THREADED_RTS */
206 /* Can't call allocate from here. Probably can't call malloc
207 either. However, we have to schedule a new thread somehow.
209 It's probably ok to request a context switch and allow the
210 scheduler to start the handler thread, but how do we
211 communicate this to the scheduler?
213 We need some kind of locking, but with low overhead (i.e. no
214 blocking signals every time around the scheduler).
216 Signal Handlers are atomic (i.e. they can't be interrupted), and
217 we can make use of this. We just need to make sure the
218 critical section of the scheduler can't be interrupted - the
219 only way to do this is to block signals. However, we can lower
220 the overhead by only blocking signals when there are any
221 handlers to run, i.e. the set of pending handlers is
225 /* We use a stack to store the pending signals. We can't
226 dynamically grow this since we can't allocate any memory from
227 within a signal handler.
229 Hence unfortunately we have to bomb out if the buffer
230 overflows. It might be acceptable to carry on in certain
231 circumstances, depending on the signal.
234 memcpy(next_pending_handler, info, sizeof(siginfo_t));
236 next_pending_handler++;
239 if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
240 errorBelch("too many pending signals");
241 stg_exit(EXIT_FAILURE);
244 contextSwitchCapability(&MainCapability);
246 #endif /* THREADED_RTS */
249 /* -----------------------------------------------------------------------------
250 * Blocking/Unblocking of the user signals
251 * -------------------------------------------------------------------------- */
253 static sigset_t userSignals;
254 static sigset_t savedSignals;
257 initUserSignals(void)
259 sigemptyset(&userSignals);
261 getStablePtr((StgPtr)&base_GHCziConc_runHandlers_closure);
262 // needed to keep runHandler alive
267 blockUserSignals(void)
269 sigprocmask(SIG_BLOCK, &userSignals, &savedSignals);
273 unblockUserSignals(void)
275 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
279 anyUserHandlers(void)
281 return n_haskell_handlers != 0;
284 #if !defined(THREADED_RTS)
286 awaitUserSignals(void)
288 while (!signals_pending() && sched_state == SCHED_RUNNING) {
294 /* -----------------------------------------------------------------------------
295 * Install a Haskell signal handler.
297 * We should really do this in Haskell in GHC.Conc, and share the
298 * signal_handlers array with the one there.
300 * -------------------------------------------------------------------------- */
303 stg_sig_install(int sig, int spi, void *mask)
305 sigset_t signals, osignals;
306 struct sigaction action;
309 // Block the signal until we figure out what to do
310 // Count on this to fail if the signal number is invalid
311 if (sig < 0 || sigemptyset(&signals) ||
312 sigaddset(&signals, sig) || sigprocmask(SIG_BLOCK, &signals, &osignals)) {
318 previous_spi = signal_handlers[sig];
324 action.sa_handler = SIG_IGN;
328 action.sa_handler = SIG_DFL;
332 action.sa_flags |= SA_RESETHAND;
335 action.sa_sigaction = generic_handler;
336 action.sa_flags |= SA_SIGINFO;
340 barf("stg_sig_install: bad spi");
344 action.sa_mask = *(sigset_t *)mask;
346 sigemptyset(&action.sa_mask);
348 action.sa_flags |= sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
350 if (sigaction(sig, &action, NULL))
352 errorBelch("sigaction");
356 signal_handlers[sig] = spi;
361 sigaddset(&userSignals, sig);
362 if (previous_spi != STG_SIG_HAN && previous_spi != STG_SIG_RST) {
363 n_haskell_handlers++;
368 sigdelset(&userSignals, sig);
369 if (previous_spi == STG_SIG_HAN || previous_spi == STG_SIG_RST) {
370 n_haskell_handlers--;
375 if (sigprocmask(SIG_SETMASK, &osignals, NULL))
377 errorBelch("sigprocmask");
384 /* -----------------------------------------------------------------------------
385 * Creating new threads for signal handlers.
386 * -------------------------------------------------------------------------- */
388 #if !defined(THREADED_RTS)
390 startSignalHandlers(Capability *cap)
397 while (next_pending_handler != pending_handler_buf) {
399 next_pending_handler--;
401 sig = next_pending_handler->si_signo;
402 if (signal_handlers[sig] == STG_SIG_DFL) {
403 continue; // handler has been changed.
406 info = stgMallocBytes(sizeof(siginfo_t), "startSignalHandlers");
407 // freed by runHandler
408 memcpy(info, next_pending_handler, sizeof(siginfo_t));
412 RtsFlags.GcFlags.initialStkSize,
415 &base_GHCziConc_runHandlers_closure,
416 rts_mkPtr(cap, info)),
417 rts_mkInt(cap, info->si_signo))));
420 unblockUserSignals();
424 /* ----------------------------------------------------------------------------
425 * Mark signal handlers during GC.
426 * -------------------------------------------------------------------------- */
429 markSignalHandlers (evac_fn evac STG_UNUSED, void *user STG_UNUSED)
434 #else /* !RTS_USER_SIGNALS */
436 stg_sig_install(StgInt sig STG_UNUSED,
437 StgInt spi STG_UNUSED,
438 void* mask STG_UNUSED)
440 //barf("User signals not supported");
446 #if defined(RTS_USER_SIGNALS)
447 /* -----------------------------------------------------------------------------
450 * We like to shutdown nicely after receiving a SIGINT, write out the
451 * stats, write profiling info, close open files and flush buffers etc.
452 * -------------------------------------------------------------------------- */
454 shutdown_handler(int sig STG_UNUSED)
456 // If we're already trying to interrupt the RTS, terminate with
457 // extreme prejudice. So the first ^C tries to exit the program
458 // cleanly, and the second one just kills it.
459 if (sched_state >= SCHED_INTERRUPTING) {
460 stg_exit(EXIT_INTERRUPTED);
466 /* -----------------------------------------------------------------------------
467 * Install default signal handlers.
469 * The RTS installs a default signal handler for catching
470 * SIGINT, so that we can perform an orderly shutdown.
472 * Haskell code may install their own SIGINT handler, which is
473 * fine, provided they're so kind as to put back the old one
474 * when they de-install.
476 * In addition to handling SIGINT, the RTS also handles SIGFPE
477 * by ignoring it. Apparently IEEE requires floating-point
478 * exceptions to be ignored by default, but alpha-dec-osf3
479 * doesn't seem to do so.
480 * -------------------------------------------------------------------------- */
482 initDefaultHandlers(void)
484 struct sigaction action,oact;
486 // install the SIGINT handler
487 action.sa_handler = shutdown_handler;
488 sigemptyset(&action.sa_mask);
490 if (sigaction(SIGINT, &action, &oact) != 0) {
491 sysErrorBelch("warning: failed to install SIGINT handler");
494 #if defined(HAVE_SIGINTERRUPT)
495 siginterrupt(SIGINT, 1); // isn't this the default? --SDM
498 // install the SIGFPE handler
500 // In addition to handling SIGINT, also handle SIGFPE by ignoring it.
501 // Apparently IEEE requires floating-point exceptions to be ignored by
502 // default, but alpha-dec-osf3 doesn't seem to do so.
504 // Commented out by SDM 2/7/2002: this causes an infinite loop on
505 // some architectures when an integer division by zero occurs: we
506 // don't recover from the floating point exception, and the
507 // program just generates another one immediately.
509 action.sa_handler = SIG_IGN;
510 sigemptyset(&action.sa_mask);
512 if (sigaction(SIGFPE, &action, &oact) != 0) {
513 sysErrorBelch("warning: failed to install SIGFPE handler");
517 #ifdef alpha_HOST_ARCH
518 ieee_set_fp_control(0);
521 // ignore SIGPIPE; see #1619
522 action.sa_handler = SIG_IGN;
523 sigemptyset(&action.sa_mask);
525 if (sigaction(SIGPIPE, &action, &oact) != 0) {
526 sysErrorBelch("warning: failed to install SIGPIPE handler");
531 resetDefaultHandlers(void)
533 struct sigaction action;
535 action.sa_handler = SIG_DFL;
536 sigemptyset(&action.sa_mask);
540 if (sigaction(SIGINT, &action, NULL) != 0) {
541 sysErrorBelch("warning: failed to uninstall SIGINT handler");
544 if (sigaction(SIGPIPE, &action, NULL) != 0) {
545 sysErrorBelch("warning: failed to uninstall SIGPIPE handler");
550 freeSignalHandlers(void) {
551 if (signal_handlers != NULL) {
552 stgFree(signal_handlers);
556 #endif /* RTS_USER_SIGNALS */