/* Build a fake stack frame or frames */
access_control_frame_pointer(th) =
- (lispobj *)(unsigned long)
+ (lispobj *)(uword_t)
(*os_context_register_addr(context, reg_CSP));
- if ((lispobj *)(unsigned long)
+ if ((lispobj *)(uword_t)
(*os_context_register_addr(context, reg_CFP))
== access_control_frame_pointer(th)) {
/* There is a small window during call where the callee's
thread->pseudo_atomic_bits =
#else
dynamic_space_free_pointer =
- (lispobj *)(unsigned long)
+ (lispobj *)(uword_t)
#endif
(*os_context_register_addr(context, reg_ALLOC));
/* fprintf(stderr,"dynamic_space_free_pointer: %p\n", */
/* dynamic_space_free_pointer); */
#if defined(LISP_FEATURE_ALPHA) || defined(LISP_FEATURE_MIPS)
- if ((long)dynamic_space_free_pointer & 1) {
+ if ((sword_t)dynamic_space_free_pointer & 1) {
lose("dead in fake_foreign_function_call, context = %x\n", context);
}
#endif
/* why doesnt PPC and SPARC do something like this: */
#if defined(LISP_FEATURE_HPPA)
- if ((long)dynamic_space_free_pointer & 4) {
+ if ((sword_t)dynamic_space_free_pointer & 4) {
lose("dead in fake_foreign_function_call, context = %x, d_s_f_p = %x\n", context, dynamic_space_free_pointer);
}
#endif
#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
+ (uword_t) dynamic_space_free_pointer
| (*os_context_register_addr(context, reg_ALLOC)
& LOWTAG_MASK);
/*
- ((unsigned long)(*os_context_register_addr(context, reg_ALLOC))
+ ((uword_t)(*os_context_register_addr(context, reg_ALLOC))
& ~LOWTAG_MASK)
- | ((unsigned long) dynamic_space_free_pointer & LOWTAG_MASK);
+ | ((uword_t) dynamic_space_free_pointer & LOWTAG_MASK);
*/
#endif
#if defined(reg_ALLOC) && defined(LISP_FEATURE_SB_THREAD)
* 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
+ (uword_t) 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. */
/* handles the STOP_FOR_GC_PENDING case, plus THRUPTIONS */
if (SymbolValue(STOP_FOR_GC_PENDING,thread) != NIL
# ifdef LISP_FEATURE_SB_THRUPTION
- || SymbolValue(THRUPTION_PENDING,thread) != NIL
+ || (SymbolValue(THRUPTION_PENDING,thread) != NIL
+ && SymbolValue(INTERRUPTS_ENABLED, thread) != NIL)
# endif
)
- {
/* We ought to take this chance to do a pitstop now. */
-
- /* Now, it goes without saying that the context sigmask
- * tweaking around this call is not pretty. However, it
- * currently seems to be "needed" for the following
- * situation. (So let's find a better solution and remove
- * this comment afterwards.)
- *
- * Suppose we are in a signal handler (let's say SIGALRM).
- * At the end of a WITHOUT-INTERRUPTS, the lisp code notices
- * that a thruption is pending, and says to itself "let's
- * receive pending interrupts then". We trust that the
- * caller is happy to run those sorts of things now,
- * including thruptions, otherwise it wouldn't have called
- * us. But that's the problem: Even though we can guess the
- * caller's intention, may_thrupt() would see that signals
- * are blocked in the signal context (because that context
- * itself points to a signal handler). So we cheat and
- * pretend that signals weren't blocked.
- * --DFL */
-#ifndef LISP_FEATURE_WIN32
- sigset_t old, *ctxset = os_context_sigmask_addr(context);
- unblock_signals(&deferrable_sigset, ctxset, &old);
-#endif
- thread_pitstop(context);
-#ifndef LISP_FEATURE_WIN32
- sigcopyset(&old, ctxset);
-#endif
- }
+ thread_in_lisp_raised(context);
#elif defined(LISP_FEATURE_SB_THREAD)
if (SymbolValue(STOP_FOR_GC_PENDING,thread) != NIL) {
/* STOP_FOR_GC_PENDING and GC_PENDING are cleared by
* an interrupt arrived during GC (POST-GC, really) it was
* handled. */
if (original_pending_handler != data->pending_handler)
- lose("pending handler changed in gc: %x -> %d.",
+ lose("pending handler changed in gc: %x -> %x.",
original_pending_handler, data->pending_handler);
}
* in PA. MG - 2005-08-29 */
lispobj info_sap, context_sap;
+
+#ifndef LISP_FEATURE_SB_SAFEPOINT
/* Leave deferrable signals blocked, the handler itself will
* allow signals again when it sees fit. */
-#ifndef LISP_FEATURE_SB_SAFEPOINT
unblock_gc_signals(0, 0);
+#else
+ WITH_GC_AT_SAFEPOINTS_ONLY()
#endif
- context_sap = alloc_sap(context);
- info_sap = alloc_sap(info);
+ { // the block is needed for WITH_GC_AT_SAFEPOINTS_ONLY() to work
+ context_sap = alloc_sap(context);
+ info_sap = alloc_sap(info);
- FSHOW_SIGNAL((stderr,"/calling Lisp-level handler\n"));
+ FSHOW_SIGNAL((stderr,"/calling Lisp-level handler\n"));
-#ifdef LISP_FEATURE_SB_SAFEPOINT
- WITH_GC_AT_SAFEPOINTS_ONLY()
-#endif
- funcall3(handler.lisp,
- make_fixnum(signal),
- info_sap,
- context_sap);
+ funcall3(handler.lisp,
+ make_fixnum(signal),
+ info_sap,
+ context_sap);
+ }
} else {
/* This cannot happen in sane circumstances. */
#endif
}
+// x86-64 has an undefined_alien_function tramp in x86-64-assem.S
+#ifndef LISP_FEATURE_X86_64
/* KLUDGE: Theoretically the approach we use for undefined alien
* variables should work for functions as well, but on PPC/Darwin
* we get bus error at bogus addresses instead, hence this workaround,
void
undefined_alien_function(void)
{
- funcall0(StaticSymbolFunction(UNDEFINED_ALIEN_FUNCTION_ERROR));
+ funcall0(StaticSymbolFunction(UNDEFINED_ALIEN_FUN_ERROR));
}
+#endif
void lower_thread_control_stack_guard_page(struct thread *th)
{
#undef SA_NODEFER_TEST_BLOCK_SIGNAL
#undef SA_NODEFER_TEST_KILL_SIGNAL
+#if defined(LISP_FEATURE_SB_SAFEPOINT_STRICTLY) && !defined(LISP_FEATURE_WIN32)
+
+static void *
+signal_thread_trampoline(void *pthread_arg)
+{
+ int signo = (int) pthread_arg;
+ os_context_t fake_context;
+ siginfo_t fake_info;
+#ifdef LISP_FEATURE_PPC
+ mcontext_t uc_regs;
+#endif
+
+ memset(&fake_info, 0, sizeof(fake_info));
+ memset(&fake_context, 0, sizeof(fake_context));
+#ifdef LISP_FEATURE_PPC
+ memset(&uc_regs, 0, sizeof(uc_regs));
+ fake_context.uc_mcontext.uc_regs = &uc_regs;
+#endif
+
+ *os_context_pc_addr(&fake_context) = &signal_thread_trampoline;
+#ifdef ARCH_HAS_STACK_POINTER /* aka x86(-64) */
+ *os_context_sp_addr(&fake_context) = __builtin_frame_address(0);
+#endif
+
+ signal_handler_callback(interrupt_handlers[signo].lisp,
+ signo, &fake_info, &fake_context);
+ return 0;
+}
+
+static void
+sigprof_handler_trampoline(int signal, siginfo_t *info, void *void_context)
+{
+ SAVE_ERRNO(signal,context,void_context);
+ struct thread *self = arch_os_get_current_thread();
+
+ /* alloc() is not re-entrant and still uses pseudo atomic (even though
+ * inline allocation does not). In this case, give up. */
+ if (get_pseudo_atomic_atomic(self))
+ goto cleanup;
+
+ struct alloc_region tmp = self->alloc_region;
+ self->alloc_region = self->sprof_alloc_region;
+ self->sprof_alloc_region = tmp;
+
+ interrupt_handle_now_handler(signal, info, void_context);
+
+ /* And we're back. We know that the SIGPROF handler never unwinds
+ * non-locally, and can simply swap things back: */
+
+ tmp = self->alloc_region;
+ self->alloc_region = self->sprof_alloc_region;
+ self->sprof_alloc_region = tmp;
+
+cleanup:
+ ; /* Dear C compiler, it's OK to have a label here. */
+ RESTORE_ERRNO;
+}
+
+static void
+spawn_signal_thread_handler(int signal, siginfo_t *info, void *void_context)
+{
+ SAVE_ERRNO(signal,context,void_context);
+
+ pthread_attr_t attr;
+ pthread_t th;
+
+ if (pthread_attr_init(&attr))
+ goto lost;
+ if (pthread_attr_setstacksize(&attr, thread_control_stack_size))
+ goto lost;
+ if (pthread_create(&th, &attr, &signal_thread_trampoline, (void*) signal))
+ goto lost;
+ if (pthread_attr_destroy(&attr))
+ goto lost;
+
+ RESTORE_ERRNO;
+ return;
+
+lost:
+ lose("spawn_signal_thread_handler");
+}
+#endif
+
static void
unblock_me_trampoline(int signal, siginfo_t *info, void *void_context)
{
#endif
/* This is called from Lisp. */
-unsigned long
-install_handler(int signal, void handler(int, siginfo_t*, os_context_t*))
+uword_t
+install_handler(int signal, void handler(int, siginfo_t*, os_context_t*),
+ int synchronous)
{
#ifndef LISP_FEATURE_WIN32
struct sigaction sa;
if (ARE_SAME_HANDLER(handler, SIG_DFL) ||
ARE_SAME_HANDLER(handler, SIG_IGN))
sa.sa_sigaction = (void (*)(int, siginfo_t*, void*))handler;
+#ifdef LISP_FEATURE_SB_SAFEPOINT_STRICTLY
+ else if (signal == SIGPROF)
+ sa.sa_sigaction = sigprof_handler_trampoline;
+ else if (!synchronous)
+ sa.sa_sigaction = spawn_signal_thread_handler;
+#endif
else if (sigismember(&deferrable_sigset, signal))
sa.sa_sigaction = maybe_now_maybe_later;
else if (!sigaction_nodefer_works &&
FSHOW((stderr, "/leaving POSIX install_handler(%d, ..)\n", signal));
- return (unsigned long)oldhandler.lisp;
+ return (uword_t)oldhandler.lisp;
#else
/* Probably-wrong Win32 hack */
return 0;
arch_handle_single_step_trap(context, trap);
break;
#endif
-#ifdef LISP_FEATURE_SB_SAFEPOINT
+#ifdef trap_GlobalSafepoint
case trap_GlobalSafepoint:
fake_foreign_function_call(context);
thread_in_lisp_raised(context);