diff options
author | Andy Wingo <wingo@pobox.com> | 2016-11-27 21:33:30 +0100 |
---|---|---|
committer | Andy Wingo <wingo@pobox.com> | 2016-12-05 21:46:37 +0100 |
commit | aa84489d18320df086e08554554d6f3b92c45893 (patch) | |
tree | 94fb265632d6dbd35f31b8dd7f34d2f0a418e6b7 /libguile/threads.c | |
parent | a9dc553893dcd26f047afecc8dc84d30c9bdcde6 (diff) | |
download | guile-aa84489d18320df086e08554554d6f3b92c45893.tar.gz |
Reimplement dynamic states
There are two goals: one, to use less memory per dynamic state in order
to allow millions of dynamic states to be allocated in light-weight
threading scenarios. The second goal is to prevent dynamic states from
being actively mutated in two threads at once. This second goal does
mean that dynamic states object that escape into scheme are now copies
that won't receive further updates; an incompatible change, but one
which we hope doesn't affect anyone.
* libguile/cache-internal.h: New file.
* libguile/fluids.c (is_dynamic_state, get_dynamic_state)
(save_dynamic_state, restore_dynamic_state, add_entry)
(copy_value_table): New functions.
(scm_i_fluid_print, scm_i_dynamic_state_print): Move up.
(new_fluid): No need for a number.
(scm_fluid_p: scm_is_fluid): Inline IS_FLUID uses.
(fluid_set_x, fluid_ref): Adapt to dynamic state changes.
(scm_fluid_set_x, scm_fluid_unset_x): Call fluid_set_x.
(scm_swap_fluid): Rewrite in terms of fluid_ref and fluid_set.
(swap_fluid): Use internal fluid_set_x.
(scm_i_make_initial_dynamic_state): Adapt to dynamic state
representation change.
(scm_dynamic_state_p, scm_is_dynamic_state): Use new accessors.
(scm_current_dynamic_state): Use make_dynamic_state.
(scm_dynwind_current_dynamic_state): Use new accessor.
* libguile/fluids.h: Remove internal definitions. Add new struct
definition.
* libguile/threads.h (scm_i_thread): Use scm_t_dynamic_state for dynamic
state.
* libguile/threads.c (guilify_self_1, guilify_self_2):
(scm_i_init_thread_for_guile, scm_init_guile):
(scm_call_with_new_thread):
(scm_init_threads, scm_init_threads_default_dynamic_state): Adapt to
scm_i_thread change.
(scm_i_with_guile, with_guile): Remove "and parent" suffix.
(scm_i_reset_fluid): Remove unneeded function.
* doc/ref/api-scheduling.texi (Fluids and Dynamic States): Remove
scm_make_dynamic_state docs. Update current-dynamic-state docs.
* libguile/vm-engine.c (vm_engine): Update fluid-ref and fluid-set!
inlined fast paths for dynamic state changes.
* libguile/vm.c (vm_error_unbound_fluid): Remove now-unused function.
* NEWS: Update.
* module/ice-9/deprecated.scm (make-dynamic-state): New definition.
* libguile/deprecated.h:
* libguile/deprecated.c (scm_make_dynamic_state): Move here.
* libguile/__scm.h (scm_t_dynamic_state): New typedef.
* libguile/dynstack.h:
* libguile/dynstack.c (scm_dynstack_push_fluid):
(scm_dynstack_unwind_fluid): Take raw dynstate in these internal
functions.
* libguile/throw.c (catch): Adapt to dynstack changes.
Diffstat (limited to 'libguile/threads.c')
-rw-r--r-- | libguile/threads.c | 69 |
1 files changed, 23 insertions, 46 deletions
diff --git a/libguile/threads.c b/libguile/threads.c index 28f6cf4ea..91b18b43a 100644 --- a/libguile/threads.c +++ b/libguile/threads.c @@ -372,25 +372,7 @@ static scm_i_pthread_mutex_t thread_admin_mutex = SCM_I_PTHREAD_MUTEX_INITIALIZE static scm_i_thread *all_threads = NULL; static int thread_count; -static SCM scm_i_default_dynamic_state; - -/* Run when a fluid is collected. */ -void -scm_i_reset_fluid (size_t n) -{ - scm_i_thread *t; - - scm_i_pthread_mutex_lock (&thread_admin_mutex); - for (t = all_threads; t; t = t->next_thread) - if (SCM_I_DYNAMIC_STATE_P (t->dynamic_state)) - { - SCM v = SCM_I_DYNAMIC_STATE_FLUIDS (t->dynamic_state); - - if (n < SCM_SIMPLE_VECTOR_LENGTH (v)) - SCM_SIMPLE_VECTOR_SET (v, n, SCM_UNDEFINED); - } - scm_i_pthread_mutex_unlock (&thread_admin_mutex); -} +static SCM default_dynamic_state; /* Perform first stage of thread initialisation, in non-guile mode. */ @@ -409,7 +391,7 @@ guilify_self_1 (struct GC_stack_base *base) t.result = SCM_BOOL_F; t.freelists = NULL; t.pointerless_freelists = NULL; - t.dynamic_state = SCM_BOOL_F; + t.dynamic_state = NULL; t.dynstack.base = NULL; t.dynstack.top = NULL; t.dynstack.limit = NULL; @@ -463,7 +445,7 @@ guilify_self_1 (struct GC_stack_base *base) /* Perform second stage of thread initialisation, in guile mode. */ static void -guilify_self_2 (SCM parent) +guilify_self_2 (SCM dynamic_state) { scm_i_thread *t = SCM_I_CURRENT_THREAD; @@ -480,10 +462,8 @@ guilify_self_2 (SCM parent) t->pointerless_freelists = scm_gc_malloc (size, "atomic freelists"); } - if (scm_is_true (parent)) - t->dynamic_state = scm_make_dynamic_state (parent); - else - t->dynamic_state = scm_i_make_initial_dynamic_state (); + t->dynamic_state = scm_gc_typed_calloc (scm_t_dynamic_state); + scm_set_current_dynamic_state (dynamic_state); t->dynstack.base = scm_gc_malloc (16 * sizeof (scm_t_bits), "dynstack"); t->dynstack.limit = t->dynstack.base + 16; @@ -557,8 +537,7 @@ init_thread_key (void) BASE is the stack base to use with GC. - PARENT is the dynamic state to use as the parent, ot SCM_BOOL_F in - which case the default dynamic state is used. + DYNAMIC_STATE is the set of fluid values to start with. Returns zero when the thread was known to guile already; otherwise return 1. @@ -569,7 +548,8 @@ init_thread_key (void) be sure. New threads are put into guile mode implicitly. */ static int -scm_i_init_thread_for_guile (struct GC_stack_base *base, SCM parent) +scm_i_init_thread_for_guile (struct GC_stack_base *base, + SCM dynamic_state) { scm_i_pthread_once (&init_thread_key_once, init_thread_key); @@ -612,7 +592,7 @@ scm_i_init_thread_for_guile (struct GC_stack_base *base, SCM parent) #endif guilify_self_1 (base); - guilify_self_2 (parent); + guilify_self_2 (dynamic_state); } return 1; } @@ -624,8 +604,7 @@ scm_init_guile () struct GC_stack_base stack_base; if (GC_get_stack_base (&stack_base) == GC_SUCCESS) - scm_i_init_thread_for_guile (&stack_base, - scm_i_default_dynamic_state); + scm_i_init_thread_for_guile (&stack_base, default_dynamic_state); else { fprintf (stderr, "Failed to get stack base for current thread.\n"); @@ -637,7 +616,7 @@ struct with_guile_args { GC_fn_type func; void *data; - SCM parent; + SCM dynamic_state; }; static void * @@ -649,14 +628,14 @@ with_guile_trampoline (void *data) } static void * -with_guile_and_parent (struct GC_stack_base *base, void *data) +with_guile (struct GC_stack_base *base, void *data) { void *res; int new_thread; scm_i_thread *t; struct with_guile_args *args = data; - new_thread = scm_i_init_thread_for_guile (base, args->parent); + new_thread = scm_i_init_thread_for_guile (base, args->dynamic_state); t = SCM_I_CURRENT_THREAD; if (new_thread) { @@ -698,22 +677,21 @@ with_guile_and_parent (struct GC_stack_base *base, void *data) } static void * -scm_i_with_guile_and_parent (void *(*func)(void *), void *data, SCM parent) +scm_i_with_guile (void *(*func)(void *), void *data, SCM dynamic_state) { struct with_guile_args args; args.func = func; args.data = data; - args.parent = parent; + args.dynamic_state = dynamic_state; - return GC_call_with_stack_base (with_guile_and_parent, &args); + return GC_call_with_stack_base (with_guile, &args); } void * scm_with_guile (void *(*func)(void *), void *data) { - return scm_i_with_guile_and_parent (func, data, - scm_i_default_dynamic_state); + return scm_i_with_guile (func, data, default_dynamic_state); } void * @@ -753,7 +731,7 @@ scm_call_with_new_thread (SCM thunk, SCM handler) } typedef struct { - SCM parent; + SCM dynamic_state; SCM thunk; } launch_data; @@ -769,7 +747,7 @@ launch_thread (void *d) { launch_data *data = (launch_data *)d; scm_i_pthread_detach (scm_i_pthread_self ()); - scm_i_with_guile_and_parent (really_launch, d, data->parent); + scm_i_with_guile (really_launch, d, data->dynamic_state); return NULL; } @@ -786,7 +764,7 @@ SCM_DEFINE (scm_sys_call_with_new_thread, "%call-with-new-thread", 1, 0, 0, GC_collect_a_little (); data = scm_gc_typed_calloc (launch_data); - data->parent = scm_current_dynamic_state (); + data->dynamic_state = scm_current_dynamic_state (); data->thunk = thunk; err = scm_i_pthread_create (&id, NULL, launch_thread, data); if (err) @@ -1792,8 +1770,8 @@ scm_init_threads () sizeof (struct scm_cond)); scm_set_smob_print (scm_tc16_condvar, scm_cond_print); - scm_i_default_dynamic_state = SCM_BOOL_F; - guilify_self_2 (SCM_BOOL_F); + default_dynamic_state = SCM_BOOL_F; + guilify_self_2 (scm_i_make_initial_dynamic_state ()); threads_initialized_p = 1; scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION, @@ -1804,8 +1782,7 @@ scm_init_threads () void scm_init_threads_default_dynamic_state () { - SCM state = scm_make_dynamic_state (scm_current_dynamic_state ()); - scm_i_default_dynamic_state = state; + default_dynamic_state = scm_current_dynamic_state (); } |