From: Daniel B. <da...@us...> - 2003-09-30 11:23:08
|
Update of /cvsroot/sbcl/sbcl/src/runtime In directory sc8-pr-cvs1:/tmp/cvs-serv31939/src/runtime Modified Files: Tag: atropos-branch alloc.c breakpoint.c cheneygc.c gencgc.c interrupt.c linux-os.c linux-os.h runtime.c thread.c thread.h x86-linux-os.c x86-linux-os.h Log Message: 0.8.3.95.atropos.1 ; cutting threads There is getting to be rather a lot of sensible but not-now-while-we're-releasing code in my thread/gc fix. So here it is on a branch, hopefully minus the slightly more evil debugging crud doc/ - fix up some of the sgml errors that sourceforge keeps mailing me about New function release-spinlock that only changes the lock value if we owned the spinlock, so good for unwind-protect cleanups when lock acquisition failed get-spinlock release-spinlock current-thread-id could all win from being inlinable Use a RT signal (SIG_DEQUEUE) for resuming threads that were on queues, instead of having SIGCONT do both this and the resume-after-gc task. Scattered commentary describing the state of the signal mask in various interesting places In gencgc alloc, only install a deferred handler for GC if there was no previous handler for anything else. This fixes a longstanding bug where the GC thread would eat all cpu while waiting indefinitely for othr threads to stop. Add SIG_STOP_FOR_GC to the blockable list interrupt_maybe_gc_int: enable signals before calling SUB-GC, or the locking that sub-gc does is going to interact badly. Minor rearrangement to parent thread to stop it having to wake up on every GC Inline arch_os_get_current_thread (note, thread.h is not a sensible place for an x86linuxonly operation, rearrange this before committing to HEAD) Add grovel_headers lines for our RT signals. OAOOM alert... (Actually, of these three we only need SIG-DEQUEUE) Index: alloc.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/alloc.c,v retrieving revision 1.16 retrieving revision 1.16.8.1 diff -u -d -r1.16 -r1.16.8.1 --- alloc.c 16 Jul 2003 08:26:03 -0000 1.16 +++ alloc.c 30 Sep 2003 11:23:04 -0000 1.16.8.1 @@ -17,6 +17,7 @@ #include <stdio.h> #include <string.h> +#include "genesis/config.h" #include "runtime.h" #include "os.h" #include "sbcl.h" Index: breakpoint.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/breakpoint.c,v retrieving revision 1.13 retrieving revision 1.13.4.1 diff -u -d -r1.13 -r1.13.4.1 --- breakpoint.c 18 Sep 2003 21:09:09 -0000 1.13 +++ breakpoint.c 30 Sep 2003 11:23:04 -0000 1.13.4.1 @@ -145,7 +145,8 @@ fake_foreign_function_call(context); code = find_code(context); - + /* FIXME we're calling into Lisp with signals masked here. Is this + * the right thing to do? */ funcall3(SymbolFunction(HANDLE_BREAKPOINT), compute_offset(context, code), code, @@ -187,6 +188,8 @@ code = find_code(context); codeptr = (struct code *)native_pointer(code); + /* FIXME again, calling into Lisp with signals masked. Is this + * sensible? */ funcall3(SymbolFunction(HANDLE_BREAKPOINT), compute_offset(context, code), code, Index: cheneygc.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/cheneygc.c,v retrieving revision 1.6 retrieving revision 1.6.12.1 diff -u -d -r1.6 -r1.6.12.1 --- cheneygc.c 5 May 2003 23:27:08 -0000 1.6 +++ cheneygc.c 30 Sep 2003 11:23:04 -0000 1.6.12.1 @@ -136,6 +136,8 @@ gettimeofday(&start_tv, (struct timezone *) 0); #endif + /* it's possible that signals are blocked already if this was called + * from a signal handler (e.g. with the sigsegv gc_trigger stuff) */ sigemptyset(&tmp); sigaddset_blockable(&tmp); sigprocmask(SIG_BLOCK, &tmp, &old); Index: gencgc.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/gencgc.c,v retrieving revision 1.40 retrieving revision 1.40.4.1 diff -u -d -r1.40 -r1.40.4.1 --- gencgc.c 22 Sep 2003 23:01:14 -0000 1.40 +++ gencgc.c 30 Sep 2003 11:23:04 -0000 1.40.4.1 @@ -687,7 +687,7 @@ max_new_areas = new_areas_index; } -/* Update the tables for the alloc_region. The region maybe added to +/* Update the tables for the alloc_region. The region may be added to * the new_areas. * * When done the alloc_region is set up so that the next quick alloc @@ -4249,9 +4249,13 @@ */ if (auto_gc_trigger && bytes_allocated > auto_gc_trigger) { /* set things up so that GC happens when we finish the PA - * section. */ + * section. We only do this if there wasn't a pending handler + * already, in case it was a gc. If it wasn't a GC, the next + * allocation will get us back to this point anyway, so no harm done + */ struct interrupt_data *data=th->interrupt_data; - maybe_defer_handler(interrupt_maybe_gc_int,data,0,0,0); + if(!data->pending_handler) + maybe_defer_handler(interrupt_maybe_gc_int,data,0,0,0); } new_obj = gc_alloc_with_region(nbytes,0,region,0); return (new_obj); Index: interrupt.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/interrupt.c,v retrieving revision 1.46 retrieving revision 1.46.4.1 diff -u -d -r1.46 -r1.46.4.1 --- interrupt.c 18 Sep 2003 23:15:57 -0000 1.46 +++ interrupt.c 30 Sep 2003 11:23:04 -0000 1.46.4.1 @@ -103,8 +103,7 @@ 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); #endif } @@ -276,7 +275,7 @@ * before the Lisp error handling mechanism is set up. */ lose("internal error too early in init, can't recover"); } - undo_fake_foreign_function_call(context); + undo_fake_foreign_function_call(context); /* blocks signals again */ if (continuable) { arch_skip_instruction(context); } @@ -290,6 +289,8 @@ thread=arch_os_get_current_thread(); data=thread->interrupt_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 @@ -407,7 +408,7 @@ if (were_in_lisp) #endif { - undo_fake_foreign_function_call(context); + undo_fake_foreign_function_call(context); /* block signals again */ } #ifdef QSHOW_SIGNALS @@ -427,6 +428,7 @@ run_deferred_handler(struct interrupt_data *data, void *v_context) { (*(data->pending_handler)) (data->pending_signal,&(data->pending_info), v_context); + data->pending_handler=0; } boolean @@ -505,23 +507,19 @@ 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--; release_spinlock(&all_threads_lock); - kill(getpid(),SIGSTOP); + kill(thread->pid,SIGSTOP); undo_fake_foreign_function_call(context); } @@ -680,16 +678,22 @@ #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; Index: linux-os.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/linux-os.c,v retrieving revision 1.29 retrieving revision 1.29.4.1 diff -u -d -r1.29 -r1.29.4.1 --- linux-os.c 18 Sep 2003 21:09:10 -0000 1.29 +++ linux-os.c 30 Sep 2003 11:23:04 -0000 1.29.4.1 @@ -268,7 +268,7 @@ undoably_install_low_level_interrupt_handler(SIG_STOP_FOR_GC, sig_stop_for_gc_handler); #endif - undoably_install_low_level_interrupt_handler(SIGCONT, + undoably_install_low_level_interrupt_handler(SIG_DEQUEUE, sigcont_handler); } Index: linux-os.h =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/linux-os.h,v retrieving revision 1.9 retrieving revision 1.9.6.1 diff -u -d -r1.9 -r1.9.6.1 --- linux-os.h 25 Aug 2003 21:00:02 -0000 1.9 +++ linux-os.h 30 Sep 2003 11:23:04 -0000 1.9.6.1 @@ -39,5 +39,6 @@ #define SIG_MEMORY_FAULT SIGSEGV #define SIG_INTERRUPT_THREAD SIGRTMIN #define SIG_STOP_FOR_GC (SIGRTMIN+1) +#define SIG_DEQUEUE (SIGRTMIN+2) Index: runtime.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/runtime.c,v retrieving revision 1.31 retrieving revision 1.31.6.1 diff -u -d -r1.31 -r1.31.6.1 --- runtime.c 25 Aug 2003 21:00:02 -0000 1.31 +++ runtime.c 30 Sep 2003 11:23:04 -0000 1.31.6.1 @@ -407,7 +407,7 @@ while(!all_threads) { sched_yield(); } - while(all_threads && (pid=waitpid(-1,&status,__WALL|WUNTRACED))) { + while(all_threads && (pid=waitpid(-1,&status,__WALL))) { struct thread *th; int real_errno=errno; if(pid==-1) { @@ -418,9 +418,9 @@ fprintf(stderr,"waitpid: %s\n",strerror(real_errno)); continue; } - th=find_thread_by_pid(pid); - if(!th) continue; if(WIFEXITED(status) || WIFSIGNALED(status)) { + th=find_thread_by_pid(pid); + if(!th) continue; fprintf(stderr,"waitpid : child %d %x exited \n", pid,th); destroy_thread(th); if(!all_threads) break; Index: thread.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/thread.c,v retrieving revision 1.14 retrieving revision 1.14.4.1 diff -u -d -r1.14 -r1.14.4.1 --- thread.c 22 Sep 2003 23:01:14 -0000 1.14 +++ thread.c 30 Sep 2003 11:23:04 -0000 1.14.4.1 @@ -270,7 +270,7 @@ */ sigset_t newset; sigemptyset(&newset); - sigaddset(&newset,SIGCONT); + sigaddset(&newset,SIG_DEQUEUE); sigprocmask(SIG_BLOCK, &newset, 0); } @@ -282,7 +282,7 @@ { sigset_t set; sigemptyset(&set); - sigaddset(&set,SIGCONT); + sigaddset(&set,SIG_DEQUEUE); do { errno=0; sigwaitinfo(&set,0); @@ -297,6 +297,14 @@ return sigqueue(pid, SIG_INTERRUPT_THREAD, sigval); } + +/* stopping the world is a two-stage process. From this thread we signal + * all the others with SIG_STOP_FOR_GC. The handler for this thread does + * the usual pseudo-atomic checks (we don't want to stop a thread while + * it's in the middle of allocation) then kills _itself_ with SIGSTOP. + * At any given time, countdown_to_gc should reflect the number of threads + * signalled but which haven't yet come to rest + */ void gc_stop_the_world() { Index: thread.h =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/thread.h,v retrieving revision 1.7 retrieving revision 1.7.6.1 diff -u -d -r1.7 -r1.7.6.1 --- thread.h 25 Aug 2003 21:00:02 -0000 1.7 +++ thread.h 30 Sep 2003 11:23:04 -0000 1.7.6.1 @@ -4,6 +4,7 @@ #include <sys/types.h> #include <unistd.h> +#include <stddef.h> #include "runtime.h" #include "sbcl.h" #include "os.h" @@ -92,6 +93,18 @@ { return th->interrupt_contexts [fixnum_value(SymbolValue(FREE_INTERRUPT_CONTEXT_INDEX,th)-1)]; +} + +inline static struct thread *arch_os_get_current_thread() { +#ifdef LISP_FEATURE_SB_THREAD + register struct thread *me=0; + if(all_threads) + __asm__ __volatile__ ("movl %%fs:%c1,%0" : "=r" (me) + : "i" (offsetof (struct thread,this))); + return me; +#else + return all_threads; +#endif } Index: x86-linux-os.c =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/x86-linux-os.c,v retrieving revision 1.16 retrieving revision 1.16.6.1 diff -u -d -r1.16 -r1.16.6.1 --- x86-linux-os.c 25 Aug 2003 21:00:02 -0000 1.16 +++ x86-linux-os.c 30 Sep 2003 11:23:04 -0000 1.16.6.1 @@ -112,21 +112,6 @@ return 1; } -/* if you can't do something like this (maybe because you're using a - * register for thread base that is only available in Lisp code) - * you'll just have to find_thread_by_pid(getpid()) - */ -struct thread *arch_os_get_current_thread() { -#ifdef LISP_FEATURE_SB_THREAD - register struct thread *me=0; - if(all_threads) - __asm__ __volatile__ ("movl %%fs:%c1,%0" : "=r" (me) - : "i" (offsetof (struct thread,this))); - return me; -#else - return all_threads; -#endif -} struct thread *debug_get_fs() { register u32 fs; __asm__ __volatile__ ("movl %%fs,%0" : "=r" (fs) : ); Index: x86-linux-os.h =================================================================== RCS file: /cvsroot/sbcl/sbcl/src/runtime/x86-linux-os.h,v retrieving revision 1.6 retrieving revision 1.6.16.1 diff -u -d -r1.6 -r1.6.16.1 --- x86-linux-os.h 5 Apr 2003 13:04:15 -0000 1.6 +++ x86-linux-os.h 30 Sep 2003 11:23:04 -0000 1.6.16.1 @@ -8,6 +8,10 @@ return (os_context_t *) *void_context; } +/* if you can't do something like this (maybe because you're using a + * register for thread base that is only available in Lisp code) + * you'll just have to find_thread_by_pid(getpid()) + */ unsigned long os_context_fp_control(os_context_t *context); void os_restore_fp_control(os_context_t *context); |