2 % (c) The AQUA Project, Glasgow University, 1995
4 %************************************************************************
6 \section[Signals.lc]{Signal Handlers}
8 %************************************************************************
10 There are two particular signals that we find interesting in the RTS:
11 segmentation faults (for cheap stack overflow checks) and virtual
12 timer alarms (for profiling and thread context switching). POSIX
13 compliance is supposed to make this kind of thing easy, but it
14 doesn't. Expect every new target platform to require gory hacks to
15 get this stuff to work.
17 Then, there are the user-specified signal handlers to cope with.
18 Since they're pretty rudimentary, they shouldn't actually cause as
25 #if defined(sunos4_TARGET_OS)
26 /* The sigaction in SunOS 4.1.X does not grok SA_SIGINFO */
27 # define NON_POSIX_SOURCE
30 #if defined(osf1_TARGET_OS)
31 /* The include files for OSF1 do not normally define SA_SIGINFO */
32 # define _OSF_SOURCE 1
35 #if defined(linuxaout_TARGET_OS) || defined(linux_TARGET_OS)
36 /* I have no idea why this works (WDP 95/03) */
37 # define _BSD_SOURCE 1
42 #if defined(HAVE_SYS_TYPES_H)
43 # include <sys/types.h>
46 #if defined(HAVE_SIGNAL_H)
50 /* SIGVTALRM not avail w/ POSIX_SOURCE, but worse things happen without */
51 /* SIGH: triple SIGH (WDP 95/07) */
55 #if defined(HAVE_SIGINFO_H)
56 /* DEC OSF1 seems to need this explicitly. Maybe others do as well? */
62 %************************************************************************
64 \subsection{Stack-check by protected-memory-faulting}
66 %************************************************************************
68 If we are checking stack overflow by page faulting, then we need to be
69 able to install a @SIGSEGV@ handler, preferably one which can
70 determine where the fault occurred, so that we can satisfy ourselves
71 that it really was a stack overflow and not some random segmentation
76 #if STACK_CHECK_BY_PAGE_FAULT
78 extern P_ stks_space; /* Where the stacks live, from SMstacks.lc */
79 extern I_ SM_word_stk_size; /* How big they are (ditto) */
83 SunOS 4.x is too old to have @SA_SIGINFO@ as a flag to @sigaction@, so
84 we use the older @signal@ call instead. This means that we also have
85 to set up the handler to expect a different collection of arguments.
90 # if defined(sunos4_TARGET_OS) || defined(linuxaout_TARGET_OS) || defined(linux_TARGET_OS)
93 segv_handler(sig, code, scp, addr)
96 struct sigcontext *scp;
99 extern void StackOverflow(STG_NO_ARGS) STG_NORETURN;
101 if (addr >= (caddr_t) stks_space
102 && addr < (caddr_t) (stks_space + SM_word_stk_size))
106 fprintf(stderr, "Segmentation fault caught, address = %lx\n", (W_) addr);
111 install_segv_handler()
113 return (int) signal(SIGSEGV, segv_handler) == -1;
116 # else /* Not SunOS 4 */
118 # if defined(irix_TARGET_OS)
119 /* certainly BOGUS (WDP 94/05) -- copied from /usr/include/sys/siginfo.h */
120 # define si_addr _data._fault._addr
124 segv_handler(sig, sip)
130 fprintf(stderr, "Segmentation fault caught, address unknown\n");
132 if (sip->si_addr >= (caddr_t) stks_space
133 && sip->si_addr < (caddr_t) (stks_space + SM_word_stk_size))
136 fprintf(stderr, "Segmentation fault caught, address = %08lx\n", (W_) sip->si_addr);
142 install_segv_handler()
144 struct sigaction action;
146 action.sa_handler = segv_handler;
147 sigemptyset(&action.sa_mask);
148 action.sa_flags = SA_SIGINFO;
149 return sigaction(SIGSEGV, &action, NULL);
152 # endif /* not SunOS 4 */
154 #endif /* STACK_CHECK_BY_PAGE_FAULT */
158 %************************************************************************
160 \subsection{Virtual-timer alarm (for profiling, etc.)}
162 %************************************************************************
164 The timer interrupt is somewhat simpler, and we could probably use
165 sigaction across the board, but since we have committed ourselves to
166 the non-POSIX signal under SunOS 4.1.X, we adopt the same approach
170 #if (defined(USE_COST_CENTRES) || defined(CONCURRENT)) && !defined(GRAN)
172 # if defined(USE_COST_CENTRES)
173 extern I_ heap_profiling_req;
178 # if defined(USE_COST_CENTRES) || defined(GUM)
179 I_ contextSwitchTicks;
184 extern P_ CurrentTSO;
186 extern I_ contextSwitchTime;
193 For the parallel world, currentTSO is set if there is any work
194 on the current PE. In this case we DO want to context switch,
195 in case other PEs have sent us messages which must be processed.
198 # if defined(USE_COST_CENTRES) || defined(GUM)
199 static I_ csTicks = 0, pTicks = 0;
201 if (time_profiling) {
202 if (++pTicks % profilerTicks == 0) {
203 # if ! defined(USE_COST_CENTRES)
204 handle_tick_serial();
206 if (cc_profiling > 1 || heap_profiling_req != HEAP_NO_PROFILING)
207 handle_tick_serial();
209 handle_tick_noserial();
212 if (++csTicks % contextSwitchTicks != 0)
217 if (WaitingThreadsHd != Nil_closure)
218 AwaitEvent(contextSwitchTime);
221 if (PendingSparksTl[REQUIRED_POOL] == PendingSparksLim[REQUIRED_POOL] ||
222 PendingSparksTl[ADVISORY_POOL] == PendingSparksLim[ADVISORY_POOL]) {
224 if (PendingSparksTl[REQUIRED_POOL] == PendingSparksLim[REQUIRED_POOL])
225 PendingSparksTl[REQUIRED_POOL] = PendingSparksBase[REQUIRED_POOL] +
226 SparkLimit[REQUIRED_POOL] / 2;
227 if (PendingSparksTl[ADVISORY_POOL] == PendingSparksLim[ADVISORY_POOL])
228 PendingSparksTl[ADVISORY_POOL] = PendingSparksBase[ADVISORY_POOL] +
229 SparkLimit[ADVISORY_POOL] / 2;
232 if (CurrentTSO != NULL ||
234 if (RunnableThreadsHd != Nil_closure ||
236 PendingSparksHd[REQUIRED_POOL] < PendingSparksTl[REQUIRED_POOL] ||
237 PendingSparksHd[ADVISORY_POOL] < PendingSparksTl[ADVISORY_POOL]) {
238 /* ToDo: anything else for GRAN? WDP */
245 # if defined(sunos4_TARGET_OS) || defined(linuxaout_TARGET_OS) || defined(linux_TARGET_OS)
248 install_vtalrm_handler()
253 old = signal(SIGVTALRM, vtalrm_handler);
255 if (cc_profiling > 1 || heap_profiling_req != HEAP_NO_PROFILING)
256 old = signal(SIGVTALRM, handle_tick_serial);
258 old = signal(SIGVTALRM, handle_tick_noserial);
260 return (int) old == -1;
263 static int vtalrm_mask;
266 blockVtAlrmSignal(STG_NO_ARGS)
268 vtalrm_mask = sigblock(sigmask(SIGVTALRM));
272 unblockVtAlrmSignal(STG_NO_ARGS)
274 (void) sigsetmask(vtalrm_mask);
277 # else /* Not SunOS 4 */
280 install_vtalrm_handler(STG_NO_ARGS)
282 struct sigaction action;
285 action.sa_handler = vtalrm_handler;
287 if (cc_profiling > 1 || heap_profiling_req != HEAP_NO_PROFILING)
288 action.sa_handler = handle_tick_serial;
290 action.sa_handler = handle_tick_noserial;
293 sigemptyset(&action.sa_mask);
296 return sigaction(SIGVTALRM, &action, NULL);
300 blockVtAlrmSignal(STG_NO_ARGS)
304 sigemptyset(&signals);
305 sigaddset(&signals, SIGVTALRM);
307 (void) sigprocmask(SIG_BLOCK, &signals, NULL);
311 unblockVtAlrmSignal(STG_NO_ARGS)
315 sigemptyset(&signals);
316 sigaddset(&signals, SIGVTALRM);
318 (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);
321 # endif /* SunOS 4 */
323 #endif /* USE_COST_CENTRES || CONCURRENT (but not GRAN) */
327 Signal handling support for user-specified signal handlers. Since we
328 need stable pointers to do this properly, we just refuse to try in the
329 parallel world. Sorry.
348 # ifdef _POSIX_SOURCE
349 sig_install(sig, spi, mask)
352 sig_install(sig, spi)
358 fprintf(stderr,"No signal handling support in a parallel implementation.\n");
366 extern StgPtr deRefStablePointer PROTO((StgStablePtr));
367 extern void freeStablePointer PROTO((I_));
368 extern jmp_buf restart_main;
370 static I_ *handlers = NULL; /* Dynamically grown array of signal handlers */
371 static I_ nHandlers = 0; /* Size of handlers array */
382 if (handlers == NULL)
383 handlers = (I_ *) malloc((sig + 1) * sizeof(I_));
385 handlers = (I_ *) realloc(handlers, (sig + 1) * sizeof(I_));
387 if (handlers == NULL) {
389 fprintf(stderr, "VM exhausted\n");
392 for(i = nHandlers; i <= sig; i++)
393 /* Fill in the new slots with default actions */
394 handlers[i] = STG_SIG_DFL;
399 # ifdef _POSIX_SOURCE
406 SAVE_Hp = SAVE_HpLim; /* Just to be safe */
407 if (initStacks(&StorageMgrInfo) != 0) {
409 fprintf(stderr, "initStacks failed!\n");
412 TopClosure = deRefStablePointer(handlers[sig]);
413 sigemptyset(&signals);
414 sigaddset(&signals, sig);
415 sigprocmask(SIG_UNBLOCK, &signals, NULL);
416 longjmp(restart_main, sig);
419 static sigset_t userSignals;
420 static sigset_t savedSignals;
425 sigemptyset(&userSignals);
431 sigprocmask(SIG_SETMASK, &userSignals, &savedSignals);
437 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
444 sig_install(sig, spi, mask)
450 struct sigaction action;
453 /* Block the signal until we figure out what to do */
454 /* Count on this to fail if the signal number is invalid */
455 if(sig < 0 || sigemptyset(&signals) || sigaddset(&signals, sig) ||
456 sigprocmask(SIG_BLOCK, &signals, NULL))
461 previous_spi = handlers[sig];
465 handlers[sig] = STG_SIG_IGN;
466 sigdelset(&userSignals, sig);
467 action.sa_handler = SIG_IGN;
471 handlers[sig] = STG_SIG_DFL;
472 sigdelset(&userSignals, sig);
473 action.sa_handler = SIG_DFL;
477 sigaddset(&userSignals, sig);
478 action.sa_handler = generic_handler;
483 action.sa_mask = *mask;
485 sigemptyset(&action.sa_mask);
487 action.sa_flags = sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
488 if (sigaction(sig, &action, NULL) || sigprocmask(SIG_UNBLOCK, &signals, NULL)) {
490 freeStablePointer(handlers[sig]);
502 SAVE_Hp = SAVE_HpLim; /* Just to be safe */
503 if (initStacks(&StorageMgrInfo) != 0) {
505 fprintf(stderr, "initStacks failed!\n");
508 TopClosure = deRefStablePointer(handlers[sig]);
510 longjmp(restart_main, sig);
513 static int userSignals;
514 static int savedSignals;
525 savedSignals = sigsetmask(userSignals);
531 sigsetmask(savedSignals);
535 sig_install(sig, spi)
543 /* Block the signal until we figure out what to do */
544 /* Count on this to fail if the signal number is invalid */
545 if(sig < 0 || (mask = sigmask(sig)) == 0)
548 mask = sigblock(mask);
552 previous_spi = handlers[sig];
556 handlers[sig] = STG_SIG_IGN;
557 userSignals &= ~sigmask(sig);
562 handlers[sig] = STG_SIG_DFL;
563 userSignals &= ~sigmask(sig);
568 userSignals |= sigmask(sig);
569 handler = generic_handler;
573 if (signal(sig, handler) < 0) {
575 freeStablePointer(handlers[sig]);