1 /* -----------------------------------------------------------------------------
2 * $Id: Signals.c,v 1.18 2000/08/25 13:12:07 simonmar Exp $
4 * (c) The GHC Team, 1998-1999
6 * Signal processing / handling.
8 * ---------------------------------------------------------------------------*/
10 #define NON_POSIX_SOURCE
18 #include "StablePriv.h"
20 #ifndef mingw32_TARGET_OS
24 /* SUP: The type of handlers is a little bit, well, doubtful... */
25 static StgInt *handlers = NULL; /* Dynamically grown array of signal handlers */
26 static StgInt nHandlers = 0; /* Size of handlers array */
28 #define N_PENDING_HANDLERS 16
30 StgPtr pending_handler_buf[N_PENDING_HANDLERS];
31 StgPtr *next_pending_handler = pending_handler_buf;
35 /* -----------------------------------------------------------------------------
36 Allocate/resize the table of signal handlers.
37 -------------------------------------------------------------------------- */
48 handlers = (I_ *) malloc((sig + 1) * sizeof(I_));
50 handlers = (I_ *) realloc(handlers, (sig + 1) * sizeof(I_));
52 if (handlers == NULL) {
53 /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
54 barf("VM exhausted (in more_handlers)");
56 for(i = nHandlers; i <= sig; i++)
57 /* Fill in the new slots with default actions */
58 handlers[i] = STG_SIG_DFL;
63 /* -----------------------------------------------------------------------------
64 Low-level signal handler
66 Places the requested handler on a stack of pending handlers to be
67 started up at the next context switch.
68 -------------------------------------------------------------------------- */
71 generic_handler(int sig)
75 /* Can't call allocate from here. Probably can't call malloc
76 either. However, we have to schedule a new thread somehow.
78 It's probably ok to request a context switch and allow the
79 scheduler to start the handler thread, but how do we
80 communicate this to the scheduler?
82 We need some kind of locking, but with low overhead (i.e. no
83 blocking signals every time around the scheduler).
85 Signal Handlers are atomic (i.e. they can't be interrupted), and
86 we can make use of this. We just need to make sure the
87 critical section of the scheduler can't be interrupted - the
88 only way to do this is to block signals. However, we can lower
89 the overhead by only blocking signals when there are any
90 handlers to run, i.e. the set of pending handlers is
94 /* We use a stack to store the pending signals. We can't
95 dynamically grow this since we can't allocate any memory from
96 within a signal handler.
98 Hence unfortunately we have to bomb out if the buffer
99 overflows. It might be acceptable to carry on in certain
100 circumstances, depending on the signal.
103 *next_pending_handler++ = deRefStablePtr(stgCast(StgStablePtr,handlers[sig]));
106 if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
107 barf("too many pending signals");
110 /* re-establish the signal handler, and carry on */
111 sigemptyset(&signals);
112 sigaddset(&signals, sig);
113 sigprocmask(SIG_UNBLOCK, &signals, NULL);
118 /* -----------------------------------------------------------------------------
119 Blocking/Unblocking of the user signals
120 -------------------------------------------------------------------------- */
122 static sigset_t userSignals;
123 static sigset_t savedSignals;
126 initUserSignals(void)
128 sigemptyset(&userSignals);
132 blockUserSignals(void)
134 sigprocmask(SIG_SETMASK, &userSignals, &savedSignals);
138 unblockUserSignals(void)
140 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
144 /* -----------------------------------------------------------------------------
145 Install a Haskell signal handler.
146 -------------------------------------------------------------------------- */
149 sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
152 struct sigaction action;
155 /* Block the signal until we figure out what to do */
156 /* Count on this to fail if the signal number is invalid */
157 if(sig < 0 || sigemptyset(&signals) || sigaddset(&signals, sig) ||
158 sigprocmask(SIG_BLOCK, &signals, NULL))
163 previous_spi = handlers[sig];
167 handlers[sig] = STG_SIG_IGN;
168 sigdelset(&userSignals, sig);
169 action.sa_handler = SIG_IGN;
173 handlers[sig] = STG_SIG_DFL;
174 sigdelset(&userSignals, sig);
175 action.sa_handler = SIG_DFL;
179 handlers[sig] = (I_)handler;
180 sigaddset(&userSignals, sig);
181 action.sa_handler = generic_handler;
185 barf("sig_install: bad spi");
189 action.sa_mask = *mask;
191 sigemptyset(&action.sa_mask);
193 action.sa_flags = sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
195 if (sigaction(sig, &action, NULL) ||
196 sigprocmask(SIG_UNBLOCK, &signals, NULL))
198 /* need to return an error code, so avoid a stable pointer leak
199 * by freeing the previous handler if there was one.
201 if (previous_spi >= 0) {
202 freeStablePtr(stgCast(StgStablePtr,handlers[sig]));
210 /* -----------------------------------------------------------------------------
211 Creating new threads for the pending signal handlers.
212 -------------------------------------------------------------------------- */
215 start_signal_handlers(void)
219 while (next_pending_handler != pending_handler_buf) {
221 next_pending_handler--;
224 createIOThread(RtsFlags.GcFlags.initialStkSize,
225 (StgClosure *) *next_pending_handler));
228 unblockUserSignals();
233 sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
235 /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
236 barf("no signal handling support in a parallel implementation");
240 start_signal_handlers(void)
245 /* -----------------------------------------------------------------------------
248 We like to shutdown nicely after receiving a SIGINT, write out the
249 stats, write profiling info, close open files and flush buffers etc.
250 -------------------------------------------------------------------------- */
253 pthread_t startup_guy;
257 shutdown_handler(int sig STG_UNUSED)
260 /* if I'm a worker thread, send this signal to the guy who
261 * originally called startupHaskell(). Since we're handling
262 * the signal, it won't be a "send to all threads" type of signal
263 * (according to the POSIX threads spec).
265 if (pthread_self() != startup_guy) {
266 pthread_kill(startup_guy, sig);
270 /* If we're already trying to interrupt the RTS, terminate with
271 * extreme prejudice. So the first ^C tries to exit the program
272 * cleanly, and the second one just kills it.
275 exit(EXIT_INTERRUPTED);
282 * The RTS installs a default signal handler for catching
283 * SIGINT, so that we can perform an orderly shutdown.
285 * Haskell code may install their own SIGINT handler, which is
286 * fine, provided they're so kind as to put back the old one
287 * when they de-install.
290 init_default_handlers()
292 struct sigaction action,oact;
295 startup_guy = pthread_self();
297 action.sa_handler = shutdown_handler;
298 sigemptyset(&action.sa_mask);
300 if (sigaction(SIGINT, &action, &oact) != 0) {
301 /* Oh well, at least we tried. */
302 prog_belch("failed to install SIGINT handler");
305 siginterrupt(SIGINT, 1);
308 #endif /*! mingw32_TARGET_OS */