X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Finterrupt.c;h=723952885ef581e55585a4b2d1a621b670ec2ac8;hb=c3699db2053ff3b5ac6a98d4431c3789496002d8;hp=8ee462e8f2890a646be1824a8502d2c6950c0d9d;hpb=9ab3c4123f5802bc5d4771eda564680d1a2c1a2f;p=sbcl.git diff --git a/src/runtime/interrupt.c b/src/runtime/interrupt.c index 8ee462e..7239528 100644 --- a/src/runtime/interrupt.c +++ b/src/runtime/interrupt.c @@ -45,6 +45,8 @@ #include #include #include +#include +#include #include "runtime.h" #include "arch.h" @@ -62,6 +64,8 @@ #include "genesis/fdefn.h" #include "genesis/simple-fun.h" + + void run_deferred_handler(struct interrupt_data *data, void *v_context) ; static void store_signal_data_for_later (struct interrupt_data *data, void *handler, int signal, @@ -69,8 +73,8 @@ static void store_signal_data_for_later (struct interrupt_data *data, os_context_t *context); boolean interrupt_maybe_gc_int(int signal, siginfo_t *info, void *v_context); -extern lispobj all_threads_lock; -extern int countdown_to_gc; +extern volatile lispobj all_threads_lock; +extern volatile int countdown_to_gc; /* * This is a workaround for some slightly silly Linux/GNU Libc @@ -103,9 +107,9 @@ void sigaddset_blockable(sigset_t *s) sigaddset(s, SIGUSR1); sigaddset(s, SIGUSR2); #ifdef LISP_FEATURE_SB_THREAD - /* don't block STOP_FOR_GC, we need to be able to interrupt threads - * for GC purposes even when they are blocked on queues etc */ + sigaddset(s, SIG_STOP_FOR_GC); sigaddset(s, SIG_INTERRUPT_THREAD); + sigaddset(s, SIG_THREAD_EXIT); #endif } @@ -118,6 +122,39 @@ boolean internal_errors_enabled = 0; struct interrupt_data * global_interrupt_data; +/* At the toplevel repl we routinely call this function. The signal + * 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; iinterrupt_data; + /* FIXME I'm not altogether sure this is appropriate if we're + * here as the result of a pseudo-atomic */ SetSymbolValue(INTERRUPT_PENDING, NIL,thread); /* restore the saved signal mask from the original signal (the @@ -327,7 +366,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 __i386__ +#ifndef LISP_FEATURE_X86 boolean were_in_lisp; #endif union interrupt_handler handler; @@ -344,7 +383,7 @@ interrupt_handle_now(int signal, siginfo_t *info, void *void_context) return; } -#ifndef __i386__ +#ifndef LISP_FEATURE_X86 were_in_lisp = !foreign_function_call_active; if (were_in_lisp) #endif @@ -403,11 +442,11 @@ interrupt_handle_now(int signal, siginfo_t *info, void *void_context) (*handler.c)(signal, info, void_context); } -#ifndef __i386__ +#ifndef LISP_FEATURE_X86 if (were_in_lisp) #endif { - undo_fake_foreign_function_call(context); + undo_fake_foreign_function_call(context); /* block signals again */ } #ifdef QSHOW_SIGNALS @@ -425,10 +464,9 @@ interrupt_handle_now(int signal, siginfo_t *info, void *void_context) void run_deferred_handler(struct interrupt_data *data, void *v_context) { - fprintf(stderr,"Running deferred handler for %d, 0x%x\n", - data->pending_signal, data->pending_handler); (*(data->pending_handler)) (data->pending_signal,&(data->pending_info), v_context); + data->pending_handler=0; } boolean @@ -445,7 +483,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 __i386__ +#ifndef LISP_FEATURE_X86 (!foreign_function_call_active) && #endif arch_pseudo_atomic_atomic(context)) { @@ -507,23 +545,20 @@ sig_stop_for_gc_handler(int signal, siginfo_t *info, void *void_context) os_context_t *context = arch_os_get_context(&void_context); struct thread *thread=arch_os_get_current_thread(); struct interrupt_data *data=thread->interrupt_data; - sigset_t block; + if(maybe_defer_handler(sig_stop_for_gc_handler,data, signal,info,context)){ return; } - sigemptyset(&block); - sigaddset_blockable(&block); - sigprocmask(SIG_BLOCK, &block, 0); - /* need the context stored so it can have registers scavenged */ fake_foreign_function_call(context); get_spinlock(&all_threads_lock,thread->pid); countdown_to_gc--; + thread->state=STATE_STOPPED; release_spinlock(&all_threads_lock); - kill(getpid(),SIGSTOP); + kill(thread->pid,SIGSTOP); undo_fake_foreign_function_call(context); } @@ -625,17 +660,40 @@ void arrange_return_to_lisp_function(os_context_t *context, lispobj function) } #ifdef LISP_FEATURE_SB_THREAD -void handle_rt_signal(int num, siginfo_t *info, void *v_context) +void interrupt_thread_handler(int num, siginfo_t *info, void *v_context) { os_context_t *context = (os_context_t*)arch_os_get_context(&v_context); struct thread *th=arch_os_get_current_thread(); struct interrupt_data *data= th ? th->interrupt_data : global_interrupt_data; - if(maybe_defer_handler(handle_rt_signal,data,num,info,context)){ + if(maybe_defer_handler(interrupt_thread_handler,data,num,info,context)){ return ; } arrange_return_to_lisp_function(context,info->si_value.sival_int); } + +void thread_exit_handler(int num, siginfo_t *info, void *v_context) +{ /* called when a child thread exits */ + os_context_t *context = (os_context_t*)arch_os_get_context(&v_context); + struct thread *th=arch_os_get_current_thread(); + pid_t kid; + int *status; + struct interrupt_data *data= + th ? th->interrupt_data : global_interrupt_data; + if(maybe_defer_handler(thread_exit_handler,data,num,info,context)){ + return ; + } + while(1) { + kid=waitpid(-1,&status,__WALL|WNOHANG); + if(kid<1) break; + if(WIFEXITED(status) || WIFSIGNALED(status)) { + struct thread *th=find_thread_by_pid(kid); + if(!th) continue; + funcall1(SymbolFunction(HANDLE_THREAD_EXIT),make_fixnum(kid)); + destroy_thread(th); + } + } +} #endif boolean handle_control_stack_guard_triggered(os_context_t *context,void *addr){ @@ -682,16 +740,22 @@ interrupt_maybe_gc(int signal, siginfo_t *info, void *void_context) #endif -/* this is also used by from gencgc.c alloc() */ +/* this is also used by gencgc, in alloc() */ boolean interrupt_maybe_gc_int(int signal, siginfo_t *info, void *void_context) { + sigset_t new; os_context_t *context=(os_context_t *) void_context; fake_foreign_function_call(context); /* SUB-GC may return without GCing if *GC-INHIBIT* is set, in * which case we will be running with no gc trigger barrier * thing for a while. But it shouldn't be long until the end * of WITHOUT-GCING. */ + + sigemptyset(&new); + sigaddset_blockable(&new); + /* enable signals before calling into Lisp */ + sigprocmask(SIG_UNBLOCK,&new,0); funcall0(SymbolFunction(SUB_GC)); undo_fake_foreign_function_call(context); return 1;