2 * interrupt-handling magic
6 * This software is part of the SBCL system. See the README file for
9 * This software is derived from the CMU CL system, which was
10 * written at Carnegie Mellon University and released into the
11 * public domain. The software is in the public domain and is
12 * provided with absolutely no warranty. See the COPYING and CREDITS
13 * files for more information.
17 /* As far as I can tell, what's going on here is:
19 * In the case of most signals, when Lisp asks us to handle the
20 * signal, the outermost handler (the one actually passed to UNIX) is
21 * either interrupt_handle_now(..) or maybe_now_maybe_later(..).
22 * In that case, the Lisp-level handler is stored in interrupt_handlers[..]
23 * and interrupt_low_level_handlers[..] is cleared.
25 * However, some signals need special handling, e.g.
27 * o the SIGSEGV (for e.g. Linux) or SIGBUS (for e.g. FreeBSD) used by the
28 * garbage collector to detect violations of write protection,
29 * because some cases of such signals (e.g. GC-related violations of
30 * write protection) are handled at C level and never passed on to
31 * Lisp. For such signals, we still store any Lisp-level handler
32 * in interrupt_handlers[..], but for the outermost handle we use
33 * the value from interrupt_low_level_handlers[..], instead of the
34 * ordinary interrupt_handle_now(..) or interrupt_handle_later(..).
36 * o the SIGTRAP (Linux/Alpha) which Lisp code uses to handle breakpoints,
37 * pseudo-atomic sections, and some classes of error (e.g. "function
38 * not defined"). This never goes anywhere near the Lisp handlers at all.
39 * See runtime/alpha-arch.c and code/signal.lisp
41 * - WHN 20000728, dan 20010128 */
48 #include <sys/types.h>
55 #include "interrupt.h"
64 #include "genesis/fdefn.h"
65 #include "genesis/simple-fun.h"
69 void run_deferred_handler(struct interrupt_data *data, void *v_context) ;
70 static void store_signal_data_for_later (struct interrupt_data *data,
71 void *handler, int signal,
73 os_context_t *context);
74 boolean interrupt_maybe_gc_int(int signal, siginfo_t *info, void *v_context);
76 extern volatile lispobj all_threads_lock;
79 * This is a workaround for some slightly silly Linux/GNU Libc
80 * behaviour: glibc defines sigset_t to support 1024 signals, which is
81 * more than the kernel. This is usually not a problem, but becomes
82 * one when we want to save a signal mask from a ucontext, and restore
83 * it later into another ucontext: the ucontext is allocated on the
84 * stack by the kernel, so copying a libc-sized sigset_t into it will
85 * overflow and cause other data on the stack to be corrupted */
87 #define REAL_SIGSET_SIZE_BYTES ((NSIG/8))
89 void sigaddset_blockable(sigset_t *s)
93 sigaddset(s, SIGQUIT);
94 sigaddset(s, SIGPIPE);
95 sigaddset(s, SIGALRM);
98 sigaddset(s, SIGTSTP);
99 sigaddset(s, SIGCHLD);
101 sigaddset(s, SIGXCPU);
102 sigaddset(s, SIGXFSZ);
103 sigaddset(s, SIGVTALRM);
104 sigaddset(s, SIGPROF);
105 sigaddset(s, SIGWINCH);
106 sigaddset(s, SIGUSR1);
107 sigaddset(s, SIGUSR2);
108 #ifdef LISP_FEATURE_SB_THREAD
109 sigaddset(s, SIG_STOP_FOR_GC);
110 sigaddset(s, SIG_INTERRUPT_THREAD);
111 sigaddset(s, SIG_THREAD_EXIT);
115 /* When we catch an internal error, should we pass it back to Lisp to
116 * be handled in a high-level way? (Early in cold init, the answer is
117 * 'no', because Lisp is still too brain-dead to handle anything.
118 * After sufficient initialization has been completed, the answer
120 boolean internal_errors_enabled = 0;
122 struct interrupt_data * global_interrupt_data;
124 /* At the toplevel repl we routinely call this function. The signal
125 * mask ought to be clear anyway most of the time, but may be non-zero
126 * if we were interrupted e.g. while waiting for a queue. */
129 void reset_signal_mask ()
133 sigprocmask(SIG_SETMASK,&new,0);
136 void reset_signal_mask ()
142 sigprocmask(SIG_SETMASK,&new,&old);
143 for(i=1; i<NSIG; i++) {
144 if(sigismember(&old,i)) {
146 "Warning: signal %d is masked: this is unexpected\n",i);
151 fprintf(stderr,"If this version of SBCL is less than three months old, please report this.\nOtherwise, please try a newer version first\n. Reset signal mask.\n");
159 * utility routines used by various signal handlers
163 build_fake_control_stack_frames(struct thread *th,os_context_t *context)
165 #ifndef LISP_FEATURE_X86
169 /* Build a fake stack frame or frames */
171 current_control_frame_pointer =
172 (lispobj *)(*os_context_register_addr(context, reg_CSP));
173 if ((lispobj *)(*os_context_register_addr(context, reg_CFP))
174 == current_control_frame_pointer) {
175 /* There is a small window during call where the callee's
176 * frame isn't built yet. */
177 if (lowtag_of(*os_context_register_addr(context, reg_CODE))
178 == FUN_POINTER_LOWTAG) {
179 /* We have called, but not built the new frame, so
180 * build it for them. */
181 current_control_frame_pointer[0] =
182 *os_context_register_addr(context, reg_OCFP);
183 current_control_frame_pointer[1] =
184 *os_context_register_addr(context, reg_LRA);
185 current_control_frame_pointer += 8;
186 /* Build our frame on top of it. */
187 oldcont = (lispobj)(*os_context_register_addr(context, reg_CFP));
190 /* We haven't yet called, build our frame as if the
191 * partial frame wasn't there. */
192 oldcont = (lispobj)(*os_context_register_addr(context, reg_OCFP));
195 /* We can't tell whether we are still in the caller if it had to
196 * allocate a stack frame due to stack arguments. */
197 /* This observation provoked some past CMUCL maintainer to ask
198 * "Can anything strange happen during return?" */
201 oldcont = (lispobj)(*os_context_register_addr(context, reg_CFP));
204 current_control_stack_pointer = current_control_frame_pointer + 8;
206 current_control_frame_pointer[0] = oldcont;
207 current_control_frame_pointer[1] = NIL;
208 current_control_frame_pointer[2] =
209 (lispobj)(*os_context_register_addr(context, reg_CODE));
214 fake_foreign_function_call(os_context_t *context)
217 struct thread *thread=arch_os_get_current_thread();
219 /* Get current Lisp state from context. */
221 dynamic_space_free_pointer =
222 (lispobj *)(*os_context_register_addr(context, reg_ALLOC));
224 if ((long)dynamic_space_free_pointer & 1) {
225 lose("dead in fake_foreign_function_call, context = %x", context);
230 current_binding_stack_pointer =
231 (lispobj *)(*os_context_register_addr(context, reg_BSP));
234 build_fake_control_stack_frames(thread,context);
236 /* Do dynamic binding of the active interrupt context index
237 * and save the context in the context array. */
239 fixnum_value(SymbolValue(FREE_INTERRUPT_CONTEXT_INDEX,thread));
241 if (context_index >= MAX_INTERRUPTS) {
242 lose("maximum interrupt nesting depth (%d) exceeded", MAX_INTERRUPTS);
245 bind_variable(FREE_INTERRUPT_CONTEXT_INDEX,
246 make_fixnum(context_index + 1),thread);
248 thread->interrupt_contexts[context_index] = context;
250 /* no longer in Lisp now */
251 foreign_function_call_active = 1;
254 /* blocks all blockable signals. If you are calling from a signal handler,
255 * the usual signal mask will be restored from the context when the handler
256 * finishes. Otherwise, be careful */
259 undo_fake_foreign_function_call(os_context_t *context)
261 struct thread *thread=arch_os_get_current_thread();
262 /* Block all blockable signals. */
265 sigaddset_blockable(&block);
266 sigprocmask(SIG_BLOCK, &block, 0);
268 /* going back into Lisp */
269 foreign_function_call_active = 0;
271 /* Undo dynamic binding of FREE_INTERRUPT_CONTEXT_INDEX */
275 /* Put the dynamic space free pointer back into the context. */
276 *os_context_register_addr(context, reg_ALLOC) =
277 (unsigned long) dynamic_space_free_pointer;
281 /* a handler for the signal caused by execution of a trap opcode
282 * signalling an internal error */
284 interrupt_internal_error(int signal, siginfo_t *info, os_context_t *context,
287 lispobj context_sap = 0;
289 fake_foreign_function_call(context);
291 /* Allocate the SAP object while the interrupts are still
293 if (internal_errors_enabled) {
294 context_sap = alloc_sap(context);
297 sigprocmask(SIG_SETMASK, os_context_sigmask_addr(context), 0);
299 if (internal_errors_enabled) {
300 SHOW("in interrupt_internal_error");
302 /* Display some rudimentary debugging information about the
303 * error, so that even if the Lisp error handler gets badly
304 * confused, we have a chance to determine what's going on. */
305 describe_internal_error(context);
307 funcall2(SymbolFunction(INTERNAL_ERROR), context_sap,
308 continuable ? T : NIL);
310 describe_internal_error(context);
311 /* There's no good way to recover from an internal error
312 * before the Lisp error handling mechanism is set up. */
313 lose("internal error too early in init, can't recover");
315 undo_fake_foreign_function_call(context); /* blocks signals again */
317 arch_skip_instruction(context);
322 interrupt_handle_pending(os_context_t *context)
324 struct thread *thread;
325 struct interrupt_data *data;
327 thread=arch_os_get_current_thread();
328 data=thread->interrupt_data;
329 /* FIXME I'm not altogether sure this is appropriate if we're
330 * here as the result of a pseudo-atomic */
331 SetSymbolValue(INTERRUPT_PENDING, NIL,thread);
333 /* restore the saved signal mask from the original signal (the
334 * one that interrupted us during the critical section) into the
335 * os_context for the signal we're currently in the handler for.
336 * This should ensure that when we return from the handler the
337 * blocked signals are unblocked */
339 memcpy(os_context_sigmask_addr(context), &data->pending_mask,
340 REAL_SIGSET_SIZE_BYTES);
342 sigemptyset(&data->pending_mask);
343 /* This will break on sparc linux: the deferred handler really wants
344 * to be called with a void_context */
345 run_deferred_handler(data,(void *)context);
349 * the two main signal handlers:
350 * interrupt_handle_now(..)
351 * maybe_now_maybe_later(..)
353 * to which we have added interrupt_handle_now_handler(..). Why?
354 * Well, mostly because the SPARC/Linux platform doesn't quite do
355 * signals the way we want them done. The third argument in the
356 * handler isn't filled in by the kernel properly, so we fix it up
357 * ourselves in the arch_os_get_context(..) function; however, we only
358 * want to do this when we first hit the handler, and not when
359 * interrupt_handle_now(..) is being called from some other handler
360 * (when the fixup will already have been done). -- CSR, 2002-07-23
364 interrupt_handle_now(int signal, siginfo_t *info, void *void_context)
366 os_context_t *context = (os_context_t*)void_context;
367 struct thread *thread=arch_os_get_current_thread();
368 #ifndef LISP_FEATURE_X86
369 boolean were_in_lisp;
371 union interrupt_handler handler;
373 #ifdef LISP_FEATURE_LINUX
374 /* Under Linux on some architectures, we appear to have to restore
375 the FPU control word from the context, as after the signal is
376 delivered we appear to have a null FPU control word. */
377 os_restore_fp_control(context);
379 handler = thread->interrupt_data->interrupt_handlers[signal];
381 if (ARE_SAME_HANDLER(handler.c, SIG_IGN)) {
385 #ifndef LISP_FEATURE_X86
386 were_in_lisp = !foreign_function_call_active;
390 fake_foreign_function_call(context);
395 "/entering interrupt_handle_now(%d, info, context)\n",
399 if (ARE_SAME_HANDLER(handler.c, SIG_DFL)) {
401 /* This can happen if someone tries to ignore or default one
402 * of the signals we need for runtime support, and the runtime
403 * support decides to pass on it. */
404 lose("no handler for signal %d in interrupt_handle_now(..)", signal);
406 } else if (lowtag_of(handler.lisp) == FUN_POINTER_LOWTAG) {
407 /* Once we've decided what to do about contexts in a
408 * return-elsewhere world (the original context will no longer
409 * be available; should we copy it or was nobody using it anyway?)
410 * then we should convert this to return-elsewhere */
412 /* CMUCL comment said "Allocate the SAPs while the interrupts
413 * are still disabled.". I (dan, 2003.08.21) assume this is
414 * because we're not in pseudoatomic and allocation shouldn't
415 * be interrupted. In which case it's no longer an issue as
416 * all our allocation from C now goes through a PA wrapper,
417 * but still, doesn't hurt */
419 lispobj info_sap,context_sap = alloc_sap(context);
420 info_sap = alloc_sap(info);
421 /* Allow signals again. */
422 sigprocmask(SIG_SETMASK, os_context_sigmask_addr(context), 0);
425 SHOW("calling Lisp-level handler");
428 funcall3(handler.lisp,
435 SHOW("calling C-level handler");
438 /* Allow signals again. */
439 sigprocmask(SIG_SETMASK, os_context_sigmask_addr(context), 0);
441 (*handler.c)(signal, info, void_context);
444 #ifndef LISP_FEATURE_X86
448 undo_fake_foreign_function_call(context); /* block signals again */
453 "/returning from interrupt_handle_now(%d, info, context)\n",
458 /* This is called at the end of a critical section if the indications
459 * are that some signal was deferred during the section. Note that as
460 * far as C or the kernel is concerned we dealt with the signal
461 * already; we're just doing the Lisp-level processing now that we
465 run_deferred_handler(struct interrupt_data *data, void *v_context) {
466 (*(data->pending_handler))
467 (data->pending_signal,&(data->pending_info), v_context);
468 data->pending_handler=0;
472 maybe_defer_handler(void *handler, struct interrupt_data *data,
473 int signal, siginfo_t *info, os_context_t *context)
475 struct thread *thread=arch_os_get_current_thread();
476 if (SymbolValue(INTERRUPTS_ENABLED,thread) == NIL) {
477 store_signal_data_for_later(data,handler,signal,info,context);
478 SetSymbolValue(INTERRUPT_PENDING, T,thread);
481 /* a slightly confusing test. arch_pseudo_atomic_atomic() doesn't
482 * actually use its argument for anything on x86, so this branch
483 * may succeed even when context is null (gencgc alloc()) */
485 #ifndef LISP_FEATURE_X86
486 (!foreign_function_call_active) &&
488 arch_pseudo_atomic_atomic(context)) {
489 store_signal_data_for_later(data,handler,signal,info,context);
490 arch_set_pseudo_atomic_interrupted(context);
496 store_signal_data_for_later (struct interrupt_data *data, void *handler,
498 siginfo_t *info, os_context_t *context)
500 data->pending_handler = handler;
501 data->pending_signal = signal;
503 memcpy(&(data->pending_info), info, sizeof(siginfo_t));
505 /* the signal mask in the context (from before we were
506 * interrupted) is copied to be restored when
507 * run_deferred_handler happens. Then the usually-blocked
508 * signals are added to the mask in the context so that we are
509 * running with blocked signals when the handler returns */
510 sigemptyset(&(data->pending_mask));
511 memcpy(&(data->pending_mask),
512 os_context_sigmask_addr(context),
513 REAL_SIGSET_SIZE_BYTES);
514 sigaddset_blockable(os_context_sigmask_addr(context));
516 /* this is also called from gencgc alloc(), in which case
517 * there has been no signal and is therefore no context. */
520 sigaddset_blockable(&new);
521 sigprocmask(SIG_BLOCK,&new,&(data->pending_mask));
527 maybe_now_maybe_later(int signal, siginfo_t *info, void *void_context)
529 os_context_t *context = arch_os_get_context(&void_context);
530 struct thread *thread=arch_os_get_current_thread();
531 struct interrupt_data *data=thread->interrupt_data;
532 #ifdef LISP_FEATURE_LINUX
533 os_restore_fp_control(context);
535 if(maybe_defer_handler(interrupt_handle_now,data,
536 signal,info,context))
538 interrupt_handle_now(signal, info, context);
539 #ifdef LISP_FEATURE_DARWIN
540 /* Work around G5 bug */
541 sigreturn(void_context);
545 #ifdef LISP_FEATURE_SB_THREAD
547 sig_stop_for_gc_handler(int signal, siginfo_t *info, void *void_context)
549 os_context_t *context = arch_os_get_context(&void_context);
550 struct thread *thread=arch_os_get_current_thread();
551 struct interrupt_data *data=thread->interrupt_data;
555 /* KLUDGE: at least on Linux, the kernel apparently schedules a
556 thread immediately it is signalled. However, we signal
557 SIG_STOP_FOR_GC while holding the spinlock, and consequently we
558 can easily end up with a kind of thundering herd of threads all
559 wanting to acquire the lock at the same time so that they can
560 tell the system that they've gone to sleep. So we yield here.
561 Whether this is the right fix or not is unknown. -- CSR,
565 if(maybe_defer_handler(sig_stop_for_gc_handler,data,
566 signal,info,context)) {
569 /* need the context stored so it can have registers scavenged */
570 fake_foreign_function_call(context);
573 for(i=1;i<NSIG;i++) sigaddset(&ss,i); /* Block everything. */
574 sigprocmask(SIG_BLOCK,&ss,0);
576 get_spinlock(&all_threads_lock,thread->pid);
577 thread->state=STATE_STOPPED;
578 release_spinlock(&all_threads_lock);
580 sigemptyset(&ss); sigaddset(&ss,SIG_STOP_FOR_GC);
583 undo_fake_foreign_function_call(context);
588 interrupt_handle_now_handler(int signal, siginfo_t *info, void *void_context)
590 os_context_t *context = arch_os_get_context(&void_context);
591 interrupt_handle_now(signal, info, context);
592 #ifdef LISP_FEATURE_DARWIN
593 sigreturn(void_context);
598 * stuff to detect and handle hitting the GC trigger
601 #ifndef LISP_FEATURE_GENCGC
602 /* since GENCGC has its own way to record trigger */
604 gc_trigger_hit(int signal, siginfo_t *info, os_context_t *context)
606 if (current_auto_gc_trigger == NULL)
609 void *badaddr=arch_get_bad_addr(signal,info,context);
610 return (badaddr >= (void *)current_auto_gc_trigger &&
611 badaddr <((void *)current_dynamic_space + DYNAMIC_SPACE_SIZE));
616 /* manipulate the signal context and stack such that when the handler
617 * returns, it will call function instead of whatever it was doing
621 extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
622 extern void post_signal_tramp(void);
623 void arrange_return_to_lisp_function(os_context_t *context, lispobj function)
625 #ifndef LISP_FEATURE_X86
626 void * fun=native_pointer(function);
627 void *code = &(((struct simple_fun *) fun)->code);
630 /* Build a stack frame showing `interrupted' so that the
631 * user's backtrace makes (as much) sense (as usual) */
632 #ifdef LISP_FEATURE_X86
633 /* Suppose the existence of some function that saved all
634 * registers, called call_into_lisp, then restored GP registers and
635 * returned. We shortcut this: fake the stack that call_into_lisp
636 * would see, then arrange to have it called directly. post_signal_tramp
637 * is the second half of this function
639 u32 *sp=(u32 *)*os_context_register_addr(context,reg_ESP);
641 *(sp-14) = post_signal_tramp; /* return address for call_into_lisp */
642 *(sp-13) = function; /* args for call_into_lisp : function*/
643 *(sp-12) = 0; /* arg array */
644 *(sp-11) = 0; /* no. args */
645 /* this order matches that used in POPAD */
646 *(sp-10)=*os_context_register_addr(context,reg_EDI);
647 *(sp-9)=*os_context_register_addr(context,reg_ESI);
648 /* this gets overwritten again before it's used, anyway */
649 *(sp-8)=*os_context_register_addr(context,reg_EBP);
650 *(sp-7)=0 ; /* POPAD doesn't set ESP, but expects a gap for it anyway */
651 *(sp-6)=*os_context_register_addr(context,reg_EBX);
653 *(sp-5)=*os_context_register_addr(context,reg_EDX);
654 *(sp-4)=*os_context_register_addr(context,reg_ECX);
655 *(sp-3)=*os_context_register_addr(context,reg_EAX);
656 *(sp-2)=*os_context_register_addr(context,reg_EBP);
657 *(sp-1)=*os_context_pc_addr(context);
660 struct thread *th=arch_os_get_current_thread();
661 build_fake_control_stack_frames(th,context);
664 #ifdef LISP_FEATURE_X86
665 *os_context_pc_addr(context) = call_into_lisp;
666 *os_context_register_addr(context,reg_ECX) = 0;
667 *os_context_register_addr(context,reg_EBP) = sp-2;
668 *os_context_register_addr(context,reg_ESP) = sp-14;
670 /* this much of the calling convention is common to all
672 *os_context_pc_addr(context) = code;
673 *os_context_register_addr(context,reg_NARGS) = 0;
674 *os_context_register_addr(context,reg_LIP) = code;
675 *os_context_register_addr(context,reg_CFP) =
676 current_control_frame_pointer;
678 #ifdef ARCH_HAS_NPC_REGISTER
679 *os_context_npc_addr(context) =
680 4 + *os_context_pc_addr(context);
682 #ifdef LISP_FEATURE_SPARC
683 *os_context_register_addr(context,reg_CODE) =
684 fun + FUN_POINTER_LOWTAG;
688 #ifdef LISP_FEATURE_SB_THREAD
689 void interrupt_thread_handler(int num, siginfo_t *info, void *v_context)
691 os_context_t *context = (os_context_t*)arch_os_get_context(&v_context);
692 struct thread *th=arch_os_get_current_thread();
693 struct interrupt_data *data=
694 th ? th->interrupt_data : global_interrupt_data;
695 if(maybe_defer_handler(interrupt_thread_handler,data,num,info,context)){
698 arrange_return_to_lisp_function(context,info->si_value.sival_int);
701 void thread_exit_handler(int num, siginfo_t *info, void *v_context)
702 { /* called when a child thread exits */
703 os_context_t *context = (os_context_t*)arch_os_get_context(&v_context);
704 struct thread *th=arch_os_get_current_thread();
707 struct interrupt_data *data=
708 th ? th->interrupt_data : global_interrupt_data;
709 if(maybe_defer_handler(thread_exit_handler,data,num,info,context)){
713 kid=waitpid(-1,&status,__WALL|WNOHANG);
715 if(WIFEXITED(status) || WIFSIGNALED(status)) {
716 struct thread *th=find_thread_by_pid(kid);
718 funcall1(SymbolFunction(HANDLE_THREAD_EXIT),make_fixnum(kid));
725 boolean handle_control_stack_guard_triggered(os_context_t *context,void *addr){
726 struct thread *th=arch_os_get_current_thread();
727 /* note the os_context hackery here. When the signal handler returns,
728 * it won't go back to what it was doing ... */
729 if(addr>=(void *)CONTROL_STACK_GUARD_PAGE(th) &&
730 addr<(void *)(CONTROL_STACK_GUARD_PAGE(th)+os_vm_page_size)) {
731 /* we hit the end of the control stack. disable protection
732 * temporarily so the error handler has some headroom */
733 protect_control_stack_guard_page(th->pid,0L);
735 arrange_return_to_lisp_function
736 (context, SymbolFunction(CONTROL_STACK_EXHAUSTED_ERROR));
742 #ifndef LISP_FEATURE_GENCGC
743 /* This function gets called from the SIGSEGV (for e.g. Linux, NetBSD, &
744 * OpenBSD) or SIGBUS (for e.g. FreeBSD) handler. Here we check
745 * whether the signal was due to treading on the mprotect()ed zone -
746 * and if so, arrange for a GC to happen. */
747 extern unsigned long bytes_consed_between_gcs; /* gc-common.c */
750 interrupt_maybe_gc(int signal, siginfo_t *info, void *void_context)
752 os_context_t *context=(os_context_t *) void_context;
753 struct thread *th=arch_os_get_current_thread();
754 struct interrupt_data *data=
755 th ? th->interrupt_data : global_interrupt_data;
757 if(!foreign_function_call_active && gc_trigger_hit(signal, info, context)){
758 clear_auto_gc_trigger();
759 if(!maybe_defer_handler
760 (interrupt_maybe_gc_int,data,signal,info,void_context))
761 interrupt_maybe_gc_int(signal,info,void_context);
769 /* this is also used by gencgc, in alloc() */
771 interrupt_maybe_gc_int(int signal, siginfo_t *info, void *void_context)
774 os_context_t *context=(os_context_t *) void_context;
775 fake_foreign_function_call(context);
776 /* SUB-GC may return without GCing if *GC-INHIBIT* is set, in
777 * which case we will be running with no gc trigger barrier
778 * thing for a while. But it shouldn't be long until the end
779 * of WITHOUT-GCING. */
782 sigaddset_blockable(&new);
783 /* enable signals before calling into Lisp */
784 sigprocmask(SIG_UNBLOCK,&new,0);
785 funcall0(SymbolFunction(SUB_GC));
786 undo_fake_foreign_function_call(context);
792 * noise to install handlers
796 undoably_install_low_level_interrupt_handler (int signal,
802 struct thread *th=arch_os_get_current_thread();
803 struct interrupt_data *data=
804 th ? th->interrupt_data : global_interrupt_data;
806 if (0 > signal || signal >= NSIG) {
807 lose("bad signal number %d", signal);
810 sa.sa_sigaction = handler;
811 sigemptyset(&sa.sa_mask);
812 sigaddset_blockable(&sa.sa_mask);
813 sa.sa_flags = SA_SIGINFO | SA_RESTART;
814 #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
815 if((signal==SIG_MEMORY_FAULT)
816 #ifdef SIG_INTERRUPT_THREAD
817 || (signal==SIG_INTERRUPT_THREAD)
820 sa.sa_flags|= SA_ONSTACK;
823 sigaction(signal, &sa, NULL);
824 data->interrupt_low_level_handlers[signal] =
825 (ARE_SAME_HANDLER(handler, SIG_DFL) ? 0 : handler);
828 /* This is called from Lisp. */
830 install_handler(int signal, void handler(int, siginfo_t*, void*))
834 union interrupt_handler oldhandler;
835 struct thread *th=arch_os_get_current_thread();
836 struct interrupt_data *data=
837 th ? th->interrupt_data : global_interrupt_data;
839 FSHOW((stderr, "/entering POSIX install_handler(%d, ..)\n", signal));
842 sigaddset(&new, signal);
843 sigprocmask(SIG_BLOCK, &new, &old);
846 sigaddset_blockable(&new);
848 FSHOW((stderr, "/data->interrupt_low_level_handlers[signal]=%d\n",
849 data->interrupt_low_level_handlers[signal]));
850 if (data->interrupt_low_level_handlers[signal]==0) {
851 if (ARE_SAME_HANDLER(handler, SIG_DFL) ||
852 ARE_SAME_HANDLER(handler, SIG_IGN)) {
853 sa.sa_sigaction = handler;
854 } else if (sigismember(&new, signal)) {
855 sa.sa_sigaction = maybe_now_maybe_later;
857 sa.sa_sigaction = interrupt_handle_now_handler;
860 sigemptyset(&sa.sa_mask);
861 sigaddset_blockable(&sa.sa_mask);
862 sa.sa_flags = SA_SIGINFO | SA_RESTART;
863 sigaction(signal, &sa, NULL);
866 oldhandler = data->interrupt_handlers[signal];
867 data->interrupt_handlers[signal].c = handler;
869 sigprocmask(SIG_SETMASK, &old, 0);
871 FSHOW((stderr, "/leaving POSIX install_handler(%d, ..)\n", signal));
873 return (unsigned long)oldhandler.lisp;
880 SHOW("entering interrupt_init()");
881 global_interrupt_data=calloc(sizeof(struct interrupt_data), 1);
883 /* Set up high level handler information. */
884 for (i = 0; i < NSIG; i++) {
885 global_interrupt_data->interrupt_handlers[i].c =
886 /* (The cast here blasts away the distinction between
887 * SA_SIGACTION-style three-argument handlers and
888 * signal(..)-style one-argument handlers, which is OK
889 * because it works to call the 1-argument form where the
890 * 3-argument form is expected.) */
891 (void (*)(int, siginfo_t*, void*))SIG_DFL;
894 SHOW("returning from interrupt_init()");