1 /* -----------------------------------------------------------------------------
2 * $Id: Signals.c,v 1.7 1999/07/14 13:39:46 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 fprintf(stderr, "VM exhausted (in more_handlers)\n");
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(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(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--;
221 /* create*Thread puts the thread on the head of the runnable
222 * queue, hence it will be run next. Poor man's priority
225 createIOThread(RtsFlags.GcFlags.initialStkSize,
226 (StgClosure *) *next_pending_handler);
229 unblockUserSignals();
234 sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
236 /* don't fflush(stdout); WORKAROUND bug in Linux glibc */
238 "No signal handling support in a parallel implementation.\n");
243 start_signal_handlers(void)
248 #endif /*! mingw32_TARGET_OS */