1 /* -----------------------------------------------------------------------------
2 * $Id: Signals.c,v 1.2 1998/12/02 13:28:46 simonm Exp $
4 * Signal processing / handling.
6 * ---------------------------------------------------------------------------*/
13 #include "StablePtr.h"
17 static StgInt *handlers = NULL; /* Dynamically grown array of signal handlers */
18 static StgInt nHandlers = 0; /* Size of handlers array */
20 #define N_PENDING_HANDLERS 16
22 StgPtr pending_handler_buf[N_PENDING_HANDLERS];
23 StgPtr *next_pending_handler = pending_handler_buf;
27 /* -----------------------------------------------------------------------------
28 Allocate/resize the table of signal handlers.
29 -------------------------------------------------------------------------- */
40 handlers = (I_ *) malloc((sig + 1) * sizeof(I_));
42 handlers = (I_ *) realloc(handlers, (sig + 1) * sizeof(I_));
44 if (handlers == NULL) {
46 fprintf(stderr, "VM exhausted (in more_handlers)\n");
49 for(i = nHandlers; i <= sig; i++)
50 /* Fill in the new slots with default actions */
51 handlers[i] = STG_SIG_DFL;
56 /* -----------------------------------------------------------------------------
57 Low-level signal handler
59 Places the requested handler on a stack of pending handlers to be
60 started up at the next context switch.
61 -------------------------------------------------------------------------- */
64 generic_handler(int sig)
68 /* Can't call allocate from here. Probably can't call malloc
69 either. However, we have to schedule a new thread somehow.
71 It's probably ok to request a context switch and allow the
72 scheduler to start the handler thread, but how to we
73 communicate this to the scheduler?
75 We need some kind of locking, but with low overhead (i.e. no
76 blocking signals every time around the scheduler).
78 Signal Handlers are atomic (i.e. they can't be interrupted), and
79 we can make use of this. We just need to make sure the
80 critical section of the scheduler can't be interrupted - the
81 only way to do this is to block signals. However, we can lower
82 the overhead by only blocking signals when there are any
83 handlers to run, i.e. the set of pending handlers is
87 /* We use a stack to store the pending signals. We can't
88 dynamically grow this since we can't allocate any memory from
89 within a signal handler.
91 Hence unfortunately we have to bomb out if the buffer
92 overflows. It might be acceptable to carry on in certain
93 circumstances, depending on the signal.
96 *next_pending_handler++ = deRefStablePointer(handlers[sig]);
99 if (next_pending_handler == &pending_handler_buf[N_PENDING_HANDLERS]) {
100 barf("too many pending signals");
103 /* re-establish the signal handler, and carry on */
104 sigemptyset(&signals);
105 sigaddset(&signals, sig);
106 sigprocmask(SIG_UNBLOCK, &signals, NULL);
109 /* -----------------------------------------------------------------------------
110 Blocking/Unblocking of the user signals
111 -------------------------------------------------------------------------- */
113 static sigset_t userSignals;
114 static sigset_t savedSignals;
117 initUserSignals(void)
119 sigemptyset(&userSignals);
123 blockUserSignals(void)
125 sigprocmask(SIG_SETMASK, &userSignals, &savedSignals);
129 unblockUserSignals(void)
131 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
135 /* -----------------------------------------------------------------------------
136 Install a Haskell signal handler.
137 -------------------------------------------------------------------------- */
140 sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
143 struct sigaction action;
146 /* Block the signal until we figure out what to do */
147 /* Count on this to fail if the signal number is invalid */
148 if(sig < 0 || sigemptyset(&signals) || sigaddset(&signals, sig) ||
149 sigprocmask(SIG_BLOCK, &signals, NULL))
154 previous_spi = handlers[sig];
158 handlers[sig] = STG_SIG_IGN;
159 sigdelset(&userSignals, sig);
160 action.sa_handler = SIG_IGN;
164 handlers[sig] = STG_SIG_DFL;
165 sigdelset(&userSignals, sig);
166 action.sa_handler = SIG_DFL;
169 handlers[sig] = (I_)handler;
170 sigaddset(&userSignals, sig);
171 action.sa_handler = generic_handler;
174 barf("sig_install: bad spi");
178 action.sa_mask = *mask;
180 sigemptyset(&action.sa_mask);
182 action.sa_flags = sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
184 if (sigaction(sig, &action, NULL) ||
185 sigprocmask(SIG_UNBLOCK, &signals, NULL))
187 /* need to return an error code, so avoid a stable pointer leak
188 * by freeing the previous handler if there was one.
190 if (previous_spi >= 0) {
191 freeStablePointer(handlers[sig]);
199 /* -----------------------------------------------------------------------------
200 Creating new threads for the pending signal handlers.
201 -------------------------------------------------------------------------- */
204 start_signal_handlers(void)
208 while (next_pending_handler != pending_handler_buf) {
210 next_pending_handler--;
212 /* create*Thread puts the thread on the head of the runnable
213 * queue, hence it will be run next. Poor man's priority
216 createIOThread(RtsFlags.GcFlags.initialStkSize,
217 (StgClosure *) *next_pending_handler);
220 unblockUserSignals();
225 sig_install(StgInt sig, StgInt spi, StgStablePtr handler, sigset_t *mask)
229 "No signal handling support in a parallel implementation.\n");
234 start_signal_handlers(void)