1 /* -----------------------------------------------------------------------------
2 * $Id: Signals.c,v 1.22 2001/10/31 10:34:29 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>
25 #ifndef mingw32_TARGET_OS
29 /* SUP: The type of handlers is a little bit, well, doubtful... */
30 static StgInt *handlers = NULL; /* Dynamically grown array of signal handlers */
31 static StgInt nHandlers = 0; /* Size of handlers array */
33 #define N_PENDING_HANDLERS 16
35 StgPtr pending_handler_buf[N_PENDING_HANDLERS];
36 StgPtr *next_pending_handler = pending_handler_buf;
40 /* -----------------------------------------------------------------------------
41 * Allocate/resize the table of signal handlers.
42 * -------------------------------------------------------------------------- */
53 handlers = (StgInt *) malloc((sig + 1) * sizeof(StgInt));
55 handlers = (StgInt *) realloc(handlers, (sig + 1) * sizeof(StgInt));
57 if (handlers == NULL) {
58 // don't fflush(stdout); WORKAROUND bug in Linux glibc
59 barf("VM exhausted (in more_handlers)");
61 for(i = nHandlers; i <= sig; i++)
62 // Fill in the new slots with default actions
63 handlers[i] = STG_SIG_DFL;
68 /* -----------------------------------------------------------------------------
71 * It seems that shells tend to put stdin back into blocking mode
72 * following a suspend/resume of the process. Here we arrange to put
73 * it back into non-blocking mode. We don't do anything to
74 * stdout/stderr because these handles don't get put into non-blocking
75 * mode at all - see the comments on stdout/stderr in PrelHandle.hsc.
76 * -------------------------------------------------------------------------- */
79 cont_handler(int sig STG_UNUSED)
84 /* -----------------------------------------------------------------------------
85 * Low-level signal handler
87 * Places the requested handler on a stack of pending handlers to be
88 * started up at the next context switch.
89 * -------------------------------------------------------------------------- */
92 generic_handler(int sig)
96 /* Can't call allocate from here. Probably can't call malloc
97 either. However, we have to schedule a new thread somehow.
99 It's probably ok to request a context switch and allow the
100 scheduler to start the handler thread, but how do we
101 communicate this to the scheduler?
103 We need some kind of locking, but with low overhead (i.e. no
104 blocking signals every time around the scheduler).
106 Signal Handlers are atomic (i.e. they can't be interrupted), and
107 we can make use of this. We just need to make sure the
108 critical section of the scheduler can't be interrupted - the
109 only way to do this is to block signals. However, we can lower
110 the overhead by only blocking signals when there are any
111 handlers to run, i.e. the set of pending handlers is
115 /* We use a stack to store the pending signals. We can't
116 dynamically grow this since we can't allocate any memory from
117 within a signal handler.
119 Hence unfortunately we have to bomb out if the buffer
120 overflows. It might be acceptable to carry on in certain
121 circumstances, depending on the signal.
124 *next_pending_handler++ = deRefStablePtr((StgStablePtr)handlers[sig]);
127 if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
128 barf("too many pending signals");
131 // re-establish the signal handler, and carry on
132 sigemptyset(&signals);
133 sigaddset(&signals, sig);
134 sigprocmask(SIG_UNBLOCK, &signals, NULL);
136 // *always* do the SIGCONT handler, even if the user overrides it.
137 if (sig == SIGCONT) {
144 /* -----------------------------------------------------------------------------
145 * Blocking/Unblocking of the user signals
146 * -------------------------------------------------------------------------- */
148 static sigset_t userSignals;
149 static sigset_t savedSignals;
152 initUserSignals(void)
154 sigemptyset(&userSignals);
158 blockUserSignals(void)
160 sigprocmask(SIG_SETMASK, &userSignals, &savedSignals);
164 unblockUserSignals(void)
166 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
170 /* -----------------------------------------------------------------------------
171 * Install a Haskell signal handler.
172 * -------------------------------------------------------------------------- */
175 stg_sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
178 struct sigaction action;
181 // Block the signal until we figure out what to do
182 // Count on this to fail if the signal number is invalid
183 if (sig < 0 || sigemptyset(&signals) ||
184 sigaddset(&signals, sig) || sigprocmask(SIG_BLOCK, &signals, NULL)) {
190 previous_spi = handlers[sig];
194 handlers[sig] = STG_SIG_IGN;
195 sigdelset(&userSignals, sig);
196 action.sa_handler = SIG_IGN;
200 handlers[sig] = STG_SIG_DFL;
201 sigdelset(&userSignals, sig);
202 action.sa_handler = SIG_DFL;
206 handlers[sig] = (StgInt)handler;
207 sigaddset(&userSignals, sig);
208 action.sa_handler = generic_handler;
212 barf("stg_sig_install: bad spi");
216 action.sa_mask = *mask;
218 sigemptyset(&action.sa_mask);
220 action.sa_flags = sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
222 if (sigaction(sig, &action, NULL) ||
223 sigprocmask(SIG_UNBLOCK, &signals, NULL))
225 // need to return an error code, so avoid a stable pointer leak
226 // by freeing the previous handler if there was one.
227 if (previous_spi >= 0) {
228 freeStablePtr(stgCast(StgStablePtr,handlers[sig]));
236 /* -----------------------------------------------------------------------------
237 * Creating new threads for the pending signal handlers.
238 * -------------------------------------------------------------------------- */
240 startSignalHandlers(void)
244 while (next_pending_handler != pending_handler_buf) {
246 next_pending_handler--;
249 createIOThread(RtsFlags.GcFlags.initialStkSize,
250 (StgClosure *) *next_pending_handler));
253 unblockUserSignals();
258 stg_sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
260 // don't fflush(stdout); WORKAROUND bug in Linux glibc
261 barf("no signal handling support in a parallel implementation");
265 startSignalHandlers(void)
270 /* -----------------------------------------------------------------------------
273 * We like to shutdown nicely after receiving a SIGINT, write out the
274 * stats, write profiling info, close open files and flush buffers etc.
275 * -------------------------------------------------------------------------- */
277 pthread_t startup_guy;
281 shutdown_handler(int sig STG_UNUSED)
284 // if I'm a worker thread, send this signal to the guy who
285 // originally called startupHaskell(). Since we're handling
286 // the signal, it won't be a "send to all threads" type of signal
287 // (according to the POSIX threads spec).
288 if (pthread_self() != startup_guy) {
289 pthread_kill(startup_guy, sig);
294 // If we're already trying to interrupt the RTS, terminate with
295 // extreme prejudice. So the first ^C tries to exit the program
296 // cleanly, and the second one just kills it.
298 exit(EXIT_INTERRUPTED);
304 /* -----------------------------------------------------------------------------
305 * Install default signal handlers.
307 * The RTS installs a default signal handler for catching
308 * SIGINT, so that we can perform an orderly shutdown.
310 * Haskell code may install their own SIGINT handler, which is
311 * fine, provided they're so kind as to put back the old one
312 * when they de-install.
314 * In addition to handling SIGINT, the RTS also handles SIGFPE
315 * by ignoring it. Apparently IEEE requires floating-point
316 * exceptions to be ignored by default, but alpha-dec-osf3
317 * doesn't seem to do so.
318 * -------------------------------------------------------------------------- */
320 initDefaultHandlers()
322 struct sigaction action,oact;
325 startup_guy = pthread_self();
328 // install the SIGINT handler
329 action.sa_handler = shutdown_handler;
330 sigemptyset(&action.sa_mask);
332 if (sigaction(SIGINT, &action, &oact) != 0) {
333 prog_belch("warning: failed to install SIGINT handler");
336 siginterrupt(SIGINT, 1); // isn't this the default? --SDM
338 // install the SIGCONT handler
339 action.sa_handler = cont_handler;
340 sigemptyset(&action.sa_mask);
342 if (sigaction(SIGCONT, &action, &oact) != 0) {
343 prog_belch("warning: failed to install SIGCONT handler");
346 // install the SIGFPE handler
347 action.sa_handler = SIG_IGN;
348 sigemptyset(&action.sa_mask);
350 if (sigaction(SIGFPE, &action, &oact) != 0) {
351 prog_belch("warning: failed to install SIGFPE handler");
353 #ifdef alpha_TARGET_ARCH
354 ieee_set_fp_control(0);
358 #endif /*! mingw32_TARGET_OS */