#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"
#include "genesis/cons.h"
+/* When we catch an internal error, should we pass it back to Lisp to
+ * be handled in a high-level way? (Early in cold init, the answer is
+ * 'no', because Lisp is still too brain-dead to handle anything.
+ * After sufficient initialization has been completed, the answer
+ * becomes 'yes'.) */
+boolean internal_errors_enabled = 0;
+
+#ifndef LISP_FEATURE_WIN32
+static
+void (*interrupt_low_level_handlers[NSIG]) (int, siginfo_t*, os_context_t*);
+#endif
+union interrupt_handler interrupt_handlers[NSIG];
+
/* Under Linux on some architectures, we appear to have to restore the
* FPU control word from the context, as after the signal is delivered
* we appear to have a null FPU control word. */
os_context_t *context = arch_os_get_context(&void_context);
#endif
+/* Foreign code may want to start some threads on its own.
+ * Non-targetted, truly asynchronous signals can be delivered to
+ * basically any thread, but invoking Lisp handlers in such foregign
+ * threads is really bad, so let's resignal it.
+ *
+ * This should at least bring attention to the problem, but it cannot
+ * 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)
+{
+ int i;
+ for(i = 1; i < NSIG; i++) {
+ if (!(ARE_SAME_HANDLER(interrupt_low_level_handlers[i], SIG_DFL)) ||
+ !(ARE_SAME_HANDLER(interrupt_handlers[i].c, SIG_DFL))) {
+ sigaddset(sigset, i);
+ }
+ }
+}
+
+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)
+{
+#ifdef LISP_FEATURE_SB_THREAD
+ if (!pthread_getspecific(lisp_thread)) {
+ if (!(sigismember(&deferrable_sigset,signal))) {
+ corruption_warning_and_maybe_lose
+ ("Received signal %d in non-lisp thread %lu, resignalling to a lisp thread.",
+ signal,
+ pthread_self());
+ }
+ {
+ sigset_t sigset;
+ sigemptyset(&sigset);
+ add_handled_signals(&sigset);
+ block_signals(&sigset, 0, 0);
+ block_signals(&sigset, os_context_sigmask_addr(context), 0);
+ kill(getpid(), signal);
+ }
+ return 1;
+ } else
+#endif
+ return 0;
+}
+
/* These are to be used in signal handlers. Currently all handlers are
* called from one of:
*
* kernel properly, so we fix it up ourselves in the
* arch_os_get_context(..) function. -- CSR, 2002-07-23
*/
-#define SAVE_ERRNO(context,void_context) \
+#define SAVE_ERRNO(signal,context,void_context) \
{ \
int _saved_errno = errno; \
RESTORE_FP_CONTROL_WORD(context,void_context); \
+ if (!maybe_resignal_to_lisp_thread(signal, context)) \
{
#define RESTORE_ERRNO \
#endif
+#if !defined(LISP_FEATURE_WIN32)
boolean
deferrables_blocked_p(sigset_t *sigset)
{
return all_signals_blocked_p(sigset, &deferrable_sigset, "deferrable");
}
+#endif
void
check_deferrables_unblocked_or_lose(sigset_t *sigset)
#endif
}
+#if !defined(LISP_FEATURE_WIN32)
boolean
blockables_blocked_p(sigset_t *sigset)
{
return all_signals_blocked_p(sigset, &blockable_sigset, "blockable");
}
+#endif
void
check_blockables_unblocked_or_lose(sigset_t *sigset)
#endif
}
+#if !defined(LISP_FEATURE_WIN32)
boolean
gc_signals_blocked_p(sigset_t *sigset)
{
return all_signals_blocked_p(sigset, &gc_sigset, "gc");
}
+#endif
void
check_gc_signals_unblocked_or_lose(sigset_t *sigset)
}
#endif
}
-
-/* When we catch an internal error, should we pass it back to Lisp to
- * be handled in a high-level way? (Early in cold init, the answer is
- * 'no', because Lisp is still too brain-dead to handle anything.
- * After sufficient initialization has been completed, the answer
- * becomes 'yes'.) */
-boolean internal_errors_enabled = 0;
-
-#ifndef LISP_FEATURE_WIN32
-static
-void (*interrupt_low_level_handlers[NSIG]) (int, siginfo_t*, os_context_t*);
-#endif
-union interrupt_handler interrupt_handlers[NSIG];
-
\f
/*
* utility routines used by various signal handlers
static void
maybe_now_maybe_later(int signal, siginfo_t *info, void *void_context)
{
- SAVE_ERRNO(context,void_context);
+ SAVE_ERRNO(signal,context,void_context);
struct thread *thread = arch_os_get_current_thread();
struct interrupt_data *data = thread->interrupt_data;
-
if(!maybe_defer_handler(interrupt_handle_now,data,signal,info,context))
interrupt_handle_now(signal, info, context);
RESTORE_ERRNO;
static void
low_level_maybe_now_maybe_later(int signal, siginfo_t *info, void *void_context)
{
- SAVE_ERRNO(context,void_context);
+ SAVE_ERRNO(signal,context,void_context);
struct thread *thread = arch_os_get_current_thread();
struct interrupt_data *data = thread->interrupt_data;
void
interrupt_handle_now_handler(int signal, siginfo_t *info, void *void_context)
{
- SAVE_ERRNO(context,void_context);
+ SAVE_ERRNO(signal,context,void_context);
#ifndef LISP_FEATURE_WIN32
if ((signal == SIGILL) || (signal == SIGBUS)
#ifndef LISP_FEATURE_LINUX
{
struct thread *th=arch_os_get_current_thread();
- /* note the os_context hackery here. When the signal handler returns,
- * it won't go back to what it was doing ... */
- if(addr >= CONTROL_STACK_GUARD_PAGE(th) &&
- addr < CONTROL_STACK_GUARD_PAGE(th) + os_vm_page_size) {
+ if(addr >= CONTROL_STACK_HARD_GUARD_PAGE(th) &&
+ addr < CONTROL_STACK_HARD_GUARD_PAGE(th) + os_vm_page_size) {
+ lose("Control stack exhausted");
+ }
+ else if(addr >= CONTROL_STACK_GUARD_PAGE(th) &&
+ addr < CONTROL_STACK_GUARD_PAGE(th) + os_vm_page_size) {
/* We hit the end of the control stack: disable guard page
* 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, NULL);
protect_control_stack_return_guard_page(1, NULL);
+ fprintf(stderr, "INFO: Control stack guard page unprotected\n");
#ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
/* For the unfortunate case, when the control stack is
* unprotect this one. This works even if we somehow missed
* the return-guard-page, and hit it on our way to new
* exhaustion instead. */
- fprintf(stderr, "INFO: Control stack guard page reprotected\n");
protect_control_stack_guard_page(1, NULL);
protect_control_stack_return_guard_page(0, NULL);
+ fprintf(stderr, "INFO: Control stack guard page reprotected\n");
return 1;
}
+ else if(addr >= BINDING_STACK_HARD_GUARD_PAGE(th) &&
+ addr < BINDING_STACK_HARD_GUARD_PAGE(th) + os_vm_page_size) {
+ lose("Binding stack exhausted");
+ }
else if(addr >= BINDING_STACK_GUARD_PAGE(th) &&
addr < BINDING_STACK_GUARD_PAGE(th) + os_vm_page_size) {
- corruption_warning_and_maybe_lose("Binding stack exhausted");
protect_binding_stack_guard_page(0, NULL);
protect_binding_stack_return_guard_page(1, NULL);
+ fprintf(stderr, "INFO: Binding stack guard page unprotected\n");
/* For the unfortunate case, when the binding stack is
* exhausted in a signal handler. */
}
else if(addr >= BINDING_STACK_RETURN_GUARD_PAGE(th) &&
addr < BINDING_STACK_RETURN_GUARD_PAGE(th) + os_vm_page_size) {
- fprintf(stderr, "INFO: Binding stack guard page reprotected\n");
protect_binding_stack_guard_page(1, NULL);
protect_binding_stack_return_guard_page(0, NULL);
+ fprintf(stderr, "INFO: Binding stack guard page reprotected\n");
return 1;
}
+ else if(addr >= ALIEN_STACK_HARD_GUARD_PAGE(th) &&
+ addr < ALIEN_STACK_HARD_GUARD_PAGE(th) + os_vm_page_size) {
+ lose("Alien stack exhausted");
+ }
else if(addr >= ALIEN_STACK_GUARD_PAGE(th) &&
addr < ALIEN_STACK_GUARD_PAGE(th) + os_vm_page_size) {
- corruption_warning_and_maybe_lose("Alien stack exhausted");
protect_alien_stack_guard_page(0, NULL);
protect_alien_stack_return_guard_page(1, NULL);
+ fprintf(stderr, "INFO: Alien stack guard page unprotected\n");
/* For the unfortunate case, when the alien stack is
* exhausted in a signal handler. */
}
else if(addr >= ALIEN_STACK_RETURN_GUARD_PAGE(th) &&
addr < ALIEN_STACK_RETURN_GUARD_PAGE(th) + os_vm_page_size) {
- fprintf(stderr, "INFO: Alien stack guard page reprotected\n");
protect_alien_stack_guard_page(1, NULL);
protect_alien_stack_return_guard_page(0, NULL);
+ fprintf(stderr, "INFO: Alien stack guard page reprotected\n");
return 1;
}
else if (addr >= undefined_alien_address &&
static void
unblock_me_trampoline(int signal, siginfo_t *info, void *void_context)
{
- SAVE_ERRNO(context,void_context);
+ SAVE_ERRNO(signal,context,void_context);
sigset_t unblock;
sigemptyset(&unblock);
static void
low_level_unblock_me_trampoline(int signal, siginfo_t *info, void *void_context)
{
- SAVE_ERRNO(context,void_context);
+ SAVE_ERRNO(signal,context,void_context);
sigset_t unblock;
sigemptyset(&unblock);
static void
low_level_handle_now_handler(int signal, siginfo_t *info, void *void_context)
{
- SAVE_ERRNO(context,void_context);
+ SAVE_ERRNO(signal,context,void_context);
(*interrupt_low_level_handlers[signal])(signal, info, context);
RESTORE_ERRNO;
}