aboutsummaryrefslogtreecommitdiffstats
path: root/test/src/emacs-module-resources
diff options
context:
space:
mode:
authorPhilipp Stephani2020-11-27 19:08:55 +0100
committerPhilipp Stephani2020-11-27 20:15:33 +0100
commit23974cfa48b9245658667eff81d132b3aecd2618 (patch)
tree654441136c36d579d366f64f32907bb72e2b3b20 /test/src/emacs-module-resources
parente7423689208026658fbe8c75523eac6dbe022c39 (diff)
downloademacs-23974cfa48b9245658667eff81d132b3aecd2618.tar.gz
emacs-23974cfa48b9245658667eff81d132b3aecd2618.zip
Fix incorrect handling of module runtime and environment pointers.
We used to store module runtime and environment pointers in the static lists Vmodule_runtimes and Vmodule_environments. However, this is incorrect because these objects have to be kept per-thread. With this naive approach, interleaving module function calls in separate threads leads to environments being removed in the wrong order, which in turn can cause local module values to be incorrectly garbage-collected. The fix isn't completely trivial: specbinding the lists wouldn't work either, because then the garbage collector wouldn't find the environments in other threads than the current ones, again leading to objects being garbage-collected incorrectly. While introducing custom pseudovector types would fix this, it's simpler to put the runtime and environment pointers into the specbinding list as new specbinding kinds. This works since we need to unwind them anyway, and we only ever treat the lists as a stack. The thread switching machinery ensures that the specbinding lists are thread-local, and that all elements of the specbinding lists in all threads are marked during garbage collection. Module assertions now have to walk the specbinding list for the current thread, which is more correct since they now only find environments for the current thread. As a result, we can now remove the faulty Vmodule_runtimes and Vmodule_environments variables entirely. Also add a unit test that exemplifies the problem. It interleaves two module calls in two threads so that the first call ends while the second one is still active. Without this change, this test triggers an assertion failure. * src/lisp.h (enum specbind_tag): Add new tags for module runtimes and environments. * src/eval.c (record_unwind_protect_module): New function to record a module object in the specpdl list. (do_one_unbind): Unwind module objects. (backtrace_eval_unrewind, default_toplevel_binding, lexbound_p) (Fbacktrace__locals): Deal with new specbinding types. (mark_specpdl): Mark module environments as needed. * src/alloc.c (garbage_collect): Remove call to 'mark-modules'. Garbage collection of module values is now handled as part of marking the specpdl of each thread. * src/emacs-module.c (Fmodule_load, funcall_module): Use specpdl to record module runtimes and environments. (module_assert_runtime, module_assert_env, value_to_lisp): Walk through specpdl list instead of list variables. (mark_module_environment): Rename from 'mark_modules'. Don't attempt to walk though current thread's environments only, since that would miss other threads. (initialize_environment, finalize_environment): Don't change Vmodule_environments variable; environments are now in the specpdl list. (finalize_environment_unwind, finalize_runtime_unwind): Make 'extern' since do_one_unbind now calls them. (finalize_runtime_unwind): Don't change Vmodule_runtimes variable; runtimes are now in the specpdl list. (syms_of_module): Remove Vmodule_runtimes and Vmodule_environments. * test/data/emacs-module/mod-test.c (Fmod_test_funcall): New test function. (emacs_module_init): Bind it. * test/src/emacs-module-tests.el (emacs-module-tests--variable): New helper type to guard access to state in a thread-safe way. (emacs-module-tests--wait-for-variable) (emacs-module-tests--change-variable): New helper functions. (emacs-module-tests/interleaved-threads): New unit test.
Diffstat (limited to 'test/src/emacs-module-resources')
-rw-r--r--test/src/emacs-module-resources/mod-test.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/test/src/emacs-module-resources/mod-test.c b/test/src/emacs-module-resources/mod-test.c
index 258a679b207..419621256ae 100644
--- a/test/src/emacs-module-resources/mod-test.c
+++ b/test/src/emacs-module-resources/mod-test.c
@@ -691,6 +691,14 @@ Fmod_test_identity (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
691 return args[0]; 691 return args[0];
692} 692}
693 693
694static emacs_value
695Fmod_test_funcall (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
696 void *data)
697{
698 assert (0 < nargs);
699 return env->funcall (env, args[0], nargs - 1, args + 1);
700}
701
694/* Lisp utilities for easier readability (simple wrappers). */ 702/* Lisp utilities for easier readability (simple wrappers). */
695 703
696/* Provide FEATURE to Emacs. */ 704/* Provide FEATURE to Emacs. */
@@ -780,6 +788,8 @@ emacs_module_init (struct emacs_runtime *ert)
780 DEFUN ("mod-test-function-finalizer-calls", 788 DEFUN ("mod-test-function-finalizer-calls",
781 Fmod_test_function_finalizer_calls, 0, 0, NULL, NULL); 789 Fmod_test_function_finalizer_calls, 0, 0, NULL, NULL);
782 DEFUN ("mod-test-async-pipe", Fmod_test_async_pipe, 1, 1, NULL, NULL); 790 DEFUN ("mod-test-async-pipe", Fmod_test_async_pipe, 1, 1, NULL, NULL);
791 DEFUN ("mod-test-funcall", Fmod_test_funcall, 1, emacs_variadic_function,
792 NULL, NULL);
783 793
784#undef DEFUN 794#undef DEFUN
785 795