1 /* -----------------------------------------------------------------------------
2 * $Id: Signals.c,v 1.16 2000/04/04 10:04:47 simonmar Exp $
4 * (c) The GHC Team, 1998-1999
6 * Signal processing / handling.
8 * ---------------------------------------------------------------------------*/
16 #include "StablePriv.h"
18 #ifndef mingw32_TARGET_OS
22 static StgInt *handlers = NULL; /* Dynamically grown array of signal handlers */
23 static StgInt nHandlers = 0; /* Size of handlers array */
25 #define N_PENDING_HANDLERS 16
27 StgPtr pending_handler_buf[N_PENDING_HANDLERS];
28 StgPtr *next_pending_handler = pending_handler_buf;
32 /* -----------------------------------------------------------------------------
33 Allocate/resize the table of signal handlers.
34 -------------------------------------------------------------------------- */
45 handlers = (I_ *) malloc((sig + 1) * sizeof(I_));
47 handlers = (I_ *) realloc(handlers, (sig + 1) * sizeof(I_));
49 if (handlers == NULL) {
50 /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
51 barf("VM exhausted (in more_handlers)");
53 for(i = nHandlers; i <= sig; i++)
54 /* Fill in the new slots with default actions */
55 handlers[i] = STG_SIG_DFL;
60 /* -----------------------------------------------------------------------------
61 Low-level signal handler
63 Places the requested handler on a stack of pending handlers to be
64 started up at the next context switch.
65 -------------------------------------------------------------------------- */
68 generic_handler(int sig)
72 /* Can't call allocate from here. Probably can't call malloc
73 either. However, we have to schedule a new thread somehow.
75 It's probably ok to request a context switch and allow the
76 scheduler to start the handler thread, but how do we
77 communicate this to the scheduler?
79 We need some kind of locking, but with low overhead (i.e. no
80 blocking signals every time around the scheduler).
82 Signal Handlers are atomic (i.e. they can't be interrupted), and
83 we can make use of this. We just need to make sure the
84 critical section of the scheduler can't be interrupted - the
85 only way to do this is to block signals. However, we can lower
86 the overhead by only blocking signals when there are any
87 handlers to run, i.e. the set of pending handlers is
91 /* We use a stack to store the pending signals. We can't
92 dynamically grow this since we can't allocate any memory from
93 within a signal handler.
95 Hence unfortunately we have to bomb out if the buffer
96 overflows. It might be acceptable to carry on in certain
97 circumstances, depending on the signal.
100 *next_pending_handler++ = deRefStablePtr(handlers[sig]);
103 if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
104 barf("too many pending signals");
107 /* re-establish the signal handler, and carry on */
108 sigemptyset(&signals);
109 sigaddset(&signals, sig);
110 sigprocmask(SIG_UNBLOCK, &signals, NULL);
115 /* -----------------------------------------------------------------------------
116 Blocking/Unblocking of the user signals
117 -------------------------------------------------------------------------- */
119 static sigset_t userSignals;
120 static sigset_t savedSignals;
123 initUserSignals(void)
125 sigemptyset(&userSignals);
129 blockUserSignals(void)
131 sigprocmask(SIG_SETMASK, &userSignals, &savedSignals);
135 unblockUserSignals(void)
137 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
141 /* -----------------------------------------------------------------------------
142 Install a Haskell signal handler.
143 -------------------------------------------------------------------------- */
146 sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
149 struct sigaction action;
152 /* Block the signal until we figure out what to do */
153 /* Count on this to fail if the signal number is invalid */
154 if(sig < 0 || sigemptyset(&signals) || sigaddset(&signals, sig) ||
155 sigprocmask(SIG_BLOCK, &signals, NULL))
160 previous_spi = handlers[sig];
164 handlers[sig] = STG_SIG_IGN;
165 sigdelset(&userSignals, sig);
166 action.sa_handler = SIG_IGN;
170 handlers[sig] = STG_SIG_DFL;
171 sigdelset(&userSignals, sig);
172 action.sa_handler = SIG_DFL;
176 handlers[sig] = (I_)handler;
177 sigaddset(&userSignals, sig);
178 action.sa_handler = generic_handler;
182 barf("sig_install: bad spi");
186 action.sa_mask = *mask;
188 sigemptyset(&action.sa_mask);
190 action.sa_flags = sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
192 if (sigaction(sig, &action, NULL) ||
193 sigprocmask(SIG_UNBLOCK, &signals, NULL))
195 /* need to return an error code, so avoid a stable pointer leak
196 * by freeing the previous handler if there was one.
198 if (previous_spi >= 0) {
199 freeStablePtr(handlers[sig]);
207 /* -----------------------------------------------------------------------------
208 Creating new threads for the pending signal handlers.
209 -------------------------------------------------------------------------- */
212 start_signal_handlers(void)
216 while (next_pending_handler != pending_handler_buf) {
218 next_pending_handler--;
221 createIOThread(RtsFlags.GcFlags.initialStkSize,
222 (StgClosure *) *next_pending_handler));
225 unblockUserSignals();
230 sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
232 /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
233 barf("no signal handling support in a parallel implementation");
237 start_signal_handlers(void)
242 /* -----------------------------------------------------------------------------
245 We like to shutdown nicely after receiving a SIGINT, write out the
246 stats, write profiling info, close open files and flush buffers etc.
247 -------------------------------------------------------------------------- */
250 pthread_t startup_guy;
254 shutdown_handler(int sig STG_UNUSED)
257 /* if I'm a worker thread, send this signal to the guy who
258 * originally called startupHaskell(). Since we're handling
259 * the signal, it won't be a "send to all threads" type of signal
260 * (according to the POSIX threads spec).
262 if (pthread_self() != startup_guy) {
263 pthread_kill(startup_guy, sig);
267 /* If we're already trying to interrupt the RTS, terminate with
268 * extreme prejudice. So the first ^C tries to exit the program
269 * cleanly, and the second one just kills it.
272 exit(EXIT_INTERRUPTED);
279 * The RTS installs a default signal handler for catching
280 * SIGINT, so that we can perform an orderly shutdown.
282 * Haskell code may install their own SIGINT handler, which is
283 * fine, provided they're so kind as to put back the old one
284 * when they de-install.
287 init_default_handlers()
289 struct sigaction action,oact;
292 startup_guy = pthread_self();
294 action.sa_handler = shutdown_handler;
295 sigemptyset(&action.sa_mask);
297 if (sigaction(SIGINT, &action, &oact) != 0) {
298 /* Oh well, at least we tried. */
299 prog_belch("failed to install SIGINT handler");
303 #endif /*! mingw32_TARGET_OS */