0.9.0.8:
[sbcl.git] / src / runtime / interrupt.c
index 25b8943..1578aca 100644 (file)
@@ -124,32 +124,12 @@ struct interrupt_data * global_interrupt_data;
  * mask ought to be clear anyway most of the time, but may be non-zero
  * if we were interrupted e.g. while waiting for a queue.  */
 
-#if 1
 void reset_signal_mask () 
 {
     sigset_t new;
     sigemptyset(&new);
     sigprocmask(SIG_SETMASK,&new,0);
 }
-#else
-void reset_signal_mask () 
-{
-    sigset_t new,old;
-    int i;
-    int wrong=0;
-    sigemptyset(&new);
-    sigprocmask(SIG_SETMASK,&new,&old);
-    for(i=1; i<NSIG; i++) {
-       if(sigismember(&old,i)) {
-           fprintf(stderr,
-                   "Warning: signal %d is masked: this is unexpected\n",i);
-           wrong=1;
-       }
-    }
-    if(wrong) 
-       fprintf(stderr,"If this version of SBCL is less than three months old, please report this.\nOtherwise, please try a newer version first\n.  Reset signal mask.\n");
-}
-#endif
 
 
 
@@ -161,7 +141,7 @@ void reset_signal_mask ()
 void 
 build_fake_control_stack_frames(struct thread *th,os_context_t *context)
 {
-#ifndef LISP_FEATURE_X86
+#ifndef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
     
     lispobj oldcont;
 
@@ -219,7 +199,7 @@ fake_foreign_function_call(os_context_t *context)
 #ifdef reg_ALLOC
     dynamic_space_free_pointer =
        (lispobj *)(*os_context_register_addr(context, reg_ALLOC));
-#ifdef alpha
+#if defined(LISP_FEATURE_ALPHA)
     if ((long)dynamic_space_free_pointer & 1) {
        lose("dead in fake_foreign_function_call, context = %x", context);
     }
@@ -364,7 +344,7 @@ interrupt_handle_now(int signal, siginfo_t *info, void *void_context)
 {
     os_context_t *context = (os_context_t*)void_context;
     struct thread *thread=arch_os_get_current_thread();
-#ifndef LISP_FEATURE_X86
+#if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64)
     boolean were_in_lisp;
 #endif
     union interrupt_handler handler;
@@ -381,7 +361,7 @@ interrupt_handle_now(int signal, siginfo_t *info, void *void_context)
        return;
     }
     
-#ifndef LISP_FEATURE_X86
+#if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64)
     were_in_lisp = !foreign_function_call_active;
     if (were_in_lisp)
 #endif
@@ -440,7 +420,7 @@ interrupt_handle_now(int signal, siginfo_t *info, void *void_context)
         (*handler.c)(signal, info, void_context);
     }
 
-#ifndef LISP_FEATURE_X86
+#if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64)
     if (were_in_lisp)
 #endif
     {
@@ -481,7 +461,7 @@ maybe_defer_handler(void *handler, struct interrupt_data *data,
      * actually use its argument for anything on x86, so this branch
      * may succeed even when context is null (gencgc alloc()) */
     if (
-#ifndef LISP_FEATURE_X86
+#if !defined(LISP_FEATURE_X86) && !defined(LISP_FEATURE_X86_64)
        (!foreign_function_call_active) &&
 #endif
        arch_pseudo_atomic_atomic(context)) {
@@ -537,7 +517,7 @@ maybe_now_maybe_later(int signal, siginfo_t *info, void *void_context)
     interrupt_handle_now(signal, info, context);
 #ifdef LISP_FEATURE_DARWIN
     /* Work around G5 bug */
-    sigreturn(void_context);
+    DARWIN_FIX_CONTEXT(context);
 #endif
 }
 
@@ -583,7 +563,7 @@ interrupt_handle_now_handler(int signal, siginfo_t *info, void *void_context)
     os_context_t *context = arch_os_get_context(&void_context);
     interrupt_handle_now(signal, info, context);
 #ifdef LISP_FEATURE_DARWIN
-    sigreturn(void_context);
+    DARWIN_FIX_CONTEXT(context);
 #endif
 }
 
@@ -615,7 +595,7 @@ extern lispobj call_into_lisp(lispobj fun, lispobj *args, int nargs);
 extern void post_signal_tramp(void);
 void arrange_return_to_lisp_function(os_context_t *context, lispobj function)
 {
-#ifndef LISP_FEATURE_X86
+#if !(defined(LISP_FEATURE_X86) || defined(LISP_FEATURE_X86_64))
     void * fun=native_pointer(function);
     void *code = &(((struct simple_fun *) fun)->code);
 #endif    
@@ -625,10 +605,31 @@ void arrange_return_to_lisp_function(os_context_t *context, lispobj function)
 #ifdef LISP_FEATURE_X86
     /* Suppose the existence of some function that saved all
      * registers, called call_into_lisp, then restored GP registers and
-     * returned.  We shortcut this: fake the stack that call_into_lisp
-     * would see, then arrange to have it called directly.  post_signal_tramp
-     * is the second half of this function
+     * returned.  It would look something like this:
+
+     push   ebp
+     mov    ebp esp
+     pushad
+     push   $0
+     push   $0
+     pushl  {address of function to call}
+     call   0x8058db0 <call_into_lisp>
+     addl   $12,%esp
+     popa
+     leave  
+     ret    
+
+     * What we do here is set up the stack that call_into_lisp would
+     * expect to see if it had been called by this code, and frob the
+     * signal context so that signal return goes directly to call_into_lisp,
+     * and when that function (and the lisp function it invoked) returns,
+     * it returns to the second half of this imaginary function which
+     * restores all registers and returns to C
+
+     * For this to work, the latter part of the imaginary function
+     * must obviously exist in reality.  That would be post_signal_tramp
      */
+
     u32 *sp=(u32 *)*os_context_register_addr(context,reg_ESP);
 
     *(sp-14) = post_signal_tramp; /* return address for call_into_lisp */
@@ -638,9 +639,9 @@ void arrange_return_to_lisp_function(os_context_t *context, lispobj function)
     /* this order matches that used in POPAD */
     *(sp-10)=*os_context_register_addr(context,reg_EDI);
     *(sp-9)=*os_context_register_addr(context,reg_ESI);
-    /* this gets overwritten again before it's used, anyway */
-    *(sp-8)=*os_context_register_addr(context,reg_EBP);
-    *(sp-7)=0 ; /* POPAD doesn't set ESP, but expects a gap for it anyway */
+
+    *(sp-8)=*os_context_register_addr(context,reg_ESP)-8;
+    *(sp-7)=0;
     *(sp-6)=*os_context_register_addr(context,reg_EBX);
 
     *(sp-5)=*os_context_register_addr(context,reg_EDX);
@@ -649,6 +650,32 @@ void arrange_return_to_lisp_function(os_context_t *context, lispobj function)
     *(sp-2)=*os_context_register_addr(context,reg_EBP);
     *(sp-1)=*os_context_pc_addr(context);
 
+#elif defined(LISP_FEATURE_X86_64)
+    u64 *sp=(u64 *)*os_context_register_addr(context,reg_RSP);
+    *(sp-19) = post_signal_tramp;  /* return address for call_into_lisp */
+
+    *(sp-18)=*os_context_register_addr(context,reg_R15);
+    *(sp-17)=*os_context_register_addr(context,reg_R14);
+    *(sp-16)=*os_context_register_addr(context,reg_R13);
+    *(sp-15)=*os_context_register_addr(context,reg_R12);
+    *(sp-14)=*os_context_register_addr(context,reg_R11);
+    *(sp-13)=*os_context_register_addr(context,reg_R10);
+    *(sp-12)=*os_context_register_addr(context,reg_R9);
+    *(sp-11)=*os_context_register_addr(context,reg_R8);
+    *(sp-10)=*os_context_register_addr(context,reg_RDI);
+    *(sp-9)=*os_context_register_addr(context,reg_RSI);
+    *(sp-8)=*os_context_register_addr(context,reg_RSP)-16;
+    *(sp-7)=0;
+    *(sp-6)=*os_context_register_addr(context,reg_RBX);
+    *(sp-5)=*os_context_register_addr(context,reg_RDX);
+    *(sp-4)=*os_context_register_addr(context,reg_RCX);
+    *(sp-3)=*os_context_register_addr(context,reg_RAX);
+    *(sp-2)=*os_context_register_addr(context,reg_RBP);
+    *(sp-1)=*os_context_pc_addr(context);
+
+    *os_context_register_addr(context,reg_RDI) = function; /* function */
+    *os_context_register_addr(context,reg_RSI) = 0;        /* arg. array */
+    *os_context_register_addr(context,reg_RDX) = 0;        /* no. args */
 #else 
     struct thread *th=arch_os_get_current_thread();
     build_fake_control_stack_frames(th,context);
@@ -658,7 +685,16 @@ void arrange_return_to_lisp_function(os_context_t *context, lispobj function)
     *os_context_pc_addr(context) = call_into_lisp;
     *os_context_register_addr(context,reg_ECX) = 0; 
     *os_context_register_addr(context,reg_EBP) = sp-2;
+#ifdef __NetBSD__ 
+    *os_context_register_addr(context,reg_UESP) = sp-14;
+#else
     *os_context_register_addr(context,reg_ESP) = sp-14;
+#endif
+#elif defined(LISP_FEATURE_X86_64)
+    *os_context_pc_addr(context) = call_into_lisp;
+    *os_context_register_addr(context,reg_RCX) = 0; 
+    *os_context_register_addr(context,reg_RBP) = sp-2;
+    *os_context_register_addr(context,reg_RSP) = sp-19;
 #else
     /* this much of the calling convention is common to all
        non-x86 ports */
@@ -695,22 +731,51 @@ void thread_exit_handler(int num, siginfo_t *info, void *v_context)
 {   /* called when a child thread exits */
     mark_dead_threads();
 }
-
        
 #endif
 
-boolean handle_control_stack_guard_triggered(os_context_t *context,void *addr){
+/* 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,
+ * that has the added benefit of automatically discriminating between
+ * functions and variables. 
+ */
+void undefined_alien_function() {
+    funcall0(SymbolFunction(UNDEFINED_ALIEN_FUNCTION_ERROR));
+}
+
+boolean handle_guard_page_triggered(os_context_t *context,void *addr){
     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>=(void *)CONTROL_STACK_GUARD_PAGE(th) && 
-       addr<(void *)(CONTROL_STACK_GUARD_PAGE(th)+os_vm_page_size)) {
-       /* we hit the end of the control stack.  disable protection
-        * temporarily so the error handler has some headroom */
-       protect_control_stack_guard_page(th->pid,0L);
-       
+    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. */
+        protect_control_stack_guard_page(th->pid,0);
+        protect_control_stack_return_guard_page(th->pid,1);
+        
+        arrange_return_to_lisp_function
+            (context, SymbolFunction(CONTROL_STACK_EXHAUSTED_ERROR));
+        return 1;
+    }
+    else if(addr >= CONTROL_STACK_RETURN_GUARD_PAGE(th) &&
+            addr < CONTROL_STACK_RETURN_GUARD_PAGE(th) + os_vm_page_size) {
+        /* We're returning from the guard page: reprotect it, and
+         * 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(th->pid,1);
+        protect_control_stack_return_guard_page(th->pid,0);
+        return 1;
+    }
+    else if (addr >= undefined_alien_address &&
+            addr < undefined_alien_address + os_vm_page_size) {
        arrange_return_to_lisp_function
-           (context, SymbolFunction(CONTROL_STACK_EXHAUSTED_ERROR));
+          (context, SymbolFunction(UNDEFINED_ALIEN_VARIABLE_ERROR));
        return 1;
     }
     else return 0;