From 3b92693146f6449cf8ed4e5d9774bd7ce5586fa5 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Wed, 18 Nov 2009 20:46:49 +0000 Subject: [PATCH] write-barrier handling with multiple threads svn: r16880 --- src/mzscheme/gc2/newgc.c | 7 ++++++- src/mzscheme/src/future.c | 26 ++++++++++++++++++++------ src/mzscheme/src/future.h | 1 + src/mzscheme/src/salloc.c | 8 ++++++++ 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/mzscheme/gc2/newgc.c b/src/mzscheme/gc2/newgc.c index 0b43220677..db73b66e42 100644 --- a/src/mzscheme/gc2/newgc.c +++ b/src/mzscheme/gc2/newgc.c @@ -1698,8 +1698,13 @@ static int designate_modified_gc(NewGC *gc, void *p) page->mprotected = 0; vm_protect_pages(page->addr, (page->size_class > 1) ? round_to_apage_size(page->size) : APAGE_SIZE, 1); page->back_pointers = 1; - return 1; } + /* For a single mutator thread, we shouldn't get here + (and a `return 1' in the braces above would make more + sense). With multiple mutators, though, two threads might + hit the same page at effectively the same time, and only + the first one of them will handle the signal. */ + return 1; } else { if (gc->primoridal_gc) { return designate_modified_gc(gc->primoridal_gc, p); diff --git a/src/mzscheme/src/future.c b/src/mzscheme/src/future.c index 1c26f9e871..20edcc6aa7 100644 --- a/src/mzscheme/src/future.c +++ b/src/mzscheme/src/future.c @@ -50,7 +50,7 @@ void scheme_init_futures(Scheme_Env *env) extern void *on_demand_jit_code; -#define THREAD_POOL_SIZE 3 +#define THREAD_POOL_SIZE 1 #define INITIAL_C_STACK_SIZE 500000 static pthread_t g_pool_threads[THREAD_POOL_SIZE]; static int *g_fuel_pointers[THREAD_POOL_SIZE]; @@ -59,6 +59,7 @@ static int g_num_avail_threads = 0; static unsigned long g_cur_cpu_mask = 1; static void *g_signal_handle = NULL; +static struct NewGC *g_shared_GC; future_t *g_future_queue = NULL; int g_next_futureid = 0; pthread_t g_rt_threadid = 0; @@ -86,7 +87,7 @@ static void register_traversers(void); extern void scheme_on_demand_generate_lambda(Scheme_Native_Closure *nc, int argc, Scheme_Object **argv); static void start_gc_not_ok(); -static void end_gc_not_ok(); +static void end_gc_not_ok(future_t *ft); THREAD_LOCAL_DECL(static future_t *current_ft); @@ -310,6 +311,7 @@ void futures_init(void) for (i = 0; i < THREAD_POOL_SIZE; i++) { gc_counter_ptr = &scheme_did_gc_count; + g_shared_GC = GC; pthread_create(&threadid, &attr, worker_thread_future_loop, &i); sema_wait(&ready_sema); @@ -337,8 +339,14 @@ static void start_gc_not_ok() #endif } -static void end_gc_not_ok() +static void end_gc_not_ok(future_t *ft) { + if (ft) { + scheme_set_runstack_limits(ft->runstack_start, + ft->runstack_size, + ft->runstack - ft->runstack_start, + ft->runstack_size); + } pthread_mutex_lock(&gc_ok_m); --gc_not_ok; pthread_cond_signal(&gc_ok_c); @@ -465,6 +473,7 @@ Scheme_Object *future(int argc, Scheme_Object *argv[]) rs = rs_start XFORM_OK_PLUS init_runstack_size; ft->runstack_start = rs_start; ft->runstack = rs; + ft->runstack_size = init_runstack_size; } //pthread_mutex_unlock(&g_future_queue_mutex); @@ -603,6 +612,8 @@ void *worker_thread_future_loop(void *arg) scheme_init_os_thread(); + GC = g_shared_GC; + //Set processor affinity /*pthread_mutex_lock(&g_future_queue_mutex); if (pthread_setaffinity_np(pthread_self(), sizeof(g_cur_cpu_mask), &g_cur_cpu_mask)) @@ -635,7 +646,7 @@ void *worker_thread_future_loop(void *arg) pthread_mutex_lock(&g_future_queue_mutex); while (!(ft = get_pending_future())) { - end_gc_not_ok(); + end_gc_not_ok(NULL); pthread_cond_wait(&g_future_pending_cv, &g_future_queue_mutex); start_gc_not_ok(); } @@ -679,12 +690,15 @@ void *worker_thread_future_loop(void *arg) ft->work_completed = 1; ft->retval = v; + ft->runstack = NULL; + ft->runstack_start = NULL; + //Update the status ft->status = FINISHED; scheme_signal_received_at(g_signal_handle); pthread_mutex_unlock(&g_future_queue_mutex); - end_gc_not_ok(); + end_gc_not_ok(NULL); goto wait_for_work; @@ -737,7 +751,7 @@ int future_do_runtimecall( //Wait for the signal that the RT call is finished future->can_continue_cv = &worker_can_continue_cv; - end_gc_not_ok(); + end_gc_not_ok(future); pthread_cond_wait(&worker_can_continue_cv, &g_future_queue_mutex); start_gc_not_ok(); diff --git a/src/mzscheme/src/future.h b/src/mzscheme/src/future.h index c1b8451db8..9b10e44059 100644 --- a/src/mzscheme/src/future.h +++ b/src/mzscheme/src/future.h @@ -80,6 +80,7 @@ typedef struct future { int work_completed; pthread_cond_t *can_continue_cv; + long runstack_size; Scheme_Object **runstack; Scheme_Object **runstack_start; Scheme_Object *orig_lambda; diff --git a/src/mzscheme/src/salloc.c b/src/mzscheme/src/salloc.c index 94d4a2e2f3..a492d2f8d7 100644 --- a/src/mzscheme/src/salloc.c +++ b/src/mzscheme/src/salloc.c @@ -65,6 +65,9 @@ THREAD_LOCAL Thread_Local_Variables scheme_thread_locals; extern int scheme_num_copied_stacks; static unsigned long scheme_primordial_os_thread_stack_base; THREAD_LOCAL_DECL(static unsigned long scheme_os_thread_stack_base); +#ifdef USE_THREAD_LOCAL +Thread_Local_Variables *scheme_vars; /* for debugging */ +#endif static Scheme_Report_Out_Of_Memory_Proc more_report_out_of_memory; @@ -164,7 +167,12 @@ int scheme_main_stack_setup(int no_auto_statics, Scheme_Nested_Main _main, void fprintf(stderr, "pthread key create failed"); abort(); } +#endif + scheme_init_os_thread(); + +#ifdef USE_THREAD_LOCAL + scheme_vars = scheme_get_thread_local_variables(); #endif scheme_set_stack_base(PROMPT_STACK(stack_start), no_auto_statics);