1 /* -----------------------------------------------------------------------------
2 * $Id: Signals.c,v 1.12 2000/01/13 12:40:16 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--;
220 createIOThread(RtsFlags.GcFlags.initialStkSize,
221 (StgClosure *) *next_pending_handler);
224 unblockUserSignals();
229 sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
231 /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
232 barf("no signal handling support in a parallel implementation");
236 start_signal_handlers(void)
241 /* -----------------------------------------------------------------------------
244 We like to shutdown nicely after receiving a SIGINT, write out the
245 stats, write profiling info, close open files and flush buffers etc.
246 -------------------------------------------------------------------------- */
249 pthread_t startup_guy;
253 shutdown_handler(int sig STG_UNUSED)
256 /* if I'm a worker thread, send this signal to the guy who
257 * originally called startupHaskell(). Since we're handling
258 * the signal, it won't be a "send to all threads" type of signal
259 * (according to the POSIX threads spec).
261 if (pthread_self() != startup_guy) {
262 pthread_kill(startup_guy, sig);
266 shutdownHaskellAndExit(EXIT_INTERRUPTED);
270 * The RTS installs a default signal handler for catching
271 * SIGINT, so that we can perform an orderly shutdown.
273 * Haskell code may install their own SIGINT handler, which is
274 * fine, provided they're so kind as to put back the old one
275 * when they de-install.
278 init_shutdown_handler()
280 struct sigaction action,oact;
283 startup_guy = pthread_self();
285 action.sa_handler = shutdown_handler;
286 sigemptyset(&action.sa_mask);
288 if (sigaction(SIGINT, &action, &oact) != 0) {
289 /* Oh well, at least we tried. */
291 fprintf(stderr, "init_shutdown_handler: failed to reg SIGINT handler");
299 #endif /*! mingw32_TARGET_OS */