1 /* $Header: /Volumes/share2/src/cmucl/cvs2git/cvsroot/src/lisp/interrupt.c,v 1.60 2009/11/02 15:05:07 rtoy Rel $ */
3 /* Interrupt handling magic. */
13 #include "internals.h"
15 #include "interrupt.h"
25 boolean internal_errors_enabled = 0;
27 os_context_t *lisp_interrupt_contexts[MAX_INTERRUPTS];
29 union interrupt_handler interrupt_handlers[NSIG];
30 void (*interrupt_low_level_handlers[NSIG])(HANDLER_ARGS) = {0};
32 static int pending_signal = 0;
33 static siginfo_t pending_code = {0};
34 static sigset_t pending_mask;
35 static boolean maybe_gc_pending = FALSE;
38 /****************************************************************\
39 * Utility routines used by various signal handlers. *
40 \****************************************************************/
43 build_fake_control_stack_frame(os_context_t * context)
45 #if !(defined(i386) || defined(__x86_64))
48 /* Build a fake stack frame */
49 current_control_frame_pointer = (lispobj *) SC_REG(context, reg_CSP);
50 if ((lispobj *) SC_REG(context, reg_CFP) == current_control_frame_pointer) {
51 /* There is a small window during call where the callee's frame */
52 /* isn't built yet. */
53 if (LowtagOf(SC_REG(context, reg_CODE)) == type_FunctionPointer) {
54 /* We have called, but not built the new frame, so
56 current_control_frame_pointer[0] = SC_REG(context, reg_OCFP);
57 current_control_frame_pointer[1] = SC_REG(context, reg_LRA);
58 current_control_frame_pointer += 8;
59 /* Build our frame on top of it. */
60 oldcont = (lispobj) SC_REG(context, reg_CFP);
62 /* We haven't yet called, build our frame as if the
63 partial frame wasn't there. */
64 oldcont = (lispobj) SC_REG(context, reg_OCFP);
67 /* ### We can't tell if we are still in the caller if it had to
68 reg_ALLOCate the stack frame due to stack arguments. */
69 /* ### Can anything strange happen during return? */
73 oldcont = (lispobj) SC_REG(context, reg_CFP);
76 current_control_stack_pointer = current_control_frame_pointer + 8;
78 current_control_frame_pointer[0] = oldcont;
79 current_control_frame_pointer[1] = NIL;
80 current_control_frame_pointer[2] = (lispobj) SC_REG(context, reg_CODE);
85 fake_foreign_function_call(os_context_t * context)
89 /* Get current LISP state from context */
91 current_dynamic_space_free_pointer = (lispobj *) SC_REG(context, reg_ALLOC);
93 if ((long) current_dynamic_space_free_pointer & 1) {
94 printf("Dead in fake_foriegn_function-call, context = %x\n", context);
100 current_binding_stack_pointer = (lispobj *) SC_REG(context, reg_BSP);
103 build_fake_control_stack_frame(context);
105 /* Do dynamic binding of the active interrupt context index
106 and save the context in the context array. */
107 context_index = SymbolValue(FREE_INTERRUPT_CONTEXT_INDEX) >> 2;
109 if (context_index >= MAX_INTERRUPTS) {
111 "Maximum number (%d) of interrupts exceeded. Exiting.\n",
116 bind_variable(FREE_INTERRUPT_CONTEXT_INDEX, make_fixnum(context_index + 1));
118 lisp_interrupt_contexts[context_index] = context;
120 /* No longer in Lisp now. */
121 foreign_function_call_active = 1;
125 undo_fake_foreign_function_call(os_context_t * context)
127 /* Block all blockable signals */
131 FILLBLOCKSET(&block);
132 sigprocmask(SIG_BLOCK, &block, 0);
134 /* Going back into lisp. */
135 foreign_function_call_active = 0;
137 /* Undo dynamic binding. */
138 /* ### Do I really need to unbind_to_here()? */
142 /* Put the dynamic space free pointer back into the context. */
143 SC_REG(context, reg_ALLOC) =
144 (unsigned long) current_dynamic_space_free_pointer;
149 interrupt_internal_error(HANDLER_ARGS, boolean continuable)
151 ucontext_t *ucontext = (ucontext_t *) context;
152 lispobj context_sap = NIL;
154 fake_foreign_function_call(context);
156 /* Allocate the SAP object while the interrupts are still disabled. */
157 if (internal_errors_enabled)
158 context_sap = alloc_sap(context);
160 sigprocmask(SIG_SETMASK, &ucontext->uc_sigmask, 0);
162 if (internal_errors_enabled)
163 funcall2(SymbolFunction(INTERNAL_ERROR), context_sap,
164 continuable ? T : NIL);
166 internal_error(context);
167 undo_fake_foreign_function_call(context);
169 arch_skip_instruction(context);
173 copy_sigmask(sigset_t *dst, sigset_t *src)
178 memcpy(dst, src, NSIG / CHAR_BIT);
183 interrupt_handle_pending(os_context_t * context)
186 boolean were_in_lisp = !foreign_function_call_active;
189 SetSymbolValue(INTERRUPT_PENDING, NIL);
191 if (maybe_gc_pending) {
192 maybe_gc_pending = FALSE;
196 fake_foreign_function_call(context);
197 funcall0(SymbolFunction(MAYBE_GC));
201 undo_fake_foreign_function_call(context);
204 copy_sigmask(&context->uc_sigmask, &pending_mask);
205 sigemptyset(&pending_mask);
207 if (pending_signal) {
211 signal = pending_signal;
214 /* pending_code = 0; */
215 interrupt_handle_now(signal, &code, context);
220 /****************************************************************\
221 * interrupt_handle_now_handler, maybe_now_maybe_later *
222 * the two main signal handlers. *
223 * interrupt_handle_now *
224 * is called from those to do the real work, but isn't itself *
226 \****************************************************************/
229 interrupt_handle_now_handler(HANDLER_ARGS)
231 interrupt_handle_now(signal, code, context);
233 #if defined(DARWIN) && defined(__ppc__)
234 /* Work around G5 bug; fix courtesy gbyers via chandler */
240 interrupt_handle_now(HANDLER_ARGS)
243 ucontext_t *ucontext = (ucontext_t *) context;
244 union interrupt_handler handler;
246 handler = interrupt_handlers[signal];
248 RESTORE_FPU(context);
250 if (handler.c == (void (*)(HANDLER_ARGS)) SIG_IGN)
254 /**/ were_in_lisp = !foreign_function_call_active;
255 #if ! (defined(i386) || defined(_x86_64))
258 fake_foreign_function_call(context);
260 if (handler.c == (void (*)(HANDLER_ARGS)) SIG_DFL)
261 /* This can happen if someone tries to ignore or default on one of the */
262 /* signals we need for runtime support, and the runtime support */
263 /* decides to pass on it. */
264 lose("interrupt_handle_now: No handler for signal %d?\n", signal);
265 else if (LowtagOf(handler.lisp) == type_FunctionPointer) {
266 /* Allocate the SAP object while the interrupts are still
268 lispobj context_sap = alloc_sap(context);
270 /* Allow signals again. */
271 sigprocmask(SIG_SETMASK, &ucontext->uc_sigmask, 0);
274 funcall3(handler.lisp, make_fixnum(signal), make_fixnum(CODE(code)),
277 funcall3(handler.lisp, make_fixnum(signal), alloc_sap(code),
281 /* Allow signals again. */
282 sigprocmask(SIG_SETMASK, &ucontext->uc_sigmask, 0);
284 (*handler.c) (signal, code, context);
287 #if !(defined(i386) || defined(__x86_64))
290 undo_fake_foreign_function_call(context);
294 setup_pending_signal(HANDLER_ARGS)
296 ucontext_t *ucontext = (ucontext_t *) context;
297 pending_signal = signal;
299 * Note: We used to set pending_code = *code. This doesn't work
300 * very well on Solaris since code is sometimes NULL. AFAICT, we
301 * only care about the si_code value, so just get the si_code
302 * value. The CODE macro does something appropriate when code is
305 * A look at the Lisp handlers shows that the code value is
309 pending_code.si_code = CODE(code);
310 copy_sigmask(&pending_mask, &ucontext->uc_sigmask);
311 FILLBLOCKSET(&ucontext->uc_sigmask);
315 maybe_now_maybe_later(HANDLER_ARGS)
318 if (SymbolValue(INTERRUPTS_ENABLED) == NIL) {
319 setup_pending_signal(signal, code, context);
320 SetSymbolValue(INTERRUPT_PENDING, T);
322 #if !(defined(i386) || defined(__x86_64))
323 (!foreign_function_call_active) &&
325 arch_pseudo_atomic_atomic(context)) {
326 setup_pending_signal(signal, code, context);
327 arch_set_pseudo_atomic_interrupted(context);
329 RESTORE_FPU(context);
330 interrupt_handle_now(signal, code, context);
333 #if defined(DARWIN) && defined(__ppc__)
334 /* Work around G5 bug; fix courtesy gbyers via chandler */
339 /****************************************************************\
340 * Stuff to detect and handle hitting the gc trigger. *
341 \****************************************************************/
343 #ifndef INTERNAL_GC_TRIGGER
345 gc_trigger_hit(HANDLER_ARGS)
347 if (current_auto_gc_trigger == NULL) {
350 lispobj *badaddr = (lispobj *) arch_get_bad_addr(signal, code, context);
354 "gc_trigger_hit: badaddr=%p, current_auto_gc_trigger=%p, limit=%p\n",
355 badaddr, current_auto_gc_trigger,
356 current_dynamic_space + dynamic_space_size);
358 return (badaddr >= current_auto_gc_trigger &&
359 (unsigned long) badaddr <
360 (unsigned long) current_dynamic_space +
361 (unsigned long) dynamic_space_size);
366 #if !(defined(i386) || defined(__x86_64) || defined(GENCGC))
368 interrupt_maybe_gc(HANDLER_ARGS)
370 if (!foreign_function_call_active
371 #ifndef INTERNAL_GC_TRIGGER
372 && gc_trigger_hit(signal, code, context)
375 #ifndef INTERNAL_GC_TRIGGER
376 clear_auto_gc_trigger();
379 if (arch_pseudo_atomic_atomic(context)) {
380 maybe_gc_pending = TRUE;
381 if (pending_signal == 0) {
382 copy_sigmask(&pending_mask, &context->uc_sigmask);
383 FILLBLOCKSET(&context->uc_sigmask);
385 arch_set_pseudo_atomic_interrupted(context);
387 fake_foreign_function_call(context);
388 funcall0(SymbolFunction(MAYBE_GC));
389 undo_fake_foreign_function_call(context);
398 /****************************************************************\
399 * Noise to install handlers. *
400 \****************************************************************/
402 #if !(defined(i386) || defined(__x86_64))
403 #define SIGNAL_STACK_SIZE SIGSTKSZ
404 static char altstack[SIGNAL_STACK_SIZE];
408 interrupt_install_low_level_handler(int signal, void handler(HANDLER_ARGS))
412 sa.sa_sigaction = (void (*)(HANDLER_ARGS)) handler;
413 sigemptyset(&sa.sa_mask);
414 FILLBLOCKSET(&sa.sa_mask);
415 sa.sa_flags = SA_RESTART | SA_SIGINFO;
417 /* Deliver protection violations on a dedicated signal stack,
418 because, when we get that signal because of hitting a control
419 stack guard zone, it's not a good idea to use more of the
420 control stack for handling the signal. */
421 /* But we only need this on x86 since the Lisp control stack and the
422 C control stack are the same. For others, they're separate so
423 the C stack can still be used. */
425 if (signal == PROTECTION_VIOLATION_SIGNAL) {
428 #if (defined( i386 ) || defined(__x86_64))
429 sigstack.ss_sp = (void *) SIGNAL_STACK_START;
431 sigstack.ss_sp = (void *) altstack;
433 sigstack.ss_flags = 0;
434 sigstack.ss_size = SIGNAL_STACK_SIZE;
435 if (sigaltstack(&sigstack, 0) == -1)
436 perror("sigaltstack");
437 sa.sa_flags |= SA_ONSTACK;
439 #endif /* RED_ZONE_HIT */
441 sigaction(signal, &sa, NULL);
444 if (handler == (void (*)(HANDLER_ARGS)) SIG_DFL)
445 interrupt_low_level_handlers[signal] = 0;
447 interrupt_low_level_handlers[signal] = handler;
451 install_handler(int signal, void handler(HANDLER_ARGS))
455 union interrupt_handler oldhandler;
458 sigaddset(&new, signal);
459 sigprocmask(SIG_BLOCK, &new, &old);
464 if (interrupt_low_level_handlers[signal] == 0) {
465 if (handler == (void (*)(HANDLER_ARGS)) SIG_DFL
466 || handler == (void (*)(HANDLER_ARGS)) SIG_IGN)
467 sa.sa_sigaction = (void (*)(HANDLER_ARGS)) handler;
468 else if (sigismember(&new, signal))
469 sa.sa_sigaction = (void (*)(HANDLER_ARGS)) maybe_now_maybe_later;
471 sa.sa_sigaction = (void (*)(HANDLER_ARGS)) interrupt_handle_now_handler;
473 sigemptyset(&sa.sa_mask);
474 FILLBLOCKSET(&sa.sa_mask);
475 sa.sa_flags = SA_SIGINFO | SA_RESTART;
477 sigaction(signal, &sa, NULL);
480 oldhandler = interrupt_handlers[signal];
481 interrupt_handlers[signal].c = handler;
483 sigprocmask(SIG_SETMASK, &old, 0);
485 return (unsigned long) oldhandler.lisp;
488 #ifdef FEATURE_HEAP_OVERFLOW_CHECK
490 interrupt_handle_space_overflow(lispobj error, os_context_t * context)
492 #if defined(i386) || defined(__x86_64)
493 SC_PC(context) = (int) ((struct function *) PTR(error))->code;
494 SC_REG(context, reg_NARGS) = 0;
496 build_fake_control_stack_frame(context);
497 /* This part should be common to all non-x86 ports */
498 SC_PC(context) = (long) ((struct function *) PTR(error))->code;
499 SC_NPC(context) = SC_PC(context) + 4;
500 SC_REG(context, reg_NARGS) = 0;
501 SC_REG(context, reg_LIP) = (long) ((struct function *) PTR(error))->code;
502 SC_REG(context, reg_CFP) = (long) current_control_frame_pointer;
503 /* This is sparc specific */
504 SC_REG(context, reg_CODE) = ((long) PTR(error)) + type_FunctionPointer;
506 * Restore important Lisp regs. Are there others we need to
509 SC_REG(context, reg_ALLOC) = (long) current_dynamic_space_free_pointer;
510 SC_REG(context, reg_NIL) = NIL;
512 #error interrupt_handle_space_overflow not implemented for this system
515 #endif /* FEATURE_HEAP_OVERFLOW_CHECK */
522 for (i = 0; i < NSIG; i++)
523 interrupt_handlers[i].c = (void (*)(HANDLER_ARGS)) SIG_DFL;