1 /* -----------------------------------------------------------------------------
2 * $Id: Signals.c,v 1.21 2001/08/14 13:40:09 sewardj 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 = (I_ *) malloc((sig + 1) * sizeof(I_));
55 handlers = (I_ *) realloc(handlers, (sig + 1) * sizeof(I_));
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 /* -----------------------------------------------------------------------------
69 Low-level signal handler
71 Places the requested handler on a stack of pending handlers to be
72 started up at the next context switch.
73 -------------------------------------------------------------------------- */
76 generic_handler(int sig)
80 /* Can't call allocate from here. Probably can't call malloc
81 either. However, we have to schedule a new thread somehow.
83 It's probably ok to request a context switch and allow the
84 scheduler to start the handler thread, but how do we
85 communicate this to the scheduler?
87 We need some kind of locking, but with low overhead (i.e. no
88 blocking signals every time around the scheduler).
90 Signal Handlers are atomic (i.e. they can't be interrupted), and
91 we can make use of this. We just need to make sure the
92 critical section of the scheduler can't be interrupted - the
93 only way to do this is to block signals. However, we can lower
94 the overhead by only blocking signals when there are any
95 handlers to run, i.e. the set of pending handlers is
99 /* We use a stack to store the pending signals. We can't
100 dynamically grow this since we can't allocate any memory from
101 within a signal handler.
103 Hence unfortunately we have to bomb out if the buffer
104 overflows. It might be acceptable to carry on in certain
105 circumstances, depending on the signal.
108 *next_pending_handler++ = deRefStablePtr(stgCast(StgStablePtr,handlers[sig]));
111 if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
112 barf("too many pending signals");
115 /* re-establish the signal handler, and carry on */
116 sigemptyset(&signals);
117 sigaddset(&signals, sig);
118 sigprocmask(SIG_UNBLOCK, &signals, NULL);
123 /* -----------------------------------------------------------------------------
124 Blocking/Unblocking of the user signals
125 -------------------------------------------------------------------------- */
127 static sigset_t userSignals;
128 static sigset_t savedSignals;
131 initUserSignals(void)
133 sigemptyset(&userSignals);
137 blockUserSignals(void)
139 sigprocmask(SIG_SETMASK, &userSignals, &savedSignals);
143 unblockUserSignals(void)
145 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
149 /* -----------------------------------------------------------------------------
150 Install a Haskell signal handler.
151 -------------------------------------------------------------------------- */
154 stg_sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
157 struct sigaction action;
160 /* Block the signal until we figure out what to do */
161 /* Count on this to fail if the signal number is invalid */
162 if(sig < 0 || sigemptyset(&signals) || sigaddset(&signals, sig) ||
163 sigprocmask(SIG_BLOCK, &signals, NULL))
168 previous_spi = handlers[sig];
172 handlers[sig] = STG_SIG_IGN;
173 sigdelset(&userSignals, sig);
174 action.sa_handler = SIG_IGN;
178 handlers[sig] = STG_SIG_DFL;
179 sigdelset(&userSignals, sig);
180 action.sa_handler = SIG_DFL;
184 handlers[sig] = (I_)handler;
185 sigaddset(&userSignals, sig);
186 action.sa_handler = generic_handler;
190 barf("stg_sig_install: bad spi");
194 action.sa_mask = *mask;
196 sigemptyset(&action.sa_mask);
198 action.sa_flags = sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
200 if (sigaction(sig, &action, NULL) ||
201 sigprocmask(SIG_UNBLOCK, &signals, NULL))
203 /* need to return an error code, so avoid a stable pointer leak
204 * by freeing the previous handler if there was one.
206 if (previous_spi >= 0) {
207 freeStablePtr(stgCast(StgStablePtr,handlers[sig]));
215 /* -----------------------------------------------------------------------------
216 Creating new threads for the pending signal handlers.
217 -------------------------------------------------------------------------- */
220 start_signal_handlers(void)
224 while (next_pending_handler != pending_handler_buf) {
226 next_pending_handler--;
229 createIOThread(RtsFlags.GcFlags.initialStkSize,
230 (StgClosure *) *next_pending_handler));
233 unblockUserSignals();
238 stg_sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
240 /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
241 barf("no signal handling support in a parallel implementation");
245 start_signal_handlers(void)
250 /* -----------------------------------------------------------------------------
253 We like to shutdown nicely after receiving a SIGINT, write out the
254 stats, write profiling info, close open files and flush buffers etc.
255 -------------------------------------------------------------------------- */
258 pthread_t startup_guy;
262 shutdown_handler(int sig STG_UNUSED)
265 /* if I'm a worker thread, send this signal to the guy who
266 * originally called startupHaskell(). Since we're handling
267 * the signal, it won't be a "send to all threads" type of signal
268 * (according to the POSIX threads spec).
270 if (pthread_self() != startup_guy) {
271 pthread_kill(startup_guy, sig);
275 /* If we're already trying to interrupt the RTS, terminate with
276 * extreme prejudice. So the first ^C tries to exit the program
277 * cleanly, and the second one just kills it.
280 exit(EXIT_INTERRUPTED);
287 * The RTS installs a default signal handler for catching
288 * SIGINT, so that we can perform an orderly shutdown.
290 * Haskell code may install their own SIGINT handler, which is
291 * fine, provided they're so kind as to put back the old one
292 * when they de-install.
294 * In addition to handling SIGINT, the RTS also handles SIGFPE
295 * by ignoring it. Apparently IEEE requires floating-point
296 * exceptions to be ignored by default, but alpha-dec-osf3
297 * doesn't seem to do so.
300 init_default_handlers()
302 struct sigaction action,oact;
305 startup_guy = pthread_self();
307 action.sa_handler = shutdown_handler;
308 sigemptyset(&action.sa_mask);
310 if (sigaction(SIGINT, &action, &oact) != 0) {
311 /* Oh well, at least we tried. */
312 prog_belch("failed to install SIGINT handler");
315 siginterrupt(SIGINT, 1);
317 action.sa_handler = SIG_IGN;
318 sigemptyset(&action.sa_mask);
320 if (sigaction(SIGFPE, &action, &oact) != 0) {
321 /* Oh well, at least we tried. */
322 prog_belch("failed to install SIGFPE handler");
324 #ifdef alpha_TARGET_ARCH
325 ieee_set_fp_control(0);
329 #endif /*! mingw32_TARGET_OS */