#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"
* work for SIGSEGV and similar. It is good enough for timers, and
* maybe all deferrables. */
+#ifdef LISP_FEATURE_SB_THREAD
static void
add_handled_signals(sigset_t *sigset)
{
}
void block_signals(sigset_t *what, sigset_t *where, sigset_t *old);
+#endif
static boolean
maybe_resignal_to_lisp_thread(int signal, 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));
}
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
}
/* 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); */
#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);
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
}
/* 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
| ((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
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);
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);
}
(*handler.c)(signal, info, context);
}
-#ifdef FOREIGN_FUNCTION_CALL_FLAG
if (were_in_lisp)
-#endif
{
undo_fake_foreign_function_call(context); /* block signals again */
}
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. */
/* 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);
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"));
fixnum_value(thread_state(thread)));
}
- undo_fake_foreign_function_call(context);
+ if (was_in_lisp) {
+ undo_fake_foreign_function_call(context);
+ }
}
#endif
|| (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;
*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) =
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)
{
* 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. */
* 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) &&