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(osf1_TARGET_OS)
30 /* The include files for OSF1 do not normally define SA_SIGINFO */
31 # define _OSF_SOURCE 1
35 /* SIGVTALRM not avail w/ POSIX_SOURCE, but worse things happen without */
36 /* SIGH: triple SIGH (WDP 95/07) */
42 #if defined(HAVE_SYS_TYPES_H)
43 # include <sys/types.h>
46 #if defined(HAVE_SIGNAL_H)
50 #if defined(HAVE_SIGINFO_H)
51 /* DEC OSF1 seems to need this explicitly. Maybe others do as well? */
57 %************************************************************************
59 \subsection{Stack-check by protected-memory-faulting}
61 %************************************************************************
63 If we are checking stack overflow by page faulting, then we need to be
64 able to install a @SIGSEGV@ handler, preferably one which can
65 determine where the fault occurred, so that we can satisfy ourselves
66 that it really was a stack overflow and not some random segmentation
70 #if STACK_CHECK_BY_PAGE_FAULT
72 extern P_ stks_space; /* Where the stacks live, from SMstacks.lc */
75 SunOS 4.x is too old to have @SA_SIGINFO@ as a flag to @sigaction@, so
76 we use the older @signal@ call instead. This means that we also have
77 to set up the handler to expect a different collection of arguments.
81 # if defined(sunos4_TARGET_OS)
84 segv_handler(sig, code, scp, addr)
86 int code; /* NB: all except first argument are "implementation defined" */
87 struct sigcontext *scp;
90 extern void StackOverflow(STG_NO_ARGS) STG_NORETURN;
92 if (addr >= (caddr_t) stks_space
93 && addr < (caddr_t) (stks_space + RTSflags.GcFlags.stksSize))
97 fprintf(stderr, "Segmentation fault caught, address = %lx\n", (W_) addr);
102 install_segv_handler(void)
104 return ((int) signal(SIGSEGV, segv_handler) == SIG_ERR);
105 /* I think the "== SIG_ERR" is saying "there was no
106 handler for SIGSEGV before this one". WDP 95/12
110 # else /* Not SunOS 4 */
112 # if defined(irix_TARGET_OS)
113 /* certainly BOGUS (WDP 94/05) -- copied from /usr/include/sys/siginfo.h */
114 # define si_addr _data._fault._addr
118 segv_handler(int sig, siginfo_t *sip)
119 /* NB: the second "siginfo_t" argument is not really standard */
123 fprintf(stderr, "Segmentation fault caught, address unknown\n");
125 if (sip->si_addr >= (caddr_t) stks_space
126 && sip->si_addr < (caddr_t) (stks_space + RTSflags.GcFlags.stksSize))
129 fprintf(stderr, "Segmentation fault caught, address = %08lx\n", (W_) sip->si_addr);
135 install_segv_handler(STG_NO_ARGS)
137 struct sigaction action;
139 action.sa_handler = segv_handler;
140 sigemptyset(&action.sa_mask);
141 action.sa_flags = SA_SIGINFO;
143 return sigaction(SIGSEGV, &action, NULL);
146 # endif /* not SunOS 4 */
148 #endif /* STACK_CHECK_BY_PAGE_FAULT */
152 %************************************************************************
154 \subsection{Virtual-timer alarm (for profiling, etc.)}
156 %************************************************************************
158 The timer interrupt is somewhat simpler, and we could probably use
159 sigaction across the board, but since we have committed ourselves to
160 the non-POSIX signal under SunOS 4.1.X, we adopt the same approach
164 #if (defined(PROFILING) || defined(CONCURRENT)) && !defined(GRAN)
169 extern P_ CurrentTSO;
173 vtalrm_handler(int sig)
176 For the parallel world, currentTSO is set if there is any work
177 on the current PE. In this case we DO want to context switch,
178 in case other PEs have sent us messages which must be processed.
181 # if defined(PROFILING) || defined(PAR)
182 static I_ csTicks = 0, pTicks = 0;
184 if (time_profiling) {
185 if (++pTicks % RTSflags.CcFlags.profilerTicks == 0) {
186 # if ! defined(PROFILING)
187 handle_tick_serial();
189 if (RTSflags.CcFlags.doCostCentres >= COST_CENTRES_VERBOSE
190 || RTSflags.ProfFlags.doHeapProfile)
191 handle_tick_serial();
193 handle_tick_noserial();
196 if (++csTicks % RTSflags.CcFlags.ctxtSwitchTicks != 0)
201 if (WaitingThreadsHd != Nil_closure)
202 AwaitEvent(RTSflags.ConcFlags.ctxtSwitchTime);
205 if (PendingSparksTl[REQUIRED_POOL] == PendingSparksLim[REQUIRED_POOL] ||
206 PendingSparksTl[ADVISORY_POOL] == PendingSparksLim[ADVISORY_POOL]) {
208 if (PendingSparksTl[REQUIRED_POOL] == PendingSparksLim[REQUIRED_POOL])
209 PendingSparksTl[REQUIRED_POOL] = PendingSparksBase[REQUIRED_POOL] +
210 SparkLimit[REQUIRED_POOL] / 2;
211 if (PendingSparksTl[ADVISORY_POOL] == PendingSparksLim[ADVISORY_POOL]) {
212 PendingSparksTl[ADVISORY_POOL] = PendingSparksBase[ADVISORY_POOL] +
213 SparkLimit[ADVISORY_POOL] / 2;
214 sparksIgnored += SparkLimit[REQUIRED_POOL] / 2;
218 if (CurrentTSO != NULL ||
220 if (RunnableThreadsHd != Nil_closure ||
222 PendingSparksHd[REQUIRED_POOL] < PendingSparksTl[REQUIRED_POOL] ||
223 PendingSparksHd[ADVISORY_POOL] < PendingSparksTl[ADVISORY_POOL]) {
224 /* ToDo: anything else for GRAN? WDP */
231 # if defined(sunos4_TARGET_OS)
234 install_vtalrm_handler(void)
239 old = signal(SIGVTALRM, vtalrm_handler);
241 if (RTSflags.CcFlags.doCostCentres >= COST_CENTRES_VERBOSE
242 || RTSflags.ProfFlags.doHeapProfile)
243 old = signal(SIGVTALRM, handle_tick_serial);
245 old = signal(SIGVTALRM, handle_tick_noserial);
247 return ((int) old == SIG_ERR);
250 static int vtalrm_mask;
253 blockVtAlrmSignal(STG_NO_ARGS)
255 vtalrm_mask = sigblock(sigmask(SIGVTALRM));
259 unblockVtAlrmSignal(STG_NO_ARGS)
261 (void) sigsetmask(vtalrm_mask);
264 # else /* Not SunOS 4 */
267 install_vtalrm_handler(STG_NO_ARGS)
269 struct sigaction action;
272 action.sa_handler = vtalrm_handler;
274 if (RTSflags.CcFlags.doCostCentres >= COST_CENTRES_VERBOSE
275 || RTSflags.ProfFlags.doHeapProfile)
276 action.sa_handler = handle_tick_serial;
278 action.sa_handler = handle_tick_noserial;
281 sigemptyset(&action.sa_mask);
284 return sigaction(SIGVTALRM, &action, NULL);
288 blockVtAlrmSignal(STG_NO_ARGS)
292 sigemptyset(&signals);
293 sigaddset(&signals, SIGVTALRM);
295 (void) sigprocmask(SIG_BLOCK, &signals, NULL);
299 unblockVtAlrmSignal(STG_NO_ARGS)
303 sigemptyset(&signals);
304 sigaddset(&signals, SIGVTALRM);
306 (void) sigprocmask(SIG_UNBLOCK, &signals, NULL);
309 # endif /* ! SunOS 4 */
311 #endif /* PROFILING || CONCURRENT (but not GRAN) */
315 Signal handling support for user-specified signal handlers. Since we
316 need stable pointers to do this properly, we just refuse to try in the
317 parallel world. Sorry.
324 blockUserSignals(void)
330 unblockUserSignals(void)
336 # ifdef _POSIX_SOURCE
337 sig_install(sig, spi, mask)
340 sig_install(sig, spi)
346 fprintf(stderr,"No signal handling support in a parallel implementation.\n");
354 extern StgPtr deRefStablePointer PROTO((StgStablePtr));
355 extern void freeStablePointer PROTO((I_));
356 extern jmp_buf restart_main;
358 static I_ *handlers = NULL; /* Dynamically grown array of signal handlers */
359 static I_ nHandlers = 0; /* Size of handlers array */
362 more_handlers(I_ sig)
369 if (handlers == NULL)
370 handlers = (I_ *) malloc((sig + 1) * sizeof(I_));
372 handlers = (I_ *) realloc(handlers, (sig + 1) * sizeof(I_));
374 if (handlers == NULL) {
376 fprintf(stderr, "VM exhausted (in more_handlers)\n");
379 for(i = nHandlers; i <= sig; i++)
380 /* Fill in the new slots with default actions */
381 handlers[i] = STG_SIG_DFL;
386 # ifdef _POSIX_SOURCE
389 generic_handler(int sig)
393 SAVE_Hp = SAVE_HpLim; /* Just to be safe */
394 if (! initStacks(&StorageMgrInfo)) {
396 fprintf(stderr, "initStacks failed!\n");
399 TopClosure = deRefStablePointer(handlers[sig]);
400 sigemptyset(&signals);
401 sigaddset(&signals, sig);
402 sigprocmask(SIG_UNBLOCK, &signals, NULL);
403 longjmp(restart_main, sig);
406 static sigset_t userSignals;
407 static sigset_t savedSignals;
410 initUserSignals(void)
412 sigemptyset(&userSignals);
416 blockUserSignals(void)
418 sigprocmask(SIG_SETMASK, &userSignals, &savedSignals);
422 unblockUserSignals(void)
424 sigprocmask(SIG_SETMASK, &savedSignals, NULL);
431 sig_install(sig, spi, mask)
437 struct sigaction action;
440 /* Block the signal until we figure out what to do */
441 /* Count on this to fail if the signal number is invalid */
442 if(sig < 0 || sigemptyset(&signals) || sigaddset(&signals, sig) ||
443 sigprocmask(SIG_BLOCK, &signals, NULL))
448 previous_spi = handlers[sig];
452 handlers[sig] = STG_SIG_IGN;
453 sigdelset(&userSignals, sig);
454 action.sa_handler = SIG_IGN;
458 handlers[sig] = STG_SIG_DFL;
459 sigdelset(&userSignals, sig);
460 action.sa_handler = SIG_DFL;
464 sigaddset(&userSignals, sig);
465 action.sa_handler = generic_handler;
470 action.sa_mask = *mask;
472 sigemptyset(&action.sa_mask);
474 action.sa_flags = sig == SIGCHLD && nocldstop ? SA_NOCLDSTOP : 0;
476 if (sigaction(sig, &action, NULL) || sigprocmask(SIG_UNBLOCK, &signals, NULL)) {
478 freeStablePointer(handlers[sig]);
490 SAVE_Hp = SAVE_HpLim; /* Just to be safe */
491 if (! initStacks(&StorageMgrInfo)) {
493 fprintf(stderr, "initStacks failed!\n");
496 TopClosure = deRefStablePointer(handlers[sig]);
498 longjmp(restart_main, sig);
501 static int userSignals;
502 static int savedSignals;
505 initUserSignals(void)
511 blockUserSignals(void)
513 savedSignals = sigsetmask(userSignals);
517 unblockUserSignals(void)
519 sigsetmask(savedSignals);
523 sig_install(sig, spi)
529 void (*handler)(int);
531 /* Block the signal until we figure out what to do */
532 /* Count on this to fail if the signal number is invalid */
533 if(sig < 0 || (mask = sigmask(sig)) == 0)
536 mask = sigblock(mask);
540 previous_spi = handlers[sig];
544 handlers[sig] = STG_SIG_IGN;
545 userSignals &= ~sigmask(sig);
550 handlers[sig] = STG_SIG_DFL;
551 userSignals &= ~sigmask(sig);
556 userSignals |= sigmask(sig);
557 handler = generic_handler;
561 if (signal(sig, handler) < 0) {
563 freeStablePointer(handlers[sig]);