Previously (fluid-ref (make-thread-local-fluid #t)) would return #f via
scm_fluid_ref because the internal scm_hashq_ref would return #f when
the fluid had not been set, and that was interpreted as an actual value
for the fluid.
Instead, just pass the fluid default as the default for the hash table
lookups so that we don't need a second step to determine if the fluid
was set.
Thanks to Andrew Gierth for tracking down the problem.
* libguile/fluids.h (struct scm_dynamic_state): Add thread_local_values
table. Thread locals are flushed to a separate thread-local table.
The references are strong references since the table never escapes the
thread.
(scm_make_thread_local_fluid, scm_fluid_thread_local_p): New
functions.
* libguile/fluids.c (FLUID_F_THREAD_LOCAL):
(SCM_I_FLUID_THREAD_LOCAL_P): New macros.
(restore_dynamic_state): Add comment about precondition.
(save_dynamic_state): Flush thread locals.
(scm_i_fluid_print): Print thread locals nicely.
(new_fluid): Add flags arg.
(scm_make_fluid, scm_make_fluid_with_default, scm_make_unbound_fluid):
Adapt.
(scm_make_thread_local_fluid, scm_fluid_thread_local_p): New
functions.
(fluid_set_x): Special flushing logic for thread-locals.
(fluid_ref): Special cache miss logic for thread locals.
* libguile/stacks.c (scm_init_stacks):
* libguile/throw.c (scm_init_throw): %stacks and %exception-handler are
thread-locals.
* libguile/threads.c (guilify_self_2): Init thread locals table.
* test-suite/tests/fluids.test ("dynamic states"): Add test.
* doc/ref/api-control.texi (Fluids and Dynamic States): Add link to
Thread-Local Variables.
* doc/ref/api-scheduling.texi (Thread Local Variables): Update with real
thread-locals.
* NEWS: Update.
Based on a patch by David Kastrup <dak@gnu.org>.
Fixes <http://bugs.gnu.org/13843>.
* libguile/fluids.c (scm_i_make_with_fluids): Reverse direction of inner
loop that checks for duplicates, to properly handle more than two
bindings to the same fluid.
Based on a patch by David Kastrup <dak@gnu.org>.
Fixes <http://bugs.gnu.org/13838>.
* libguile/fluids.c (scm_i_make_with_fluids): Remove the duplicate
binding instead of the last binding.
* test-suite/tests/fluids.test: Add test, and fix existing duplicate
tests.
* THANKS: Thanks David Kastrup.
* libguile/fluids.c (scm_make_undefined_fluid, scm_fluid_unset_x)
(scm_fluid_bound_p): New functions.
(fluid_ref): New function; like scm_fluid_ref, but will not throw an
error for unbound fluids.
(scm_fluid_ref, swap_fluid): Use `fluid_ref'.
* libguile/fluids.h (scm_make_undefined_fluid, scm_fluid_unset_x)
(scm_fluid_bound_p): New prototypes.
* libguile/vm-i-system.c (fluid_ref): If fluid is unbound, jump to
`vm_error_unbound_fluid'.
* libguile/vm-engine.c (VM_NAME)[vm_error_unbound_fluid]: New error
message.
* test-suite/tests/fluids.test ("unbound fluids")["fluid-ref of unbound
fluid", "fluid-bound? of bound fluid", "fluid-bound? of unbound
fluid", "unbound fluids can be set", "bound fluids can be unset"]: New
tests.
* module/ice-9/boot-9.scm:
* module/ice-9/deprecated.scm (@bind): Deprecate @bind, which was a
thread-unsafe dynamic scoping mechanism, used in the old elisp
support. Fluids are more correct, and are probably faster, given the
VM support for with-fluids.
* test-suite/tests/dynamic-scope.test: Remove.
* test-suite/tests/fluids.test: Move relevant tests from
dynamic-scope.test here, recast in terms of with-fluids.
* test-suite/tests/fluids.test ("initial fluid values")["initial value
is inherited from parent thread"]: New test.
("fluid values are thread-local"): New test.
* libguile/tags.h (scm_tc7_with_fluids): Allocate a tc7 for
"with-fluids" objects, which will only live on the dynamic stack (wind
list), not in normal scheme-land.
* libguile/fluids.h (SCM_WITH_FLUIDS_P, SCM_WITH_FLUIDS_LEN)
(SCM_WITH_FLUIDS_NTH_FLUID, SCM_WITH_FLUIDS_NTH_VAL)
(SCM_WITH_FLUIDS_SET_NTH_VAL): Add some accessors.
* libguile/fluids.c (scm_i_make_with_fluids, scm_i_swap_with_fluids):
New internal functions.
(scm_c_with_fluids, scm_c_with_fluid): Push with-fluids objects on the
dynwind list, not winders.
* libguile/dynwind.c (scm_i_dowinds): Add cases for winding and
unwinding with-fluids objects.
* libguile/memoize.h (scm_sym_with_fluids, SCM_M_BEGIN): New public
data.
* libguile/memoize.c (scm_m_with_fluids): Define with-fluids as a
primitive syntax.
(unmemoize): Add with-fluids case.
* libguile/eval.c (eval):
* module/ice-9/eval.scm (primitive-eval): Add with-fluids cases.
* test-suite/tests/fluids.test
("fluids not modified if nonfluid passed to with-fluids"): Enable a
now-passing test.