From f921cf62cc9ed4fbab776c9d6a0c51aec2a238aa Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Wed, 18 Nov 2009 20:07:58 +0000 Subject: [PATCH] more on thread-local allocation svn: r16879 --- src/mzscheme/gc2/vm_osx.c | 36 ++++++++++------- src/mzscheme/include/schthread.h | 6 ++- src/mzscheme/src/future.c | 66 ++++++++++++++++++++------------ src/mzscheme/src/future.h | 14 ++++--- src/mzscheme/src/jit.c | 5 ++- src/mzscheme/src/salloc.c | 8 ++++ src/mzscheme/src/thread.c | 6 +-- 7 files changed, 90 insertions(+), 51 deletions(-) diff --git a/src/mzscheme/gc2/vm_osx.c b/src/mzscheme/gc2/vm_osx.c index 9d1e9afca0..6d01b12103 100644 --- a/src/mzscheme/gc2/vm_osx.c +++ b/src/mzscheme/gc2/vm_osx.c @@ -279,25 +279,16 @@ void exception_thread(void *shared_thread_state) } } -/* this initializes the subsystem (sets the exception port, starts the - exception handling thread, etc) */ -static void macosx_init_exception_handler() +void GC_attach_current_thread_exceptions_to_handler() { mach_port_t thread_self, exc_port_s; mach_msg_type_name_t type; kern_return_t retval; - /* get ids for ourself */ - if(!task_self) task_self = mach_task_self(); - thread_self = mach_thread_self(); + if (!task_self) return; - /* allocate the port we're going to get exceptions on */ - retval = mach_port_allocate(task_self, MACH_PORT_RIGHT_RECEIVE, &exc_port); - if(retval != KERN_SUCCESS) { - GCPRINT(GCOUTF, "Couldn't allocate exception port: %s\n", - mach_error_string(retval)); - abort(); - } + /* get ids for ourself */ + thread_self = mach_thread_self(); /* extract out the send rights for that port, which the OS needs */ retval = mach_port_extract_right(task_self, exc_port, MACH_MSG_TYPE_MAKE_SEND, @@ -315,6 +306,25 @@ static void macosx_init_exception_handler() GCPRINT(GCOUTF, "Couldn't set exception ports: %s\n", mach_error_string(retval)); abort(); } +} + +/* this initializes the subsystem (sets the exception port, starts the + exception handling thread, etc) */ +static void macosx_init_exception_handler() +{ + kern_return_t retval; + + if(!task_self) task_self = mach_task_self(); + + /* allocate the port we're going to get exceptions on */ + retval = mach_port_allocate(task_self, MACH_PORT_RIGHT_RECEIVE, &exc_port); + if(retval != KERN_SUCCESS) { + GCPRINT(GCOUTF, "Couldn't allocate exception port: %s\n", + mach_error_string(retval)); + abort(); + } + + GC_attach_current_thread_exceptions_to_handler(); #ifdef PPC_HAND_ROLLED_THREAD /* Old hand-rolled thread creation. */ diff --git a/src/mzscheme/include/schthread.h b/src/mzscheme/include/schthread.h index d8c1d0ed43..0ec0171991 100644 --- a/src/mzscheme/include/schthread.h +++ b/src/mzscheme/include/schthread.h @@ -181,7 +181,8 @@ typedef struct Thread_Local_Variables { int num_running_threads_; int swap_no_setjmp_; int thread_swap_count_; - int did_gc_count_; + int scheme_did_gc_count_; + int worker_gc_counter_; struct Scheme_Object **scheme_current_runstack_start_; struct Scheme_Object **scheme_current_runstack_; MZ_MARK_STACK_TYPE scheme_current_cont_mark_stack_; @@ -344,7 +345,8 @@ XFORM_GC_VARIABLE_STACK_THROUGH_THREAD_LOCAL; #define num_running_threads XOA (scheme_get_thread_local_variables()->num_running_threads_) #define swap_no_setjmp XOA (scheme_get_thread_local_variables()->swap_no_setjmp_) #define thread_swap_count XOA (scheme_get_thread_local_variables()->thread_swap_count_) -#define did_gc_count XOA (scheme_get_thread_local_variables()->did_gc_count_) +#define scheme_did_gc_count XOA (scheme_get_thread_local_variables()->scheme_did_gc_count_) +#define worker_gc_counter XOA (scheme_get_thread_local_variables()->worker_gc_counter_) #define scheme_current_runstack_start XOA (scheme_get_thread_local_variables()->scheme_current_runstack_start_) #define scheme_current_runstack XOA (scheme_get_thread_local_variables()->scheme_current_runstack_) #define scheme_current_cont_mark_stack XOA (scheme_get_thread_local_variables()->scheme_current_cont_mark_stack_) diff --git a/src/mzscheme/src/future.c b/src/mzscheme/src/future.c index 050b50a980..1c26f9e871 100644 --- a/src/mzscheme/src/future.c +++ b/src/mzscheme/src/future.c @@ -75,10 +75,12 @@ static int gc_not_ok; THREAD_LOCAL_DECL(extern unsigned long GC_gen0_alloc_page_ptr); #endif -future_t **g_current_ft; -Scheme_Object ***g_scheme_current_runstack; -Scheme_Object ***g_scheme_current_runstack_start; -void **g_jit_future_storage; +static future_t **g_current_ft; +static Scheme_Object ***g_scheme_current_runstack; +static Scheme_Object ***g_scheme_current_runstack_start; +static void **g_jit_future_storage; +static int *gc_counter_ptr; +THREAD_LOCAL_DECL(static int worker_gc_counter); static void register_traversers(void); extern void scheme_on_demand_generate_lambda(Scheme_Native_Closure *nc, int argc, Scheme_Object **argv); @@ -307,6 +309,7 @@ void futures_init(void) pthread_attr_setstacksize(&attr, INITIAL_C_STACK_SIZE); for (i = 0; i < THREAD_POOL_SIZE; i++) { + gc_counter_ptr = &scheme_did_gc_count; pthread_create(&threadid, &attr, worker_thread_future_loop, &i); sema_wait(&ready_sema); @@ -326,6 +329,12 @@ static void start_gc_not_ok() pthread_mutex_lock(&gc_ok_m); gc_not_ok++; pthread_mutex_unlock(&gc_ok_m); +#ifdef MZ_PRECISE_GC + if (worker_gc_counter != *gc_counter_ptr) { + GC_gen0_alloc_page_ptr = 0; /* forces future to ask for memory */ + worker_gc_counter = *gc_counter_ptr; + } +#endif } static void end_gc_not_ok() @@ -581,7 +590,6 @@ Scheme_Object *touch(int argc, Scheme_Object *argv[]) return retval; } - //Entry point for a worker thread allocated for //executing futures. This function will never terminate //(until the process dies). @@ -616,10 +624,6 @@ void *worker_thread_future_loop(void *arg) g_fuel_pointers[id] = &scheme_fuel_counter; g_stack_boundary_pointers[id] = &scheme_jit_stack_boundary; - #ifdef MZ_PRECISE_GC - GC_gen0_alloc_page_ptr = 0; /* disables inline allocation */ - #endif - g_current_ft = ¤t_ft; g_scheme_current_runstack = &scheme_current_runstack; g_scheme_current_runstack_start = &scheme_current_runstack_start; @@ -744,6 +748,7 @@ int future_do_runtimecall( future->rt_prim = NULL; retval = future->rt_prim_retval; + future->rt_prim_retval = NULL; pthread_mutex_unlock(&g_future_queue_mutex); return 1; } @@ -777,27 +782,34 @@ int rtcall_void_void(void (*f)()) } -int rtcall_void_pvoid(void (*f)(), void **retval) +int rtcall_alloc_void_pvoid(void (*f)(), void **retval) { START_XFORM_SKIP; future_t *future; prim_data_t data; - memset(&data, 0, sizeof(prim_data_t)); - if (!IS_WORKER_THREAD) - { - return 0; - } - data.void_pvoid = f; - data.sigtype = SIG_VOID_PVOID; + while (1) { + memset(&data, 0, sizeof(prim_data_t)); + if (!IS_WORKER_THREAD) + { + return 0; + } - future = get_my_future(); - future->rt_prim = (void*)f; - future->prim_data = data; + data.alloc_void_pvoid = f; + data.sigtype = SIG_ALLOC_VOID_PVOID; - future_do_runtimecall((void*)f, NULL); + future = get_my_future(); + future->rt_prim = (void*)f; + future->prim_data = data; - *retval = future->prim_data.retval; + future_do_runtimecall((void*)f, NULL); + + *retval = future->alloc_retval; + future->alloc_retval = NULL; + + if (*gc_counter_ptr == future->alloc_retval_counter) + break; + } return 1; END_XFORM_SKIP; @@ -840,6 +852,7 @@ int rtcall_obj_int_pobj_obj( future_do_runtimecall((void*)f, NULL); *retval = future->prim_data.retval; + future->prim_data.retval = NULL; return 1; END_XFORM_SKIP; @@ -880,6 +893,7 @@ int rtcall_int_pobj_obj( future_do_runtimecall((void*)f, NULL); *retval = future->prim_data.retval; + future->prim_data.retval = NULL; return 1; END_XFORM_SKIP; @@ -962,6 +976,7 @@ int rtcall_int_pobj_obj_obj( future_do_runtimecall((void*)f, NULL); *retval = future->prim_data.retval; + future->prim_data.retval = NULL; return 1; END_XFORM_SKIP; @@ -995,11 +1010,12 @@ void *invoke_rtcall(future_t *future) pret = &dummy_ret; break; } - case SIG_VOID_PVOID: + case SIG_ALLOC_VOID_PVOID: { - prim_void_pvoid_t func = pdata->void_pvoid; + prim_alloc_void_pvoid_t func = pdata->alloc_void_pvoid; ret = func(); - pdata->retval = ret; + future->alloc_retval = ret; + future->alloc_retval_counter = scheme_did_gc_count; break; } case SIG_OBJ_INT_POBJ_OBJ: diff --git a/src/mzscheme/src/future.h b/src/mzscheme/src/future.h index 1438ccc488..c1b8451db8 100644 --- a/src/mzscheme/src/future.h +++ b/src/mzscheme/src/future.h @@ -33,7 +33,7 @@ extern int future_do_runtimecall(void *func, void *retval); extern void futures_init(void); typedef void (*prim_void_void_t)(void); -typedef void *(*prim_void_pvoid_t)(void); +typedef void *(*prim_alloc_void_pvoid_t)(void); typedef Scheme_Object* (*prim_obj_int_pobj_obj_t)(Scheme_Object*, int, Scheme_Object**); typedef Scheme_Object* (*prim_int_pobj_obj_t)(int, Scheme_Object**); typedef Scheme_Object* (*prim_int_pobj_obj_obj_t)(int, Scheme_Object**, Scheme_Object*); @@ -43,7 +43,7 @@ typedef struct { unsigned int sigtype; prim_void_void_t void_void; - prim_void_pvoid_t void_pvoid; + prim_alloc_void_pvoid_t alloc_void_pvoid; prim_obj_int_pobj_obj_t obj_int_pobj_obj; prim_int_pobj_obj_t int_pobj_obj; prim_int_pobj_obj_obj_t int_pobj_obj_obj; @@ -90,6 +90,8 @@ typedef struct future { void *rt_prim_retval; prim_data_t prim_data; + void *alloc_retval; + int alloc_retval_counter; Scheme_Object *retval; struct future *prev; @@ -152,7 +154,7 @@ extern void print_ms_and_us(void); //Signature flags for primitive invocations //Here the convention is SIG_[arg1type]_[arg2type]..._[return type] #define SIG_VOID_VOID 1 //void -> void -#define SIG_VOID_PVOID 2 //void -> void* +#define SIG_ALLOC_VOID_PVOID 2 //void -> void* #define SIG_OBJ_INT_POBJ_OBJ 3 //Scheme_Object* -> int -> Scheme_Object** -> Scheme_Object* #define SIG_INT_OBJARR_OBJ 4 //int -> Scheme_Object*[] -> Scheme_Object #define SIG_INT_POBJ_OBJ_OBJ 17 //int -> Scheme_Object** -> Scheme_Object* -> Scheme_Object* @@ -169,7 +171,7 @@ extern void print_ms_and_us(void); } extern int rtcall_void_void(void (*f)()); -extern int rtcall_void_pvoid(void (*f)(), void **retval); +extern int rtcall_alloc_void_pvoid(void (*f)(), void **retval); extern int rtcall_obj_int_pobj_obj( Scheme_Object* (*f)(Scheme_Object*, int, Scheme_Object**), Scheme_Object *a, @@ -195,7 +197,7 @@ extern int rtcall_int_pobj_obj( #define LOG_THISCALL LOG(__FUNCTION__) #define LOG_RTCALL_VOID_VOID(f) LOG("(function=%p)", f) -#define LOG_RTCALL_VOID_PVOID(f) LOG("(function=%p)", f) +#define LOG_RTCALL_ALLOC_VOID_PVOID(f) LOG("(function=%p)", f) #define LOG_RTCALL_OBJ_INT_POBJ_OBJ(f,a,b,c) LOG("(function = %p, a=%p, b=%d, c=%p)", f, a, b, c) #define LOG_RTCALL_OBJ_INT_POBJ_VOID(a,b,c) LOG("(%p, %d, %p)", a, b,c) #define LOG_RTCALL_INT_OBJARR_OBJ(a,b) LOG("(%d, %p)", a, b) @@ -218,7 +220,7 @@ extern int rtcall_int_pobj_obj( #define LOG_THISCALL #define LOG_RTCALL_VOID_VOID(f) -#define LOG_RTCALL_VOID_PVOID(f) +#define LOG_RTCALL_ALLOC_VOID_PVOID(f) #define LOG_RTCALL_OBJ_INT_POBJ_OBJ(f,a,b,c) #define LOG_RTCALL_OBJ_INT_POBJ_VOID(a,b,c) #define LOG_RTCALL_INT_OBJARR_OBJ(a,b) diff --git a/src/mzscheme/src/jit.c b/src/mzscheme/src/jit.c index fc850b2d1f..d5c8b8db45 100644 --- a/src/mzscheme/src/jit.c +++ b/src/mzscheme/src/jit.c @@ -2256,8 +2256,8 @@ static void *ts_prepare_retry_alloc(void *p, void *p2) LOG_PRIM_START(&prepare_retry_alloc); jit_future_storage[0] = p; jit_future_storage[1] = p2; - if (rtcall_void_pvoid(GC_make_jit_nursery_page, - &ret)) { + if (rtcall_alloc_void_pvoid(GC_make_jit_nursery_page, + &ret)) { GC_gen0_alloc_page_ptr = ret; retry_alloc_r1 = jit_future_storage[1]; p = jit_future_storage[0]; @@ -2284,6 +2284,7 @@ static void *ts_prepare_retry_alloc(void *p, void *p2) # define ts_scheme_apply_from_native _scheme_apply_from_native # define ts_scheme_tail_apply_from_native _scheme_tail_apply_from_native # define ts_on_demand on_demand +# define ts_prepare_retry_alloc prepare_retry_alloc #endif static int generate_direct_prim_tail_call(mz_jit_state *jitter, int num_rands) diff --git a/src/mzscheme/src/salloc.c b/src/mzscheme/src/salloc.c index cb6444c097..94d4a2e2f3 100644 --- a/src/mzscheme/src/salloc.c +++ b/src/mzscheme/src/salloc.c @@ -220,6 +220,9 @@ void scheme_set_report_out_of_memory(Scheme_Report_Out_Of_Memory_Proc p) #ifdef OS_X #include +# ifdef MZ_PRECISE_GC +extern void GC_attach_current_thread_exceptions_to_handler(); +# endif #endif #ifdef MZ_XFORM @@ -241,6 +244,11 @@ void scheme_init_os_thread() } # endif #endif +#ifdef OS_X +# ifdef MZ_PRECISE_GC + GC_attach_current_thread_exceptions_to_handler(); +# endif +#endif } #ifdef MZ_XFORM END_XFORM_SKIP; diff --git a/src/mzscheme/src/thread.c b/src/mzscheme/src/thread.c index 1fa87713cd..7793ac0716 100644 --- a/src/mzscheme/src/thread.c +++ b/src/mzscheme/src/thread.c @@ -160,7 +160,7 @@ volatile int *scheme_fuel_counter_ptr; THREAD_LOCAL_DECL(static int swap_no_setjmp = 0); THREAD_LOCAL_DECL(static int thread_swap_count); -THREAD_LOCAL_DECL(static int did_gc_count); +THREAD_LOCAL_DECL(int scheme_did_gc_count); static int init_load_on_demand = 1; @@ -7390,7 +7390,7 @@ static void get_ready_for_GC() scheme_current_thread->gmp_tls_data = data; } - did_gc_count++; + scheme_did_gc_count++; } extern int GC_words_allocd; @@ -7575,7 +7575,7 @@ static Scheme_Object *current_stats(int argc, Scheme_Object *argv[]) case 5: SCHEME_VEC_ELS(v)[4] = scheme_make_integer(thread_swap_count); case 4: - SCHEME_VEC_ELS(v)[3] = scheme_make_integer(did_gc_count); + SCHEME_VEC_ELS(v)[3] = scheme_make_integer(scheme_did_gc_count); case 3: SCHEME_VEC_ELS(v)[2] = scheme_make_integer(gcend); case 2: