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
24 #if defined(sunos4_TARGET_OS)
25 /* The sigaction in SunOS 4.1.X does not grok SA_SIGINFO */
26 # define NON_POSIX_SOURCE
29 #if defined(freebsd_TARGET_OS)
30 # define NON_POSIX_SOURCE
33 #if defined(osf1_TARGET_OS)
34 /* The include files for OSF1 do not normally define SA_SIGINFO */
35 # define _OSF_SOURCE 1
39 /* SIGVTALRM not avail w/ POSIX_SOURCE, but worse things happen without */
40 /* SIGH: triple SIGH (WDP 95/07) */
46 #if defined(HAVE_SYS_TYPES_H)
47 # include <sys/types.h>
50 #if defined(HAVE_SIGNAL_H)
54 #if defined(linux_TARGET_OS) || defined(linuxaout_TARGET_OS)
55 /* to look *inside* sigcontext... */
56 # include <asm/signal.h>
59 #if defined(HAVE_SIGINFO_H)
60 /* DEC OSF1 seems to need this explicitly. Maybe others do as well? */
66 %************************************************************************
68 \subsection{Stack-check by protected-memory-faulting}
70 %************************************************************************
72 If we are checking stack overflow by page faulting, then we need to be
73 able to install a @SIGSEGV@ handler, preferably one which can
74 determine where the fault occurred, so that we can satisfy ourselves
75 that it really was a stack overflow and not some random segmentation
79 #if STACK_CHECK_BY_PAGE_FAULT
81 extern P_ stks_space; /* Where the stacks live, from SMstacks.lc */
84 SunOS 4.x is too old to have @SA_SIGINFO@ as a flag to @sigaction@, so
85 we use the older @signal@ call instead. This means that we also have
86 to set up the handler to expect a different collection of arguments.
90 # if defined(sunos4_TARGET_OS) || defined(freebsd_TARGET_OS) \
91 || defined(linux_TARGET_OS) || defined(linuxaout_TARGET_OS)
95 /* NB: all except first argument are "implementation defined" */
96 # if defined(sunos4_TARGET_OS) || defined(freebsd_TARGET_OS)
97 int code, struct sigcontext *scp, caddr_t addr)
99 struct sigcontext_struct scp)
102 extern void StackOverflow(STG_NO_ARGS) STG_NORETURN;
104 # if defined(linux_TARGET_OS) || defined(linuxaout_TARGET_OS)
105 caddr_t addr = scp.cr2;
106 /* Magic info from Tommy Thorn! */
109 if (addr >= (caddr_t) stks_space
110 && addr < (caddr_t) (stks_space + RTSflags.GcFlags.stksSize))
114 fprintf(stderr, "Segmentation fault caught, address = %lx\n", (W_) addr);
119 install_segv_handler(void)
121 #if freebsd_TARGET_OS
122 /* FreeBSD seems to generate SIGBUS for stack overflows */
123 if (signal(SIGBUS, segv_handler) == SIG_ERR)
125 return ((int) signal(SIGSEGV, segv_handler));
127 return ((int) signal(SIGSEGV, segv_handler) == SIG_ERR);
128 /* I think the "== SIG_ERR" is saying "there was no
129 handler for SIGSEGV before this one". WDP 95/12
134 # else /* Not SunOS 4, FreeBSD, or Linux(a.out) */
136 # if defined(irix_TARGET_OS)
137 /* certainly BOGUS (WDP 94/05) -- copied from /usr/include/sys/siginfo.h */
138 # define si_addr _data._fault._addr
142 segv_handler(int sig, siginfo_t *sip)
143 /* NB: the second "siginfo_t" argument is not really standard */
147 fprintf(stderr, "Segmentation fault caught, address unknown\n");
149 if (sip->si_addr >= (caddr_t) stks_space
150 && sip->si_addr < (caddr_t) (stks_space + RTSflags.GcFlags.stksSize))
153 fprintf(stderr, "Segmentation fault caught, address = %08lx\n", (W_) sip->si_addr);
159 install_segv_handler(STG_NO_ARGS)
161 struct sigaction action;
163 action.sa_handler = segv_handler;
164 sigemptyset(&action.sa_mask);
165 action.sa_flags = SA_SIGINFO;
167 return sigaction(SIGSEGV, &action, NULL);
170 # endif /* not SunOS 4 */
172 #endif /* STACK_CHECK_BY_PAGE_FAULT */
176 %************************************************************************
178 \subsection{Virtual-timer alarm (for profiling, etc.)}
180 %************************************************************************
182 The timer interrupt is somewhat simpler, and we could probably use
183 sigaction across the board, but since we have committed ourselves to
184 the non-POSIX signal under SunOS 4.1.X, we adopt the same approach
188 #if defined(PROFILING) || defined(CONCURRENT) /* && !defined(GRAN) */
192 extern I_ delayTicks;
195 extern P_ CurrentTSO;
199 vtalrm_handler(int sig)
202 For the parallel world, currentTSO is set if there is any work
203 on the current PE. In this case we DO want to context switch,
204 in case other PEs have sent us messages which must be processed.
207 # if defined(PROFILING) || defined(PAR)
208 static I_ csTicks = 0, pTicks = 0;
210 if (time_profiling) {
211 if (++pTicks % RTSflags.CcFlags.profilerTicks == 0) {
212 # if ! defined(PROFILING)
213 handle_tick_serial();
215 if (RTSflags.CcFlags.doCostCentres >= COST_CENTRES_VERBOSE
216 || RTSflags.ProfFlags.doHeapProfile)
217 handle_tick_serial();
219 handle_tick_noserial();
222 if (++csTicks % RTSflags.CcFlags.ctxtSwitchTicks != 0)
228 Handling a tick for threads blocked waiting for file
229 descriptor I/O or time.
231 This requires some care since virtual time alarm ticks
232 can occur when we are in the GC. If that is the case,
233 we just increment a delayed timer tick counter, but do
234 not check to see if any TSOs have been made runnable
235 as a result. (Do a bulk update of their status once
236 the GC has completed).
238 If the vtalrm does not occur within GC, we try to promote
239 any of the waiting threads to the runnable list (see awaitEvent)
244 if (delayTicks != 0) /* delayTicks>0 => don't handle timer expiry (in GC) */
246 else if (WaitingThreadsHd != Prelude_Z91Z93_closure)
247 AwaitEvent(RTSflags.ConcFlags.ctxtSwitchTime);
250 if (PendingSparksTl[REQUIRED_POOL] == PendingSparksLim[REQUIRED_POOL] ||
251 PendingSparksTl[ADVISORY_POOL] == PendingSparksLim[ADVISORY_POOL]) {
253 if (PendingSparksTl[REQUIRED_POOL] == PendingSparksLim[REQUIRED_POOL])
254 PendingSparksTl[REQUIRED_POOL] = PendingSparksBase[REQUIRED_POOL] +
255 SparkLimit[REQUIRED_POOL] / 2;
256 if (PendingSparksTl[ADVISORY_POOL] == PendingSparksLim[ADVISORY_POOL]) {
257 PendingSparksTl[ADVISORY_POOL] = PendingSparksBase[ADVISORY_POOL] +
258 SparkLimit[ADVISORY_POOL] / 2;
259 sparksIgnored += SparkLimit[REQUIRED_POOL] / 2;
263 if (CurrentTSO != NULL ||
265 if (RunnableThreadsHd != Prelude_Z91Z93_closure ||
267 PendingSparksHd[REQUIRED_POOL] < PendingSparksTl[REQUIRED_POOL] ||
268 PendingSparksHd[ADVISORY_POOL] < PendingSparksTl[ADVISORY_POOL]) {
269 /* ToDo: anything else for GRAN? WDP */
276 # if defined(sunos4_TARGET_OS)
279 install_vtalrm_handler(void)
284 old = signal(SIGVTALRM, vtalrm_handler);
286 if (RTSflags.CcFlags.doCostCentres >= COST_CENTRES_VERBOSE
287 || RTSflags.ProfFlags.doHeapProfile)
288 old = signal(SIGVTALRM, handle_tick_serial);
290 old = signal(SIGVTALRM, handle_tick_noserial);
292 return ((int) old == SIG_ERR);
295 static int vtalrm_mask;
298 blockVtAlrmSignal(STG_NO_ARGS)
300 vtalrm_mask = sigblock(sigmask(SIGVTALRM));
304 unblockVtAlrmSignal(STG_NO_ARGS)
306 (void) sigsetmask(vtalrm_mask);
309 # else /* Not SunOS 4 */
312 install_vtalrm_handler(STG_NO_ARGS)
314 struct sigaction action;
317 action.sa_handler = vtalrm_handler;
319 if (RTSflags.CcFlags.doCostCentres >= COST_CENTRES_VERBOSE
320 || RTSflags.ProfFlags.doHeapProfile)
321 action.sa_handler = handle_tick_serial;
323 action.sa_handler = handle_tick_noserial;
326 sigemptyset(&action.sa_mask);
329 return sigaction(SIGVTALRM, &action, NULL);
333 blockVtAlrmSignal(STG_NO_ARGS)
337 sigemptyset(&signals);
338 sigaddset(&signals, SIGVTALRM);
340 (void) sigprocmask(SIG_BLOCK, &signals, NULL);
344 unblockVtAlrmSignal(STG_NO_ARGS)
348 sigemptyset(&signals);
349 sigaddset(&signals, SIGVTALRM);
351 (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);
354 # endif /* ! SunOS 4 */
356 #endif /* PROFILING || CONCURRENT (but not GRAN) */
360 Signal handling support for user-specified signal handlers. Since we
361 need stable pointers to do this properly, we just refuse to try in the
362 parallel world. Sorry.
366 #if defined(PAR) /* || defined(GRAN) */
369 blockUserSignals(void)
375 unblockUserSignals(void)
381 # ifdef _POSIX_SOURCE
382 sig_install(sig, spi, mask)
385 sig_install(sig, spi)
391 fprintf(stderr,"No signal handling support in a parallel implementation.\n");
399 StgPtr deRefStablePointer PROTO((StgStablePtr));
400 void freeStablePointer PROTO((I_));
401 extern jmp_buf restart_main;
403 static I_ *handlers = NULL; /* Dynamically grown array of signal handlers */
404 static I_ nHandlers = 0; /* Size of handlers array */
407 more_handlers(I_ sig)
414 if (handlers == NULL)
415 handlers = (I_ *) malloc((sig + 1) * sizeof(I_));
417 handlers = (I_ *) realloc(handlers, (sig + 1) * sizeof(I_));
419 if (handlers == NULL) {
421 fprintf(stderr, "VM exhausted (in more_handlers)\n");
424 for(i = nHandlers; i <= sig; i++)
425 /* Fill in the new slots with default actions */
426 handlers[i] = STG_SIG_DFL;
431 # ifdef _POSIX_SOURCE
434 generic_handler(int sig)
438 SAVE_Hp = SAVE_HpLim; /* Just to be safe */
439 if (! initStacks(&StorageMgrInfo)) {
441 fprintf(stderr, "initStacks failed!\n");
444 TopClosure = deRefStablePointer(handlers[sig]);
445 sigemptyset(&signals);
446 sigaddset(&signals, sig);
447 sigprocmask(SIG_UNBLOCK, &signals, NULL);
448 longjmp(restart_main, sig);
451 static sigset_t userSignals;
452 static sigset_t savedSignals;
455 initUserSignals(void)
457 sigemptyset(&userSignals);
461 blockUserSignals(void)
463 sigprocmask(SIG_SETMASK, &userSignals, &savedSignals);
467 unblockUserSignals(void)
469 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
476 sig_install(sig, spi, mask)
482 struct sigaction action;
485 /* Block the signal until we figure out what to do */
486 /* Count on this to fail if the signal number is invalid */
487 if(sig < 0 || sigemptyset(&signals) || sigaddset(&signals, sig) ||
488 sigprocmask(SIG_BLOCK, &signals, NULL))
493 previous_spi = handlers[sig];
497 handlers[sig] = STG_SIG_IGN;
498 sigdelset(&userSignals, sig);
499 action.sa_handler = SIG_IGN;
503 handlers[sig] = STG_SIG_DFL;
504 sigdelset(&userSignals, sig);
505 action.sa_handler = SIG_DFL;
509 sigaddset(&userSignals, sig);
510 action.sa_handler = generic_handler;
515 action.sa_mask = *mask;
517 sigemptyset(&action.sa_mask);
519 action.sa_flags = sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
521 if (sigaction(sig, &action, NULL) || sigprocmask(SIG_UNBLOCK, &signals, NULL)) {
523 freeStablePointer(handlers[sig]);
535 SAVE_Hp = SAVE_HpLim; /* Just to be safe */
536 if (! initStacks(&StorageMgrInfo)) {
538 fprintf(stderr, "initStacks failed!\n");
541 TopClosure = deRefStablePointer(handlers[sig]);
543 longjmp(restart_main, sig);
546 static int userSignals;
547 static int savedSignals;
550 initUserSignals(void)
556 blockUserSignals(void)
558 savedSignals = sigsetmask(userSignals);
562 unblockUserSignals(void)
564 sigsetmask(savedSignals);
568 sig_install(sig, spi)
574 void (*handler)(int);
576 /* Block the signal until we figure out what to do */
577 /* Count on this to fail if the signal number is invalid */
578 if(sig < 0 || (mask = sigmask(sig)) == 0)
581 mask = sigblock(mask);
585 previous_spi = handlers[sig];
589 handlers[sig] = STG_SIG_IGN;
590 userSignals &= ~sigmask(sig);
595 handlers[sig] = STG_SIG_DFL;
596 userSignals &= ~sigmask(sig);
601 userSignals |= sigmask(sig);
602 handler = generic_handler;
606 if (signal(sig, handler) < 0) {
608 freeStablePointer(handlers[sig]);