1 /* -----------------------------------------------------------------------------
2 * $Id: Signals.c,v 1.20 2001/07/26 03:24:01 ken Exp $
4 * (c) The GHC Team, 1998-1999
6 * Signal processing / handling.
8 * ---------------------------------------------------------------------------*/
10 #define NON_POSIX_SOURCE
18 #include "StablePriv.h"
20 #ifdef alpha_TARGET_ARCH
21 #include <machine/fpu.h>
24 #ifndef mingw32_TARGET_OS
28 /* SUP: The type of handlers is a little bit, well, doubtful... */
29 static StgInt *handlers = NULL; /* Dynamically grown array of signal handlers */
30 static StgInt nHandlers = 0; /* Size of handlers array */
32 #define N_PENDING_HANDLERS 16
34 StgPtr pending_handler_buf[N_PENDING_HANDLERS];
35 StgPtr *next_pending_handler = pending_handler_buf;
39 /* -----------------------------------------------------------------------------
40 Allocate/resize the table of signal handlers.
41 -------------------------------------------------------------------------- */
52 handlers = (I_ *) malloc((sig + 1) * sizeof(I_));
54 handlers = (I_ *) realloc(handlers, (sig + 1) * sizeof(I_));
56 if (handlers == NULL) {
57 /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
58 barf("VM exhausted (in more_handlers)");
60 for(i = nHandlers; i <= sig; i++)
61 /* Fill in the new slots with default actions */
62 handlers[i] = STG_SIG_DFL;
67 /* -----------------------------------------------------------------------------
68 Low-level signal handler
70 Places the requested handler on a stack of pending handlers to be
71 started up at the next context switch.
72 -------------------------------------------------------------------------- */
75 generic_handler(int sig)
79 /* Can't call allocate from here. Probably can't call malloc
80 either. However, we have to schedule a new thread somehow.
82 It's probably ok to request a context switch and allow the
83 scheduler to start the handler thread, but how do we
84 communicate this to the scheduler?
86 We need some kind of locking, but with low overhead (i.e. no
87 blocking signals every time around the scheduler).
89 Signal Handlers are atomic (i.e. they can't be interrupted), and
90 we can make use of this. We just need to make sure the
91 critical section of the scheduler can't be interrupted - the
92 only way to do this is to block signals. However, we can lower
93 the overhead by only blocking signals when there are any
94 handlers to run, i.e. the set of pending handlers is
98 /* We use a stack to store the pending signals. We can't
99 dynamically grow this since we can't allocate any memory from
100 within a signal handler.
102 Hence unfortunately we have to bomb out if the buffer
103 overflows. It might be acceptable to carry on in certain
104 circumstances, depending on the signal.
107 *next_pending_handler++ = deRefStablePtr(stgCast(StgStablePtr,handlers[sig]));
110 if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
111 barf("too many pending signals");
114 /* re-establish the signal handler, and carry on */
115 sigemptyset(&signals);
116 sigaddset(&signals, sig);
117 sigprocmask(SIG_UNBLOCK, &signals, NULL);
122 /* -----------------------------------------------------------------------------
123 Blocking/Unblocking of the user signals
124 -------------------------------------------------------------------------- */
126 static sigset_t userSignals;
127 static sigset_t savedSignals;
130 initUserSignals(void)
132 sigemptyset(&userSignals);
136 blockUserSignals(void)
138 sigprocmask(SIG_SETMASK, &userSignals, &savedSignals);
142 unblockUserSignals(void)
144 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
148 /* -----------------------------------------------------------------------------
149 Install a Haskell signal handler.
150 -------------------------------------------------------------------------- */
153 stg_sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
156 struct sigaction action;
159 /* Block the signal until we figure out what to do */
160 /* Count on this to fail if the signal number is invalid */
161 if(sig < 0 || sigemptyset(&signals) || sigaddset(&signals, sig) ||
162 sigprocmask(SIG_BLOCK, &signals, NULL))
167 previous_spi = handlers[sig];
171 handlers[sig] = STG_SIG_IGN;
172 sigdelset(&userSignals, sig);
173 action.sa_handler = SIG_IGN;
177 handlers[sig] = STG_SIG_DFL;
178 sigdelset(&userSignals, sig);
179 action.sa_handler = SIG_DFL;
183 handlers[sig] = (I_)handler;
184 sigaddset(&userSignals, sig);
185 action.sa_handler = generic_handler;
189 barf("stg_sig_install: bad spi");
193 action.sa_mask = *mask;
195 sigemptyset(&action.sa_mask);
197 action.sa_flags = sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
199 if (sigaction(sig, &action, NULL) ||
200 sigprocmask(SIG_UNBLOCK, &signals, NULL))
202 /* need to return an error code, so avoid a stable pointer leak
203 * by freeing the previous handler if there was one.
205 if (previous_spi >= 0) {
206 freeStablePtr(stgCast(StgStablePtr,handlers[sig]));
214 /* -----------------------------------------------------------------------------
215 Creating new threads for the pending signal handlers.
216 -------------------------------------------------------------------------- */
219 start_signal_handlers(void)
223 while (next_pending_handler != pending_handler_buf) {
225 next_pending_handler--;
228 createIOThread(RtsFlags.GcFlags.initialStkSize,
229 (StgClosure *) *next_pending_handler));
232 unblockUserSignals();
237 stg_sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
239 /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
240 barf("no signal handling support in a parallel implementation");
244 start_signal_handlers(void)
249 /* -----------------------------------------------------------------------------
252 We like to shutdown nicely after receiving a SIGINT, write out the
253 stats, write profiling info, close open files and flush buffers etc.
254 -------------------------------------------------------------------------- */
257 pthread_t startup_guy;
261 shutdown_handler(int sig STG_UNUSED)
264 /* if I'm a worker thread, send this signal to the guy who
265 * originally called startupHaskell(). Since we're handling
266 * the signal, it won't be a "send to all threads" type of signal
267 * (according to the POSIX threads spec).
269 if (pthread_self() != startup_guy) {
270 pthread_kill(startup_guy, sig);
274 /* If we're already trying to interrupt the RTS, terminate with
275 * extreme prejudice. So the first ^C tries to exit the program
276 * cleanly, and the second one just kills it.
279 exit(EXIT_INTERRUPTED);
286 * The RTS installs a default signal handler for catching
287 * SIGINT, so that we can perform an orderly shutdown.
289 * Haskell code may install their own SIGINT handler, which is
290 * fine, provided they're so kind as to put back the old one
291 * when they de-install.
293 * In addition to handling SIGINT, the RTS also handles SIGFPE
294 * by ignoring it. Apparently IEEE requires floating-point
295 * exceptions to be ignored by default, but alpha-dec-osf3
296 * doesn't seem to do so.
299 init_default_handlers()
301 struct sigaction action,oact;
304 startup_guy = pthread_self();
306 action.sa_handler = shutdown_handler;
307 sigemptyset(&action.sa_mask);
309 if (sigaction(SIGINT, &action, &oact) != 0) {
310 /* Oh well, at least we tried. */
311 prog_belch("failed to install SIGINT handler");
314 siginterrupt(SIGINT, 1);
316 action.sa_handler = SIG_IGN;
317 sigemptyset(&action.sa_mask);
319 if (sigaction(SIGFPE, &action, &oact) != 0) {
320 /* Oh well, at least we tried. */
321 prog_belch("failed to install SIGFPE handler");
323 #ifdef alpha_TARGET_ARCH
324 ieee_set_fp_control(0);
328 #endif /*! mingw32_TARGET_OS */