#include "alloc.h"
#include "dynbind.h"
#include "interr.h"
+#include "pseudo-atomic.h"
#include "genesis/fdefn.h"
#include "genesis/simple-fun.h"
#include "genesis/cons.h"
siginfo_t *info,
os_context_t *context);
+static void
+fill_current_sigmask(sigset_t *sigset)
+{
+ /* Get the current sigmask, by blocking the empty set. */
+ sigset_t empty;
+ sigemptyset(&empty);
+ thread_sigmask(SIG_BLOCK, &empty, sigset);
+}
+
void
sigaddset_deferrable(sigset_t *s)
{
sigaddset(s, SIGHUP);
sigaddset(s, SIGINT);
+ sigaddset(s, SIGTERM);
sigaddset(s, SIGQUIT);
sigaddset(s, SIGPIPE);
sigaddset(s, SIGALRM);
sigaddset(s, SIGTSTP);
sigaddset(s, SIGCHLD);
sigaddset(s, SIGIO);
+#ifndef LISP_FEATURE_HPUX
sigaddset(s, SIGXCPU);
sigaddset(s, SIGXFSZ);
+#endif
sigaddset(s, SIGVTALRM);
sigaddset(s, SIGPROF);
sigaddset(s, SIGWINCH);
}
/* initialized in interrupt_init */
-static sigset_t deferrable_sigset;
-static sigset_t blockable_sigset;
+sigset_t deferrable_sigset;
+sigset_t blockable_sigset;
+#endif
+
+void
+check_deferrables_blocked_in_sigset_or_lose(sigset_t *sigset)
+{
+#if !defined(LISP_FEATURE_WIN32)
+ int i;
+ for(i = 1; i < NSIG; i++) {
+ if (sigismember(&deferrable_sigset, i) && !sigismember(sigset, i))
+ lose("deferrable signal %d not blocked\n",i);
+ }
+#endif
+}
+
+void
+check_deferrables_blocked_or_lose(void)
+{
+#if !defined(LISP_FEATURE_WIN32)
+ sigset_t current;
+ fill_current_sigmask(¤t);
+ check_deferrables_blocked_in_sigset_or_lose(¤t);
#endif
+}
void
check_blockables_blocked_or_lose(void)
dynamic_space_free_pointer =
(lispobj *)(unsigned long)
(*os_context_register_addr(context, reg_ALLOC));
- /* fprintf(stderr,"dynamic_space_free_pointer: %p\n", dynamic_space_free_pointer); */
+/* 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) {
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) {
+ lose("dead in fake_foreign_function_call, context = %x, d_s_f_p = %x\n", context, dynamic_space_free_pointer);
+ }
+#endif
#endif
#ifdef reg_BSP
current_binding_stack_pointer =
| (*os_context_register_addr(context, reg_ALLOC)
& LOWTAG_MASK);
/*
- ((unsigned long)(*os_context_register_addr(context, reg_ALLOC)) & ~LOWTAG_MASK)
+ ((unsigned long)(*os_context_register_addr(context, reg_ALLOC))
+ & ~LOWTAG_MASK)
| ((unsigned long) dynamic_space_free_pointer & LOWTAG_MASK);
*/
#endif
void
interrupt_handle_pending(os_context_t *context)
{
- /* There are three ways we can get here. First, if an interrupt
+ /* There are three ways we can get here. First, if an interrupt
* occurs within pseudo-atomic, it will be deferred, and we'll
- * trap to here at the end of the pseudo-atomic block. Second, if
+ * trap to here at the end of the pseudo-atomic block. Second, if
* the GC (in alloc()) decides that a GC is required, it will set
- * *GC-PENDING* and pseudo-atomic-interrupted, and alloc() is
- * always called from within pseudo-atomic, and thus we end up
- * here again. Third, when calling GC-ON or at the end of a
- * WITHOUT-GCING, MAYBE-HANDLE-PENDING-GC will trap to here if
- * there is a pending GC. */
+ * *GC-PENDING* and pseudo-atomic-interrupted if not *GC-INHIBIT*,
+ * and alloc() is always called from within pseudo-atomic, and
+ * thus we end up here again. Third, when calling GC-ON or at the
+ * end of a WITHOUT-GCING, MAYBE-HANDLE-PENDING-GC will trap to
+ * here if there is a pending GC. Fourth, ahem, at the end of
+ * WITHOUT-INTERRUPTS (bar complications with nesting). */
/* Win32 only needs to handle the GC cases (for now?) */
struct thread *thread;
- /* Punt if in PA section, marking it as interrupted. This can
- * happenat least if we pick up a GC request while in a
- * WITHOUT-GCING with an outer PA -- it is not immediately clear
- * to me that this should/could ever happen, but better safe then
- * sorry. --NS 2007-05-15 */
if (arch_pseudo_atomic_atomic(context)) {
- arch_set_pseudo_atomic_interrupted(context);
- return;
+ lose("Handling pending interrupt in pseduo atomic.");
}
thread = arch_os_get_current_thread();
store_signal_data_for_later(data,handler,signal,info,context);
SetSymbolValue(INTERRUPT_PENDING, T,thread);
FSHOW_SIGNAL((stderr,
- "/maybe_defer_handler(%x,%d),thread=%lu: deferred\n",
- (unsigned int)handler,signal,
- (unsigned long)thread->os_thread));
+ "/maybe_defer_handler(%x,%d): deferred\n",
+ (unsigned int)handler,signal));
return 1;
}
/* a slightly confusing test. arch_pseudo_atomic_atomic() doesn't
store_signal_data_for_later(data,handler,signal,info,context);
arch_set_pseudo_atomic_interrupted(context);
FSHOW_SIGNAL((stderr,
- "/maybe_defer_handler(%x,%d),thread=%lu: deferred(PA)\n",
- (unsigned int)handler,signal,
- (unsigned long)thread->os_thread));
+ "/maybe_defer_handler(%x,%d): deferred(PA)\n",
+ (unsigned int)handler,signal));
return 1;
}
FSHOW_SIGNAL((stderr,
- "/maybe_defer_handler(%x,%d),thread=%lu: not deferred\n",
- (unsigned int)handler,signal,
- (unsigned long)thread->os_thread));
+ "/maybe_defer_handler(%x,%d): not deferred\n",
+ (unsigned int)handler,signal));
return 0;
}
if(info)
memcpy(&(data->pending_info), info, sizeof(siginfo_t));
- FSHOW_SIGNAL((stderr, "/store_signal_data_for_later: signal: %d\n", signal));
+ FSHOW_SIGNAL((stderr, "/store_signal_data_for_later: signal: %d\n",
+ signal));
if(context) {
/* the signal mask in the context (from before we were
}
static void
-low_level_interrupt_handle_now(int signal, siginfo_t *info, os_context_t *context)
+low_level_interrupt_handle_now(int signal, siginfo_t *info,
+ os_context_t *context)
{
/* No FP control fixage needed, caller has done that. */
check_blockables_blocked_or_lose();
check_interrupts_enabled_or_lose(context);
- interrupt_low_level_handlers[signal](signal, info, context);
+ (*interrupt_low_level_handlers[signal])(signal, info, context);
/* No Darwin context fixage needed, caller does that. */
}
if (arch_pseudo_atomic_atomic(context)) {
SetSymbolValue(STOP_FOR_GC_PENDING,T,thread);
arch_set_pseudo_atomic_interrupted(context);
- FSHOW_SIGNAL((stderr,"thread=%lu sig_stop_for_gc deferred (PA)\n",
- thread->os_thread));
+ FSHOW_SIGNAL((stderr, "sig_stop_for_gc deferred (PA)\n"));
return;
}
else if (SymbolValue(GC_INHIBIT,thread) != NIL) {
SetSymbolValue(STOP_FOR_GC_PENDING,T,thread);
- FSHOW_SIGNAL((stderr,
- "thread=%lu sig_stop_for_gc deferred (*GC-INHIBIT*)\n",
- thread->os_thread));
+ FSHOW_SIGNAL((stderr, "sig_stop_for_gc deferred (*GC-INHIBIT*)\n"));
return;
}
}
thread->state=STATE_SUSPENDED;
- FSHOW_SIGNAL((stderr,"thread=%lu suspended\n",thread->os_thread));
+ FSHOW_SIGNAL((stderr,"suspended\n"));
sigemptyset(&ss);
#if defined(SIG_RESUME_FROM_GC)
while (sigwaitinfo(&ss,0) != SIG_STOP_FOR_GC);
#endif
- FSHOW_SIGNAL((stderr,"thread=%lu resumed\n",thread->os_thread));
+ FSHOW_SIGNAL((stderr,"resumed\n"));
if(thread->state!=STATE_RUNNING) {
lose("sig_stop_for_gc_handler: wrong thread state on wakeup: %ld\n",
fixnum_value(thread->state));
os_context_t *context = arch_os_get_context(&void_context);
#if defined(LISP_FEATURE_LINUX) || defined(RESTORE_FP_CONTROL_FROM_CONTEXT)
os_restore_fp_control(context);
+#ifndef LISP_FEATURE_WIN32
+ if ((signal == SIGILL) || (signal == SIGBUS)
+#ifndef LISP_FEATURE_LINUX
+ || (signal == SIGEMT)
+#endif
+ )
+ corruption_warning_and_maybe_lose("Signal %d recieved", signal);
+#endif
#endif
interrupt_handle_now(signal, info, context);
}
*os_context_register_addr(context,reg_CODE) =
(os_context_register_t)(fun + FUN_POINTER_LOWTAG);
#endif
+ FSHOW((stderr, "/arranged return to Lisp function (0x%lx)\n",
+ (long)function));
}
#ifdef LISP_FEATURE_SB_THREAD
{
os_context_t *context = (os_context_t*)arch_os_get_context(&v_context);
+ FSHOW_SIGNAL((stderr,"/interrupt_thread_handler\n"));
+ check_blockables_blocked_or_lose();
+
/* let the handler enable interrupts again when it sees fit */
sigaddset_deferrable(os_context_sigmask_addr(context));
- arrange_return_to_lisp_function(context, StaticSymbolFunction(RUN_INTERRUPTION));
+ arrange_return_to_lisp_function(context,
+ StaticSymbolFunction(RUN_INTERRUPTION));
}
#endif
* 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. */
+ corruption_warning_and_maybe_lose("Control stack exhausted");
protect_control_stack_guard_page(0);
protect_control_stack_return_guard_page(1);
#endif
}
+/* This must not go through lisp as it's allowed anytime, even when on
+ * the altstack. */
+void
+sigabrt_handler(int signal, siginfo_t *info, void *void_context)
+{
+ lose("SIGABRT received.\n");
+}
+
void
interrupt_init(void)
{
* 3-argument form is expected.) */
(void (*)(int, siginfo_t*, void*))SIG_DFL;
}
-
+ undoably_install_low_level_interrupt_handler(SIGABRT, sigabrt_handler);
SHOW("returning from interrupt_init()");
#endif
}
* now -- some address is better then no address in this case.
*/
current_memory_fault_address = addr;
- arrange_return_to_lisp_function(context, StaticSymbolFunction(MEMORY_FAULT_ERROR));
+ /* To allow debugging memory faults in signal handlers and such. */
+ corruption_warning_and_maybe_lose("Memory fault");
+ arrange_return_to_lisp_function(context,
+ StaticSymbolFunction(MEMORY_FAULT_ERROR));
}
#endif