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 ioManagerStart (void)
141 // Make sure the IO manager thread is running
143 if (io_manager_pipe < 0) {
145 cap = rts_evalIO(cap,&base_GHCziConc_ensureIOManagerIsRunning_closure,NULL);
151 #if !defined(THREADED_RTS)
153 #define N_PENDING_HANDLERS 16
155 siginfo_t pending_handler_buf[N_PENDING_HANDLERS];
156 siginfo_t *next_pending_handler = pending_handler_buf;
158 #endif /* THREADED_RTS */
160 /* -----------------------------------------------------------------------------
161 * Low-level signal handler
163 * Places the requested handler on a stack of pending handlers to be
164 * started up at the next context switch.
165 * -------------------------------------------------------------------------- */
168 generic_handler(int sig USED_IF_THREADS,
172 #if defined(THREADED_RTS)
174 if (io_manager_pipe != -1)
176 StgWord8 buf[sizeof(siginfo_t) + 1];
180 memcpy(buf+1, info, sizeof(siginfo_t));
181 r = write(io_manager_pipe, buf, sizeof(siginfo_t)+1);
182 if (r == -1 && errno == EAGAIN)
184 errorBelch("lost signal due to full pipe: %d\n", sig);
187 // If the IO manager hasn't told us what the FD of the write end
188 // of its pipe is, there's not much we can do here, so just ignore
191 #else /* not THREADED_RTS */
193 /* Can't call allocate from here. Probably can't call malloc
194 either. However, we have to schedule a new thread somehow.
196 It's probably ok to request a context switch and allow the
197 scheduler to start the handler thread, but how do we
198 communicate this to the scheduler?
200 We need some kind of locking, but with low overhead (i.e. no
201 blocking signals every time around the scheduler).
203 Signal Handlers are atomic (i.e. they can't be interrupted), and
204 we can make use of this. We just need to make sure the
205 critical section of the scheduler can't be interrupted - the
206 only way to do this is to block signals. However, we can lower
207 the overhead by only blocking signals when there are any
208 handlers to run, i.e. the set of pending handlers is
212 /* We use a stack to store the pending signals. We can't
213 dynamically grow this since we can't allocate any memory from
214 within a signal handler.
216 Hence unfortunately we have to bomb out if the buffer
217 overflows. It might be acceptable to carry on in certain
218 circumstances, depending on the signal.
221 memcpy(next_pending_handler, info, sizeof(siginfo_t));
223 next_pending_handler++;
226 if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
227 errorBelch("too many pending signals");
228 stg_exit(EXIT_FAILURE);
231 contextSwitchCapability(&MainCapability);
233 #endif /* THREADED_RTS */
236 /* -----------------------------------------------------------------------------
237 * Blocking/Unblocking of the user signals
238 * -------------------------------------------------------------------------- */
240 static sigset_t userSignals;
241 static sigset_t savedSignals;
244 initUserSignals(void)
246 sigemptyset(&userSignals);
248 getStablePtr((StgPtr)&base_GHCziConc_runHandlers_closure);
249 // needed to keep runHandler alive
254 blockUserSignals(void)
256 sigprocmask(SIG_BLOCK, &userSignals, &savedSignals);
260 unblockUserSignals(void)
262 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
266 anyUserHandlers(void)
268 return n_haskell_handlers != 0;
271 #if !defined(THREADED_RTS)
273 awaitUserSignals(void)
275 while (!signals_pending() && sched_state == SCHED_RUNNING) {
281 /* -----------------------------------------------------------------------------
282 * Install a Haskell signal handler.
284 * We should really do this in Haskell in GHC.Conc, and share the
285 * signal_handlers array with the one there.
287 * -------------------------------------------------------------------------- */
290 stg_sig_install(int sig, int spi, void *mask)
292 sigset_t signals, osignals;
293 struct sigaction action;
296 // Block the signal until we figure out what to do
297 // Count on this to fail if the signal number is invalid
298 if (sig < 0 || sigemptyset(&signals) ||
299 sigaddset(&signals, sig) || sigprocmask(SIG_BLOCK, &signals, &osignals)) {
305 previous_spi = signal_handlers[sig];
311 action.sa_handler = SIG_IGN;
315 action.sa_handler = SIG_DFL;
319 action.sa_flags |= SA_RESETHAND;
322 action.sa_sigaction = generic_handler;
323 action.sa_flags |= SA_SIGINFO;
327 barf("stg_sig_install: bad spi");
331 action.sa_mask = *(sigset_t *)mask;
333 sigemptyset(&action.sa_mask);
335 action.sa_flags |= sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
337 if (sigaction(sig, &action, NULL))
339 errorBelch("sigaction");
343 signal_handlers[sig] = spi;
348 sigaddset(&userSignals, sig);
349 if (previous_spi != STG_SIG_HAN && previous_spi != STG_SIG_RST) {
350 n_haskell_handlers++;
355 sigdelset(&userSignals, sig);
356 if (previous_spi == STG_SIG_HAN || previous_spi == STG_SIG_RST) {
357 n_haskell_handlers--;
362 if (sigprocmask(SIG_SETMASK, &osignals, NULL))
364 errorBelch("sigprocmask");
371 /* -----------------------------------------------------------------------------
372 * Creating new threads for signal handlers.
373 * -------------------------------------------------------------------------- */
375 #if !defined(THREADED_RTS)
377 startSignalHandlers(Capability *cap)
384 while (next_pending_handler != pending_handler_buf) {
386 next_pending_handler--;
388 sig = next_pending_handler->si_signo;
389 if (signal_handlers[sig] == STG_SIG_DFL) {
390 continue; // handler has been changed.
393 info = stgMallocBytes(sizeof(siginfo_t), "startSignalHandlers");
394 // freed by runHandler
395 memcpy(info, next_pending_handler, sizeof(siginfo_t));
399 RtsFlags.GcFlags.initialStkSize,
402 &base_GHCziConc_runHandlers_closure,
403 rts_mkPtr(cap, info)),
404 rts_mkInt(cap, info->si_signo))));
407 unblockUserSignals();
411 /* ----------------------------------------------------------------------------
412 * Mark signal handlers during GC.
413 * -------------------------------------------------------------------------- */
416 markSignalHandlers (evac_fn evac STG_UNUSED, void *user STG_UNUSED)
421 #else /* !RTS_USER_SIGNALS */
423 stg_sig_install(StgInt sig STG_UNUSED,
424 StgInt spi STG_UNUSED,
425 void* mask STG_UNUSED)
427 //barf("User signals not supported");
433 #if defined(RTS_USER_SIGNALS)
434 /* -----------------------------------------------------------------------------
437 * We like to shutdown nicely after receiving a SIGINT, write out the
438 * stats, write profiling info, close open files and flush buffers etc.
439 * -------------------------------------------------------------------------- */
441 shutdown_handler(int sig STG_UNUSED)
443 // If we're already trying to interrupt the RTS, terminate with
444 // extreme prejudice. So the first ^C tries to exit the program
445 // cleanly, and the second one just kills it.
446 if (sched_state >= SCHED_INTERRUPTING) {
447 stg_exit(EXIT_INTERRUPTED);
453 /* -----------------------------------------------------------------------------
454 * Install default signal handlers.
456 * The RTS installs a default signal handler for catching
457 * SIGINT, so that we can perform an orderly shutdown.
459 * Haskell code may install their own SIGINT handler, which is
460 * fine, provided they're so kind as to put back the old one
461 * when they de-install.
463 * In addition to handling SIGINT, the RTS also handles SIGFPE
464 * by ignoring it. Apparently IEEE requires floating-point
465 * exceptions to be ignored by default, but alpha-dec-osf3
466 * doesn't seem to do so.
467 * -------------------------------------------------------------------------- */
469 initDefaultHandlers(void)
471 struct sigaction action,oact;
473 // install the SIGINT handler
474 action.sa_handler = shutdown_handler;
475 sigemptyset(&action.sa_mask);
477 if (sigaction(SIGINT, &action, &oact) != 0) {
478 sysErrorBelch("warning: failed to install SIGINT handler");
481 #if defined(HAVE_SIGINTERRUPT)
482 siginterrupt(SIGINT, 1); // isn't this the default? --SDM
485 // install the SIGFPE handler
487 // In addition to handling SIGINT, also handle SIGFPE by ignoring it.
488 // Apparently IEEE requires floating-point exceptions to be ignored by
489 // default, but alpha-dec-osf3 doesn't seem to do so.
491 // Commented out by SDM 2/7/2002: this causes an infinite loop on
492 // some architectures when an integer division by zero occurs: we
493 // don't recover from the floating point exception, and the
494 // program just generates another one immediately.
496 action.sa_handler = SIG_IGN;
497 sigemptyset(&action.sa_mask);
499 if (sigaction(SIGFPE, &action, &oact) != 0) {
500 sysErrorBelch("warning: failed to install SIGFPE handler");
504 #ifdef alpha_HOST_ARCH
505 ieee_set_fp_control(0);
508 // ignore SIGPIPE; see #1619
509 action.sa_handler = SIG_IGN;
510 sigemptyset(&action.sa_mask);
512 if (sigaction(SIGPIPE, &action, &oact) != 0) {
513 sysErrorBelch("warning: failed to install SIGPIPE handler");
518 resetDefaultHandlers(void)
520 struct sigaction action;
522 action.sa_handler = SIG_DFL;
523 sigemptyset(&action.sa_mask);
527 if (sigaction(SIGINT, &action, NULL) != 0) {
528 sysErrorBelch("warning: failed to uninstall SIGINT handler");
531 if (sigaction(SIGPIPE, &action, NULL) != 0) {
532 sysErrorBelch("warning: failed to uninstall SIGPIPE handler");
537 freeSignalHandlers(void) {
538 if (signal_handlers != NULL) {
539 stgFree(signal_handlers);
543 #endif /* RTS_USER_SIGNALS */