X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Finterrupt.c;h=ea0880f57459f8b2e93adda71435946f61227028;hb=344a1f088581303c92da333ddddc9aeb9c212ba9;hp=13ff61df1d81023636fef060d972a2871f7509f8;hpb=1a22ba18104caec504718967ae07d143873f6848;p=sbcl.git diff --git a/src/runtime/interrupt.c b/src/runtime/interrupt.c index 13ff61d..ea0880f 100644 --- a/src/runtime/interrupt.c +++ b/src/runtime/interrupt.c @@ -59,10 +59,10 @@ #include "globals.h" #include "lispregs.h" #include "validate.h" +#include "interr.h" #include "gc.h" #include "alloc.h" #include "dynbind.h" -#include "interr.h" #include "pseudo-atomic.h" #include "genesis/fdefn.h" #include "genesis/simple-fun.h" @@ -609,23 +609,23 @@ build_fake_control_stack_frames(struct thread *th,os_context_t *context) /* Build a fake stack frame or frames */ - current_control_frame_pointer = + access_control_frame_pointer(th) = (lispobj *)(unsigned long) (*os_context_register_addr(context, reg_CSP)); if ((lispobj *)(unsigned long) (*os_context_register_addr(context, reg_CFP)) - == current_control_frame_pointer) { + == access_control_frame_pointer(th)) { /* There is a small window during call where the callee's * frame isn't built yet. */ if (lowtag_of(*os_context_register_addr(context, reg_CODE)) == FUN_POINTER_LOWTAG) { /* We have called, but not built the new frame, so * build it for them. */ - current_control_frame_pointer[0] = + access_control_frame_pointer(th)[0] = *os_context_register_addr(context, reg_OCFP); - current_control_frame_pointer[1] = + access_control_frame_pointer(th)[1] = *os_context_register_addr(context, reg_LRA); - current_control_frame_pointer += 8; + access_control_frame_pointer(th) += 8; /* Build our frame on top of it. */ oldcont = (lispobj)(*os_context_register_addr(context, reg_CFP)); } @@ -644,11 +644,11 @@ build_fake_control_stack_frames(struct thread *th,os_context_t *context) oldcont = (lispobj)(*os_context_register_addr(context, reg_CFP)); } - current_control_stack_pointer = current_control_frame_pointer + 8; + access_control_stack_pointer(th) = access_control_frame_pointer(th) + 8; - current_control_frame_pointer[0] = oldcont; - current_control_frame_pointer[1] = NIL; - current_control_frame_pointer[2] = + access_control_frame_pointer(th)[0] = oldcont; + access_control_frame_pointer(th)[1] = NIL; + access_control_frame_pointer(th)[2] = (lispobj)(*os_context_register_addr(context, reg_CODE)); #endif } @@ -666,8 +666,12 @@ fake_foreign_function_call(os_context_t *context) /* Get current Lisp state from context. */ #ifdef reg_ALLOC +#ifdef LISP_FEATURE_SB_THREAD + thread->pseudo_atomic_bits = +#else dynamic_space_free_pointer = (lispobj *)(unsigned long) +#endif (*os_context_register_addr(context, reg_ALLOC)); /* fprintf(stderr,"dynamic_space_free_pointer: %p\n", */ /* dynamic_space_free_pointer); */ @@ -684,9 +688,8 @@ fake_foreign_function_call(os_context_t *context) #endif #endif #ifdef reg_BSP - current_binding_stack_pointer = - (lispobj *)(unsigned long) - (*os_context_register_addr(context, reg_BSP)); + set_binding_stack_pointer(thread, + *os_context_register_addr(context, reg_BSP)); #endif build_fake_control_stack_frames(thread,context); @@ -705,8 +708,11 @@ fake_foreign_function_call(os_context_t *context) thread->interrupt_contexts[context_index] = context; -#ifdef FOREIGN_FUNCTION_CALL_FLAG - foreign_function_call_active = 1; +#if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64) + /* x86oid targets don't maintain the foreign function call flag at + * all, so leave them to believe that they are never in foreign + * code. */ + foreign_function_call_active_p(thread) = 1; #endif } @@ -720,14 +726,12 @@ undo_fake_foreign_function_call(os_context_t *context) /* Block all blockable signals. */ block_blockable_signals(0, 0); -#ifdef FOREIGN_FUNCTION_CALL_FLAG - foreign_function_call_active = 0; -#endif + foreign_function_call_active_p(thread) = 0; /* Undo dynamic binding of FREE_INTERRUPT_CONTEXT_INDEX */ unbind(thread); -#ifdef reg_ALLOC +#if defined(reg_ALLOC) && !defined(LISP_FEATURE_SB_THREAD) /* Put the dynamic space free pointer back into the context. */ *os_context_register_addr(context, reg_ALLOC) = (unsigned long) dynamic_space_free_pointer @@ -739,6 +743,17 @@ undo_fake_foreign_function_call(os_context_t *context) | ((unsigned long) dynamic_space_free_pointer & LOWTAG_MASK); */ #endif +#if defined(reg_ALLOC) && defined(LISP_FEATURE_SB_THREAD) + /* Put the pseudo-atomic bits and dynamic space free pointer back + * into the context (p-a-bits for p-a, and dynamic space free + * pointer for ROOM). */ + *os_context_register_addr(context, reg_ALLOC) = + (unsigned long) dynamic_space_free_pointer + | (thread->pseudo_atomic_bits & LOWTAG_MASK); + /* And clear them so we don't get bit later by call-in/call-out + * not updating them. */ + thread->pseudo_atomic_bits = 0; +#endif } /* a handler for the signal caused by execution of a trap opcode @@ -954,9 +969,7 @@ interrupt_handle_pending(os_context_t *context) void interrupt_handle_now(int signal, siginfo_t *info, os_context_t *context) { -#ifdef FOREIGN_FUNCTION_CALL_FLAG boolean were_in_lisp; -#endif union interrupt_handler handler; check_blockables_blocked_or_lose(0); @@ -972,10 +985,8 @@ interrupt_handle_now(int signal, siginfo_t *info, os_context_t *context) return; } -#ifdef FOREIGN_FUNCTION_CALL_FLAG - were_in_lisp = !foreign_function_call_active; + were_in_lisp = !foreign_function_call_active_p(arch_os_get_current_thread()); if (were_in_lisp) -#endif { fake_foreign_function_call(context); } @@ -1032,9 +1043,7 @@ interrupt_handle_now(int signal, siginfo_t *info, os_context_t *context) (*handler.c)(signal, info, context); } -#ifdef FOREIGN_FUNCTION_CALL_FLAG if (were_in_lisp) -#endif { undo_fake_foreign_function_call(context); /* block signals again */ } @@ -1190,6 +1199,7 @@ void sig_stop_for_gc_handler(int signal, siginfo_t *info, os_context_t *context) { struct thread *thread=arch_os_get_current_thread(); + boolean was_in_lisp; /* Test for GC_INHIBIT _first_, else we'd trap on every single * pseudo atomic until gc is finally allowed. */ @@ -1210,8 +1220,12 @@ sig_stop_for_gc_handler(int signal, siginfo_t *info, os_context_t *context) /* Not PA and GC not inhibited -- we can stop now. */ - /* need the context stored so it can have registers scavenged */ - fake_foreign_function_call(context); + was_in_lisp = !foreign_function_call_active_p(arch_os_get_current_thread()); + + if (was_in_lisp) { + /* need the context stored so it can have registers scavenged */ + fake_foreign_function_call(context); + } /* Not pending anymore. */ SetSymbolValue(GC_PENDING,NIL,thread); @@ -1242,6 +1256,12 @@ sig_stop_for_gc_handler(int signal, siginfo_t *info, os_context_t *context) set_thread_state(thread,STATE_SUSPENDED); FSHOW_SIGNAL((stderr,"suspended\n")); + /* While waiting for gc to finish occupy ourselves with zeroing + * the unused portion of the control stack to reduce conservatism. + * On hypothetic platforms with threads and exact gc it is + * actually a must. */ + scrub_control_stack(); + wait_for_thread_state_change(thread, STATE_SUSPENDED); FSHOW_SIGNAL((stderr,"resumed\n")); @@ -1250,7 +1270,9 @@ sig_stop_for_gc_handler(int signal, siginfo_t *info, os_context_t *context) fixnum_value(thread_state(thread))); } - undo_fake_foreign_function_call(context); + if (was_in_lisp) { + undo_fake_foreign_function_call(context); + } } #endif @@ -1265,7 +1287,7 @@ interrupt_handle_now_handler(int signal, siginfo_t *info, void *void_context) || (signal == SIGEMT) #endif ) - corruption_warning_and_maybe_lose("Signal %d recieved", signal); + corruption_warning_and_maybe_lose("Signal %d received", signal); #endif interrupt_handle_now(signal, info, context); RESTORE_ERRNO; @@ -1453,7 +1475,7 @@ arrange_return_to_lisp_function(os_context_t *context, lispobj function) *os_context_register_addr(context,reg_LIP) = (os_context_register_t)(unsigned long)code; *os_context_register_addr(context,reg_CFP) = - (os_context_register_t)(unsigned long)current_control_frame_pointer; + (os_context_register_t)(unsigned long)access_control_frame_pointer(th); #endif #ifdef ARCH_HAS_NPC_REGISTER *os_context_npc_addr(context) = @@ -1479,6 +1501,37 @@ undefined_alien_function(void) funcall0(StaticSymbolFunction(UNDEFINED_ALIEN_FUNCTION_ERROR)); } +void lower_thread_control_stack_guard_page(struct thread *th) +{ + protect_control_stack_guard_page(0, th); + protect_control_stack_return_guard_page(1, th); + th->control_stack_guard_page_protected = NIL; + fprintf(stderr, "INFO: Control stack guard page unprotected\n"); +} + +void reset_thread_control_stack_guard_page(struct thread *th) +{ + memset(CONTROL_STACK_GUARD_PAGE(th), 0, os_vm_page_size); + protect_control_stack_guard_page(1, th); + protect_control_stack_return_guard_page(0, th); + th->control_stack_guard_page_protected = T; + fprintf(stderr, "INFO: Control stack guard page reprotected\n"); +} + +/* Called from the REPL, too. */ +void reset_control_stack_guard_page(void) +{ + struct thread *th=arch_os_get_current_thread(); + if (th->control_stack_guard_page_protected == NIL) { + reset_thread_control_stack_guard_page(th); + } +} + +void lower_control_stack_guard_page(void) +{ + lower_thread_control_stack_guard_page(arch_os_get_current_thread()); +} + boolean handle_guard_page_triggered(os_context_t *context,os_vm_address_t addr) { @@ -1494,10 +1547,9 @@ handle_guard_page_triggered(os_context_t *context,os_vm_address_t addr) * protection so the error handler has some headroom, protect the * previous page so that we can catch returns from the guard page * and restore it. */ - protect_control_stack_guard_page(0, NULL); - protect_control_stack_return_guard_page(1, NULL); - fprintf(stderr, "INFO: Control stack guard page unprotected\n"); - + if (th->control_stack_guard_page_protected == NIL) + lose("control_stack_guard_page_protected NIL"); + lower_control_stack_guard_page(); #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK /* For the unfortunate case, when the control stack is * exhausted in a signal handler. */ @@ -1513,9 +1565,9 @@ handle_guard_page_triggered(os_context_t *context,os_vm_address_t addr) * unprotect this one. This works even if we somehow missed * the return-guard-page, and hit it on our way to new * exhaustion instead. */ - protect_control_stack_guard_page(1, NULL); - protect_control_stack_return_guard_page(0, NULL); - fprintf(stderr, "INFO: Control stack guard page reprotected\n"); + if (th->control_stack_guard_page_protected != NIL) + lose("control_stack_guard_page_protected not NIL"); + reset_control_stack_guard_page(); return 1; } else if(addr >= BINDING_STACK_HARD_GUARD_PAGE(th) &&