1 /* -----------------------------------------------------------------------------
2 * $Id: Signals.c,v 1.4 1999/02/05 16:02:54 simonm Exp $
4 * (c) The GHC Team, 1998-1999
6 * Signal processing / handling.
8 * ---------------------------------------------------------------------------*/
15 #include "StablePriv.h"
19 static StgInt *handlers = NULL; /* Dynamically grown array of signal handlers */
20 static StgInt nHandlers = 0; /* Size of handlers array */
22 #define N_PENDING_HANDLERS 16
24 StgPtr pending_handler_buf[N_PENDING_HANDLERS];
25 StgPtr *next_pending_handler = pending_handler_buf;
29 /* -----------------------------------------------------------------------------
30 Allocate/resize the table of signal handlers.
31 -------------------------------------------------------------------------- */
42 handlers = (I_ *) malloc((sig + 1) * sizeof(I_));
44 handlers = (I_ *) realloc(handlers, (sig + 1) * sizeof(I_));
46 if (handlers == NULL) {
48 fprintf(stderr, "VM exhausted (in more_handlers)\n");
51 for(i = nHandlers; i <= sig; i++)
52 /* Fill in the new slots with default actions */
53 handlers[i] = STG_SIG_DFL;
58 /* -----------------------------------------------------------------------------
59 Low-level signal handler
61 Places the requested handler on a stack of pending handlers to be
62 started up at the next context switch.
63 -------------------------------------------------------------------------- */
66 generic_handler(int sig)
70 /* Can't call allocate from here. Probably can't call malloc
71 either. However, we have to schedule a new thread somehow.
73 It's probably ok to request a context switch and allow the
74 scheduler to start the handler thread, but how to we
75 communicate this to the scheduler?
77 We need some kind of locking, but with low overhead (i.e. no
78 blocking signals every time around the scheduler).
80 Signal Handlers are atomic (i.e. they can't be interrupted), and
81 we can make use of this. We just need to make sure the
82 critical section of the scheduler can't be interrupted - the
83 only way to do this is to block signals. However, we can lower
84 the overhead by only blocking signals when there are any
85 handlers to run, i.e. the set of pending handlers is
89 /* We use a stack to store the pending signals. We can't
90 dynamically grow this since we can't allocate any memory from
91 within a signal handler.
93 Hence unfortunately we have to bomb out if the buffer
94 overflows. It might be acceptable to carry on in certain
95 circumstances, depending on the signal.
98 *next_pending_handler++ = deRefStablePtr(handlers[sig]);
101 if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
102 barf("too many pending signals");
105 /* re-establish the signal handler, and carry on */
106 sigemptyset(&signals);
107 sigaddset(&signals, sig);
108 sigprocmask(SIG_UNBLOCK, &signals, NULL);
111 /* -----------------------------------------------------------------------------
112 Blocking/Unblocking of the user signals
113 -------------------------------------------------------------------------- */
115 static sigset_t userSignals;
116 static sigset_t savedSignals;
119 initUserSignals(void)
121 sigemptyset(&userSignals);
125 blockUserSignals(void)
127 sigprocmask(SIG_SETMASK, &userSignals, &savedSignals);
131 unblockUserSignals(void)
133 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
137 /* -----------------------------------------------------------------------------
138 Install a Haskell signal handler.
139 -------------------------------------------------------------------------- */
142 sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
145 struct sigaction action;
148 /* Block the signal until we figure out what to do */
149 /* Count on this to fail if the signal number is invalid */
150 if(sig < 0 || sigemptyset(&signals) || sigaddset(&signals, sig) ||
151 sigprocmask(SIG_BLOCK, &signals, NULL))
156 previous_spi = handlers[sig];
160 handlers[sig] = STG_SIG_IGN;
161 sigdelset(&userSignals, sig);
162 action.sa_handler = SIG_IGN;
166 handlers[sig] = STG_SIG_DFL;
167 sigdelset(&userSignals, sig);
168 action.sa_handler = SIG_DFL;
171 handlers[sig] = (I_)handler;
172 sigaddset(&userSignals, sig);
173 action.sa_handler = generic_handler;
176 barf("sig_install: bad spi");
180 action.sa_mask = *mask;
182 sigemptyset(&action.sa_mask);
184 action.sa_flags = sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
186 if (sigaction(sig, &action, NULL) ||
187 sigprocmask(SIG_UNBLOCK, &signals, NULL))
189 /* need to return an error code, so avoid a stable pointer leak
190 * by freeing the previous handler if there was one.
192 if (previous_spi >= 0) {
193 freeStablePtr(handlers[sig]);
201 /* -----------------------------------------------------------------------------
202 Creating new threads for the pending signal handlers.
203 -------------------------------------------------------------------------- */
206 start_signal_handlers(void)
210 while (next_pending_handler != pending_handler_buf) {
212 next_pending_handler--;
214 /* create*Thread puts the thread on the head of the runnable
215 * queue, hence it will be run next. Poor man's priority
218 createIOThread(RtsFlags.GcFlags.initialStkSize,
219 (StgClosure *) *next_pending_handler);
222 unblockUserSignals();
227 sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
231 "No signal handling support in a parallel implementation.\n");
236 start_signal_handlers(void)