1 /* -----------------------------------------------------------------------------
2 * $Id: Signals.c,v 1.5 1999/03/02 20:01:55 sof Exp $
4 * (c) The GHC Team, 1998-1999
6 * Signal processing / handling.
8 * ---------------------------------------------------------------------------*/
15 #include "StablePriv.h"
17 #ifndef mingw32_TARGET_OS
21 static StgInt *handlers = NULL; /* Dynamically grown array of signal handlers */
22 static StgInt nHandlers = 0; /* Size of handlers array */
24 #define N_PENDING_HANDLERS 16
26 StgPtr pending_handler_buf[N_PENDING_HANDLERS];
27 StgPtr *next_pending_handler = pending_handler_buf;
31 /* -----------------------------------------------------------------------------
32 Allocate/resize the table of signal handlers.
33 -------------------------------------------------------------------------- */
44 handlers = (I_ *) malloc((sig + 1) * sizeof(I_));
46 handlers = (I_ *) realloc(handlers, (sig + 1) * sizeof(I_));
48 if (handlers == NULL) {
50 fprintf(stderr, "VM exhausted (in more_handlers)\n");
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 to 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);
113 /* -----------------------------------------------------------------------------
114 Blocking/Unblocking of the user signals
115 -------------------------------------------------------------------------- */
117 static sigset_t userSignals;
118 static sigset_t savedSignals;
121 initUserSignals(void)
123 sigemptyset(&userSignals);
127 blockUserSignals(void)
129 sigprocmask(SIG_SETMASK, &userSignals, &savedSignals);
133 unblockUserSignals(void)
135 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
139 /* -----------------------------------------------------------------------------
140 Install a Haskell signal handler.
141 -------------------------------------------------------------------------- */
144 sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
147 struct sigaction action;
150 /* Block the signal until we figure out what to do */
151 /* Count on this to fail if the signal number is invalid */
152 if(sig < 0 || sigemptyset(&signals) || sigaddset(&signals, sig) ||
153 sigprocmask(SIG_BLOCK, &signals, NULL))
158 previous_spi = handlers[sig];
162 handlers[sig] = STG_SIG_IGN;
163 sigdelset(&userSignals, sig);
164 action.sa_handler = SIG_IGN;
168 handlers[sig] = STG_SIG_DFL;
169 sigdelset(&userSignals, sig);
170 action.sa_handler = SIG_DFL;
173 handlers[sig] = (I_)handler;
174 sigaddset(&userSignals, sig);
175 action.sa_handler = generic_handler;
178 barf("sig_install: bad spi");
182 action.sa_mask = *mask;
184 sigemptyset(&action.sa_mask);
186 action.sa_flags = sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
188 if (sigaction(sig, &action, NULL) ||
189 sigprocmask(SIG_UNBLOCK, &signals, NULL))
191 /* need to return an error code, so avoid a stable pointer leak
192 * by freeing the previous handler if there was one.
194 if (previous_spi >= 0) {
195 freeStablePtr(handlers[sig]);
203 /* -----------------------------------------------------------------------------
204 Creating new threads for the pending signal handlers.
205 -------------------------------------------------------------------------- */
208 start_signal_handlers(void)
212 while (next_pending_handler != pending_handler_buf) {
214 next_pending_handler--;
216 /* create*Thread puts the thread on the head of the runnable
217 * queue, hence it will be run next. Poor man's priority
220 createIOThread(RtsFlags.GcFlags.initialStkSize,
221 (StgClosure *) *next_pending_handler);
224 unblockUserSignals();
229 sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
233 "No signal handling support in a parallel implementation.\n");
238 start_signal_handlers(void)
243 #endif /*! mingw32_TARGET_OS */