1 /* -----------------------------------------------------------------------------
2 * $Id: Signals.c,v 1.31 2002/12/11 15:36:51 simonmar Exp $
4 * (c) The GHC Team, 1998-1999
6 * Signal processing / handling.
8 * ---------------------------------------------------------------------------*/
10 /* This is non-Posix-compliant.
11 #include "PosixSource.h"
19 #include "StablePriv.h"
21 #ifdef alpha_TARGET_ARCH
22 # include <machine/fpu.h>
35 #ifndef mingw32_TARGET_OS
39 /* SUP: The type of handlers is a little bit, well, doubtful... */
40 static StgInt *handlers = NULL; /* Dynamically grown array of signal handlers */
41 static StgInt nHandlers = 0; /* Size of handlers array */
43 static nat n_haskell_handlers = 0;
45 #define N_PENDING_HANDLERS 16
47 StgPtr pending_handler_buf[N_PENDING_HANDLERS];
48 StgPtr *next_pending_handler = pending_handler_buf;
52 /* -----------------------------------------------------------------------------
53 * Allocate/resize the table of signal handlers.
54 * -------------------------------------------------------------------------- */
65 handlers = (StgInt *) malloc((sig + 1) * sizeof(StgInt));
67 handlers = (StgInt *) realloc(handlers, (sig + 1) * sizeof(StgInt));
69 if (handlers == NULL) {
70 // don't fflush(stdout); WORKAROUND bug in Linux glibc
71 barf("VM exhausted (in more_handlers)");
73 for(i = nHandlers; i <= sig; i++)
74 // Fill in the new slots with default actions
75 handlers[i] = STG_SIG_DFL;
80 /* -----------------------------------------------------------------------------
83 * It seems that shells tend to put stdin back into blocking mode
84 * following a suspend/resume of the process. Here we arrange to put
85 * it back into non-blocking mode. We don't do anything to
86 * stdout/stderr because these handles don't get put into non-blocking
87 * mode at all - see the comments on stdout/stderr in PrelHandle.hsc.
88 * -------------------------------------------------------------------------- */
91 cont_handler(int sig STG_UNUSED)
96 /* -----------------------------------------------------------------------------
97 * Low-level signal handler
99 * Places the requested handler on a stack of pending handlers to be
100 * started up at the next context switch.
101 * -------------------------------------------------------------------------- */
104 generic_handler(int sig)
108 /* Can't call allocate from here. Probably can't call malloc
109 either. However, we have to schedule a new thread somehow.
111 It's probably ok to request a context switch and allow the
112 scheduler to start the handler thread, but how do we
113 communicate this to the scheduler?
115 We need some kind of locking, but with low overhead (i.e. no
116 blocking signals every time around the scheduler).
118 Signal Handlers are atomic (i.e. they can't be interrupted), and
119 we can make use of this. We just need to make sure the
120 critical section of the scheduler can't be interrupted - the
121 only way to do this is to block signals. However, we can lower
122 the overhead by only blocking signals when there are any
123 handlers to run, i.e. the set of pending handlers is
127 /* We use a stack to store the pending signals. We can't
128 dynamically grow this since we can't allocate any memory from
129 within a signal handler.
131 Hence unfortunately we have to bomb out if the buffer
132 overflows. It might be acceptable to carry on in certain
133 circumstances, depending on the signal.
136 *next_pending_handler++ = deRefStablePtr((StgStablePtr)handlers[sig]);
139 if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
140 prog_belch("too many pending signals");
141 stg_exit(EXIT_FAILURE);
144 // re-establish the signal handler, and carry on
145 sigemptyset(&signals);
146 sigaddset(&signals, sig);
147 sigprocmask(SIG_UNBLOCK, &signals, NULL);
149 // *always* do the SIGCONT handler, even if the user overrides it.
150 if (sig == SIGCONT) {
157 /* -----------------------------------------------------------------------------
158 * Blocking/Unblocking of the user signals
159 * -------------------------------------------------------------------------- */
161 static sigset_t userSignals;
162 static sigset_t savedSignals;
165 initUserSignals(void)
167 sigemptyset(&userSignals);
171 blockUserSignals(void)
173 sigprocmask(SIG_SETMASK, &userSignals, &savedSignals);
177 unblockUserSignals(void)
179 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
183 anyUserHandlers(void)
185 return n_haskell_handlers != 0;
189 awaitUserSignals(void)
191 while (!signals_pending() && !interrupted) {
196 /* -----------------------------------------------------------------------------
197 * Install a Haskell signal handler.
198 * -------------------------------------------------------------------------- */
201 stg_sig_install(int sig, int spi, StgStablePtr *handler, void *mask)
203 sigset_t signals, osignals;
204 struct sigaction action;
207 // Block the signal until we figure out what to do
208 // Count on this to fail if the signal number is invalid
209 if (sig < 0 || sigemptyset(&signals) ||
210 sigaddset(&signals, sig) || sigprocmask(SIG_BLOCK, &signals, &osignals)) {
216 previous_spi = handlers[sig];
220 handlers[sig] = STG_SIG_IGN;
221 sigdelset(&userSignals, sig);
222 action.sa_handler = SIG_IGN;
226 handlers[sig] = STG_SIG_DFL;
227 sigdelset(&userSignals, sig);
228 action.sa_handler = SIG_DFL;
233 handlers[sig] = (StgInt)*handler;
234 sigaddset(&userSignals, sig);
235 action.sa_handler = generic_handler;
236 if (spi == STG_SIG_RST) {
237 action.sa_flags = SA_RESETHAND;
239 n_haskell_handlers++;
243 barf("stg_sig_install: bad spi");
247 action.sa_mask = *(sigset_t *)mask;
249 sigemptyset(&action.sa_mask);
251 action.sa_flags |= sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
253 if (sigaction(sig, &action, NULL) ||
254 sigprocmask(SIG_SETMASK, &osignals, NULL))
256 // need to return an error code, so avoid a stable pointer leak
257 // by freeing the previous handler if there was one.
258 if (previous_spi >= 0) {
259 freeStablePtr(stgCast(StgStablePtr,handlers[sig]));
260 n_haskell_handlers--;
265 if (previous_spi == STG_SIG_DFL || previous_spi == STG_SIG_IGN
266 || previous_spi == STG_SIG_ERR) {
269 *handler = (StgStablePtr)previous_spi;
274 /* -----------------------------------------------------------------------------
275 * Creating new threads for the pending signal handlers.
276 * -------------------------------------------------------------------------- */
278 startSignalHandlers(void)
282 while (next_pending_handler != pending_handler_buf) {
284 next_pending_handler--;
287 createIOThread(RtsFlags.GcFlags.initialStkSize,
288 (StgClosure *) *next_pending_handler));
291 unblockUserSignals();
294 /* ----------------------------------------------------------------------------
295 * Mark signal handlers during GC.
297 * We do this rather than trying to start all the signal handlers
298 * prior to GC, because that requires extra heap for the new threads.
299 * Signals must be blocked (see blockUserSignals() above) during GC to
300 * avoid race conditions.
301 * -------------------------------------------------------------------------- */
304 markSignalHandlers (evac_fn evac)
308 p = next_pending_handler;
309 while (p != pending_handler_buf) {
311 evac((StgClosure **)p);
317 stg_sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
319 // don't fflush(stdout); WORKAROUND bug in Linux glibc
320 barf("no signal handling support in a parallel implementation");
324 startSignalHandlers(void)
329 /* -----------------------------------------------------------------------------
332 * We like to shutdown nicely after receiving a SIGINT, write out the
333 * stats, write profiling info, close open files and flush buffers etc.
334 * -------------------------------------------------------------------------- */
336 pthread_t startup_guy;
340 shutdown_handler(int sig STG_UNUSED)
343 // if I'm a worker thread, send this signal to the guy who
344 // originally called startupHaskell(). Since we're handling
345 // the signal, it won't be a "send to all threads" type of signal
346 // (according to the POSIX threads spec).
347 if (pthread_self() != startup_guy) {
348 pthread_kill(startup_guy, sig);
353 // If we're already trying to interrupt the RTS, terminate with
354 // extreme prejudice. So the first ^C tries to exit the program
355 // cleanly, and the second one just kills it.
357 exit(EXIT_INTERRUPTED);
363 /* -----------------------------------------------------------------------------
364 * Install default signal handlers.
366 * The RTS installs a default signal handler for catching
367 * SIGINT, so that we can perform an orderly shutdown.
369 * Haskell code may install their own SIGINT handler, which is
370 * fine, provided they're so kind as to put back the old one
371 * when they de-install.
373 * In addition to handling SIGINT, the RTS also handles SIGFPE
374 * by ignoring it. Apparently IEEE requires floating-point
375 * exceptions to be ignored by default, but alpha-dec-osf3
376 * doesn't seem to do so.
377 * -------------------------------------------------------------------------- */
379 initDefaultHandlers()
381 struct sigaction action,oact;
384 startup_guy = pthread_self();
387 // install the SIGINT handler
388 action.sa_handler = shutdown_handler;
389 sigemptyset(&action.sa_mask);
391 if (sigaction(SIGINT, &action, &oact) != 0) {
392 prog_belch("warning: failed to install SIGINT handler");
395 #ifndef cygwin32_TARGET_OS
396 siginterrupt(SIGINT, 1); // isn't this the default? --SDM
399 // install the SIGCONT handler
400 action.sa_handler = cont_handler;
401 sigemptyset(&action.sa_mask);
403 if (sigaction(SIGCONT, &action, &oact) != 0) {
404 prog_belch("warning: failed to install SIGCONT handler");
407 // install the SIGFPE handler
409 // In addition to handling SIGINT, also handle SIGFPE by ignoring it.
410 // Apparently IEEE requires floating-point exceptions to be ignored by
411 // default, but alpha-dec-osf3 doesn't seem to do so.
413 // Commented out by SDM 2/7/2002: this causes an infinite loop on
414 // some architectures when an integer division by zero occurs: we
415 // don't recover from the floating point exception, and the
416 // program just generates another one immediately.
418 action.sa_handler = SIG_IGN;
419 sigemptyset(&action.sa_mask);
421 if (sigaction(SIGFPE, &action, &oact) != 0) {
422 prog_belch("warning: failed to install SIGFPE handler");
426 #ifdef alpha_TARGET_ARCH
427 ieee_set_fp_control(0);
431 #endif /*! mingw32_TARGET_OS */