1 /* -----------------------------------------------------------------------------
2 * $Id: Signals.c,v 1.17 2000/04/14 16:47:43 panne Exp $
4 * (c) The GHC Team, 1998-1999
6 * Signal processing / handling.
8 * ---------------------------------------------------------------------------*/
16 #include "StablePriv.h"
18 #ifndef mingw32_TARGET_OS
22 /* SUP: The type of handlers is a little bit, well, doubtful... */
23 static StgInt *handlers = NULL; /* Dynamically grown array of signal handlers */
24 static StgInt nHandlers = 0; /* Size of handlers array */
26 #define N_PENDING_HANDLERS 16
28 StgPtr pending_handler_buf[N_PENDING_HANDLERS];
29 StgPtr *next_pending_handler = pending_handler_buf;
33 /* -----------------------------------------------------------------------------
34 Allocate/resize the table of signal handlers.
35 -------------------------------------------------------------------------- */
46 handlers = (I_ *) malloc((sig + 1) * sizeof(I_));
48 handlers = (I_ *) realloc(handlers, (sig + 1) * sizeof(I_));
50 if (handlers == NULL) {
51 /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
52 barf("VM exhausted (in more_handlers)");
54 for(i = nHandlers; i <= sig; i++)
55 /* Fill in the new slots with default actions */
56 handlers[i] = STG_SIG_DFL;
61 /* -----------------------------------------------------------------------------
62 Low-level signal handler
64 Places the requested handler on a stack of pending handlers to be
65 started up at the next context switch.
66 -------------------------------------------------------------------------- */
69 generic_handler(int sig)
73 /* Can't call allocate from here. Probably can't call malloc
74 either. However, we have to schedule a new thread somehow.
76 It's probably ok to request a context switch and allow the
77 scheduler to start the handler thread, but how do we
78 communicate this to the scheduler?
80 We need some kind of locking, but with low overhead (i.e. no
81 blocking signals every time around the scheduler).
83 Signal Handlers are atomic (i.e. they can't be interrupted), and
84 we can make use of this. We just need to make sure the
85 critical section of the scheduler can't be interrupted - the
86 only way to do this is to block signals. However, we can lower
87 the overhead by only blocking signals when there are any
88 handlers to run, i.e. the set of pending handlers is
92 /* We use a stack to store the pending signals. We can't
93 dynamically grow this since we can't allocate any memory from
94 within a signal handler.
96 Hence unfortunately we have to bomb out if the buffer
97 overflows. It might be acceptable to carry on in certain
98 circumstances, depending on the signal.
101 *next_pending_handler++ = deRefStablePtr(stgCast(StgStablePtr,handlers[sig]));
104 if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
105 barf("too many pending signals");
108 /* re-establish the signal handler, and carry on */
109 sigemptyset(&signals);
110 sigaddset(&signals, sig);
111 sigprocmask(SIG_UNBLOCK, &signals, NULL);
116 /* -----------------------------------------------------------------------------
117 Blocking/Unblocking of the user signals
118 -------------------------------------------------------------------------- */
120 static sigset_t userSignals;
121 static sigset_t savedSignals;
124 initUserSignals(void)
126 sigemptyset(&userSignals);
130 blockUserSignals(void)
132 sigprocmask(SIG_SETMASK, &userSignals, &savedSignals);
136 unblockUserSignals(void)
138 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
142 /* -----------------------------------------------------------------------------
143 Install a Haskell signal handler.
144 -------------------------------------------------------------------------- */
147 sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
150 struct sigaction action;
153 /* Block the signal until we figure out what to do */
154 /* Count on this to fail if the signal number is invalid */
155 if(sig < 0 || sigemptyset(&signals) || sigaddset(&signals, sig) ||
156 sigprocmask(SIG_BLOCK, &signals, NULL))
161 previous_spi = handlers[sig];
165 handlers[sig] = STG_SIG_IGN;
166 sigdelset(&userSignals, sig);
167 action.sa_handler = SIG_IGN;
171 handlers[sig] = STG_SIG_DFL;
172 sigdelset(&userSignals, sig);
173 action.sa_handler = SIG_DFL;
177 handlers[sig] = (I_)handler;
178 sigaddset(&userSignals, sig);
179 action.sa_handler = generic_handler;
183 barf("sig_install: bad spi");
187 action.sa_mask = *mask;
189 sigemptyset(&action.sa_mask);
191 action.sa_flags = sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
193 if (sigaction(sig, &action, NULL) ||
194 sigprocmask(SIG_UNBLOCK, &signals, NULL))
196 /* need to return an error code, so avoid a stable pointer leak
197 * by freeing the previous handler if there was one.
199 if (previous_spi >= 0) {
200 freeStablePtr(stgCast(StgStablePtr,handlers[sig]));
208 /* -----------------------------------------------------------------------------
209 Creating new threads for the pending signal handlers.
210 -------------------------------------------------------------------------- */
213 start_signal_handlers(void)
217 while (next_pending_handler != pending_handler_buf) {
219 next_pending_handler--;
222 createIOThread(RtsFlags.GcFlags.initialStkSize,
223 (StgClosure *) *next_pending_handler));
226 unblockUserSignals();
231 sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
233 /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
234 barf("no signal handling support in a parallel implementation");
238 start_signal_handlers(void)
243 /* -----------------------------------------------------------------------------
246 We like to shutdown nicely after receiving a SIGINT, write out the
247 stats, write profiling info, close open files and flush buffers etc.
248 -------------------------------------------------------------------------- */
251 pthread_t startup_guy;
255 shutdown_handler(int sig STG_UNUSED)
258 /* if I'm a worker thread, send this signal to the guy who
259 * originally called startupHaskell(). Since we're handling
260 * the signal, it won't be a "send to all threads" type of signal
261 * (according to the POSIX threads spec).
263 if (pthread_self() != startup_guy) {
264 pthread_kill(startup_guy, sig);
268 /* If we're already trying to interrupt the RTS, terminate with
269 * extreme prejudice. So the first ^C tries to exit the program
270 * cleanly, and the second one just kills it.
273 exit(EXIT_INTERRUPTED);
280 * The RTS installs a default signal handler for catching
281 * SIGINT, so that we can perform an orderly shutdown.
283 * Haskell code may install their own SIGINT handler, which is
284 * fine, provided they're so kind as to put back the old one
285 * when they de-install.
288 init_default_handlers()
290 struct sigaction action,oact;
293 startup_guy = pthread_self();
295 action.sa_handler = shutdown_handler;
296 sigemptyset(&action.sa_mask);
298 if (sigaction(SIGINT, &action, &oact) != 0) {
299 /* Oh well, at least we tried. */
300 prog_belch("failed to install SIGINT handler");
304 #endif /*! mingw32_TARGET_OS */