Package: emacs;
Reported by: Samir Jindel <sjindel <at> google.com>
Date: Tue, 6 Feb 2018 21:26:01 UTC
Severity: wishlist
Done: Philipp Stephani <p.stephani2 <at> gmail.com>
Bug is archived. No further changes may be made.
View this message in rfc822 format
From: help-debbugs <at> gnu.org (GNU bug Tracking System) To: Philipp Stephani <p.stephani2 <at> gmail.com> Cc: tracker <at> debbugs.gnu.org Subject: bug#30373: closed (Support finalizers for functions created in dynamic modules) Date: Fri, 03 Jan 2020 18:36:02 +0000
[Message part 1 (text/plain, inline)]
Your message dated Fri, 3 Jan 2020 19:34:51 +0100 with message-id <CAArVCkQKn9W+T5G8-jHSPPY9tudgRzRNS-aKG2C4bCO5e551SQ <at> mail.gmail.com> and subject line Re: bug#30373: [PATCH] Implement finalizers for module functions (Bug#30373) has caused the debbugs.gnu.org bug report #30373, regarding Support finalizers for functions created in dynamic modules to be marked as done. (If you believe you have received this mail in error, please contact help-debbugs <at> gnu.org.) -- 30373: http://debbugs.gnu.org/cgi/bugreport.cgi?bug=30373 GNU Bug Tracking System Contact help-debbugs <at> gnu.org with problems
[Message part 2 (message/rfc822, inline)]
From: Samir Jindel <sjindel <at> google.com> To: bug-gnu-emacs <at> gnu.org Subject: Support finalizers for functions created in dynamic modules Date: Tue, 6 Feb 2018 22:17:11 +0100[Message part 3 (text/plain, inline)]Hi, I'm very excited by the possibilities opened through the new dynamic module interface, "emacs-module.h". However, I have a concern about the API for creating Lisp functions bound to native functions: ```c emacs_value (*make_function) (emacs_env *env, ptrdiff_t min_arity, ptrdiff_t max_arity, emacs_value (*function) (emacs_env *env, ptrdiff_t nargs, emacs_value args[], void *) EMACS_NOEXCEPT, const char *documentation, void *data); ``` I presume the "data" pointer here is provided to enable native functions to work like closures, carrying additional, possibly dynamically allocated data. However, this functionality is limited by the absence of a finalization function pointer, like the "user_ptr" values have: ```c emacs_value (*make_user_ptr) (emacs_env *env, void (*fin) (void *) EMACS_NOEXCEPT, void *ptr); ``` Without the ability to provide a finalizer, a module can only safely make the "data" pointer to "make_function" point to static memory. Thanks, Samir Jindel[Message part 4 (text/html, inline)]
[Message part 5 (message/rfc822, inline)]
From: Philipp Stephani <p.stephani2 <at> gmail.com> To: 30373-done <at> debbugs.gnu.org, Samir Jindel <sjindel <at> google.com> Cc: Philipp Stephani <phst <at> google.com> Subject: Re: bug#30373: [PATCH] Implement finalizers for module functions (Bug#30373) Date: Fri, 3 Jan 2020 19:34:51 +0100Since there were no objections, I've installed this patch (plus some documentation) as commit 48ffef5ef4 into master. Am Do., 26. Dez. 2019 um 01:05 Uhr schrieb Philipp Stephani <p.stephani2 <at> gmail.com>: > > * src/module-env-28.h: Add new module environment functions to > module environment for Emacs 28. > > * src/emacs-module.c (CHECK_MODULE_FUNCTION): New function. > (struct Lisp_Module_Function): Add finalizer data member. > (module_make_function): Initialize finalizer. > (module_get_function_finalizer) > (module_set_function_finalizer): New module environment functions. > (module_finalize_function): New function. > (initialize_environment): Initialize new environment functions. > > * src/alloc.c (cleanup_vector): Call potential module function > finalizer during garbage collection. > > * test/data/emacs-module/mod-test.c (signal_error): New helper > function. > (memory_full): Use it. > (finalizer): New example function finalizer. > (Fmod_test_make_function_with_finalizer) > (Fmod_test_function_finalizer_calls): New test module functions. > (emacs_module_init): Define them. > > * test/src/emacs-module-tests.el (module/function-finalizer): New unit > test. > --- > src/alloc.c | 6 ++++ > src/emacs-module.c | 45 +++++++++++++++++++++++++--- > src/lisp.h | 1 + > src/module-env-28.h | 8 +++++ > test/data/emacs-module/mod-test.c | 49 +++++++++++++++++++++++++++++-- > test/src/emacs-module-tests.el | 8 +++++ > 6 files changed, 111 insertions(+), 6 deletions(-) > > diff --git a/src/alloc.c b/src/alloc.c > index 6a17bedc75..94c1433124 100644 > --- a/src/alloc.c > +++ b/src/alloc.c > @@ -3023,6 +3023,12 @@ cleanup_vector (struct Lisp_Vector *vector) > if (uptr->finalizer) > uptr->finalizer (uptr->p); > } > + else if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_MODULE_FUNCTION)) > + { > + ATTRIBUTE_MAY_ALIAS struct Lisp_Module_Function *function > + = (struct Lisp_Module_Function *) vector; > + module_finalize_function (function); > + } > } > > /* Reclaim space used by unmarked vectors. */ > diff --git a/src/emacs-module.c b/src/emacs-module.c > index ff1a05450c..9ec25d57af 100644 > --- a/src/emacs-module.c > +++ b/src/emacs-module.c > @@ -122,10 +122,11 @@ Copyright (C) 2015-2019 Free Software Foundation, Inc. > /* Function prototype for the module init function. */ > typedef int (*emacs_init_function) (struct emacs_runtime *); > > -/* Function prototype for module user-pointer finalizers. These > - should not throw C++ exceptions, so emacs-module.h declares the > - corresponding interfaces with EMACS_NOEXCEPT. There is only C code > - in this module, though, so this constraint is not enforced here. */ > +/* Function prototype for module user-pointer and function finalizers. > + These should not throw C++ exceptions, so emacs-module.h declares > + the corresponding interfaces with EMACS_NOEXCEPT. There is only C > + code in this module, though, so this constraint is not enforced > + here. */ > typedef void (*emacs_finalizer) (void *); > > > @@ -332,6 +333,12 @@ #define MODULE_FUNCTION_BEGIN(error_retval) \ > MODULE_FUNCTION_BEGIN_NO_CATCH (error_retval); \ > MODULE_HANDLE_NONLOCAL_EXIT (error_retval) > > +static void > +CHECK_MODULE_FUNCTION (Lisp_Object obj) > +{ > + CHECK_TYPE (MODULE_FUNCTIONP (obj), Qmodule_function_p, obj); > +} > + > static void > CHECK_USER_PTR (Lisp_Object obj) > { > @@ -488,6 +495,7 @@ module_non_local_exit_throw (emacs_env *env, emacs_value tag, emacs_value value) > ptrdiff_t min_arity, max_arity; > emacs_subr subr; > void *data; > + emacs_finalizer finalizer; > } GCALIGNED_STRUCT; > > static struct Lisp_Module_Function * > @@ -521,6 +529,7 @@ module_make_function (emacs_env *env, ptrdiff_t min_arity, ptrdiff_t max_arity, > function->max_arity = max_arity; > function->subr = func; > function->data = data; > + function->finalizer = NULL; > > if (docstring) > function->documentation = build_string_from_utf8 (docstring); > @@ -532,6 +541,32 @@ module_make_function (emacs_env *env, ptrdiff_t min_arity, ptrdiff_t max_arity, > return lisp_to_value (env, result); > } > > +static emacs_finalizer > +module_get_function_finalizer (emacs_env *env, emacs_value arg) > +{ > + MODULE_FUNCTION_BEGIN (NULL); > + Lisp_Object lisp = value_to_lisp (arg); > + CHECK_MODULE_FUNCTION (lisp); > + return XMODULE_FUNCTION (lisp)->finalizer; > +} > + > +static void > +module_set_function_finalizer (emacs_env *env, emacs_value arg, > + emacs_finalizer fin) > +{ > + MODULE_FUNCTION_BEGIN (); > + Lisp_Object lisp = value_to_lisp (arg); > + CHECK_MODULE_FUNCTION (lisp); > + XMODULE_FUNCTION (lisp)->finalizer = fin; > +} > + > +void > +module_finalize_function (const struct Lisp_Module_Function *func) > +{ > + if (func->finalizer != NULL) > + func->finalizer (func->data); > +} > + > static emacs_value > module_funcall (emacs_env *env, emacs_value func, ptrdiff_t nargs, > emacs_value *args) > @@ -1339,6 +1374,8 @@ initialize_environment (emacs_env *env, struct emacs_env_private *priv) > env->make_time = module_make_time; > env->extract_big_integer = module_extract_big_integer; > env->make_big_integer = module_make_big_integer; > + env->get_function_finalizer = module_get_function_finalizer; > + env->set_function_finalizer = module_set_function_finalizer; > Vmodule_environments = Fcons (make_mint_ptr (env), Vmodule_environments); > return env; > } > diff --git a/src/lisp.h b/src/lisp.h > index e0ae2c4262..1bd78284d7 100644 > --- a/src/lisp.h > +++ b/src/lisp.h > @@ -4245,6 +4245,7 @@ XMODULE_FUNCTION (Lisp_Object o) > (struct Lisp_Module_Function const *); > extern module_funcptr module_function_address > (struct Lisp_Module_Function const *); > +extern void module_finalize_function (const struct Lisp_Module_Function *); > extern void mark_modules (void); > extern void init_module_assertions (bool); > extern void syms_of_module (void); > diff --git a/src/module-env-28.h b/src/module-env-28.h > index dec8704edd..a2479a8f74 100644 > --- a/src/module-env-28.h > +++ b/src/module-env-28.h > @@ -1,3 +1,11 @@ > /* Add module environment functions newly added in Emacs 28 here. > Before Emacs 28 is released, remove this comment and start > module-env-29.h on the master branch. */ > + > + void (*(*EMACS_ATTRIBUTE_NONNULL (1) > + get_function_finalizer) (emacs_env *env, > + emacs_value arg)) (void *) EMACS_NOEXCEPT; > + > + void (*set_function_finalizer) (emacs_env *env, emacs_value arg, > + void (*fin) (void *) EMACS_NOEXCEPT) > + EMACS_ATTRIBUTE_NONNULL (1); > diff --git a/test/data/emacs-module/mod-test.c b/test/data/emacs-module/mod-test.c > index 5addf61147..6a70a7ab57 100644 > --- a/test/data/emacs-module/mod-test.c > +++ b/test/data/emacs-module/mod-test.c > @@ -373,15 +373,20 @@ Fmod_test_add_nanosecond (emacs_env *env, ptrdiff_t nargs, emacs_value *args, > } > > static void > -memory_full (emacs_env *env) > +signal_error (emacs_env *env, const char *message) > { > - const char *message = "Memory exhausted"; > emacs_value data = env->make_string (env, message, strlen (message)); > env->non_local_exit_signal (env, env->intern (env, "error"), > env->funcall (env, env->intern (env, "list"), 1, > &data)); > } > > +static void > +memory_full (emacs_env *env) > +{ > + signal_error (env, "Memory exhausted"); > +} > + > enum > { > max_count = ((SIZE_MAX < PTRDIFF_MAX ? SIZE_MAX : PTRDIFF_MAX) > @@ -490,6 +495,42 @@ Fmod_test_double (emacs_env *env, ptrdiff_t nargs, emacs_value *args, > return result; > } > > +static int function_data; > +static int finalizer_calls_with_correct_data; > +static int finalizer_calls_with_incorrect_data; > + > +static void > +finalizer (void *data) > +{ > + if (data == &function_data) > + ++finalizer_calls_with_correct_data; > + else > + ++finalizer_calls_with_incorrect_data; > +} > + > +static emacs_value > +Fmod_test_make_function_with_finalizer (emacs_env *env, ptrdiff_t nargs, > + emacs_value *args, void *data) > +{ > + emacs_value fun > + = env->make_function (env, 2, 2, Fmod_test_sum, NULL, &function_data); > + env->set_function_finalizer (env, fun, finalizer); > + if (env->get_function_finalizer (env, fun) != finalizer) > + signal_error (env, "Invalid finalizer"); > + return fun; > +} > + > +static emacs_value > +Fmod_test_function_finalizer_calls (emacs_env *env, ptrdiff_t nargs, > + emacs_value *args, void *data) > +{ > + emacs_value Flist = env->intern (env, "list"); > + emacs_value list_args[] > + = {env->make_integer (env, finalizer_calls_with_correct_data), > + env->make_integer (env, finalizer_calls_with_incorrect_data)}; > + return env->funcall (env, Flist, 2, list_args); > +} > + > /* Lisp utilities for easier readability (simple wrappers). */ > > /* Provide FEATURE to Emacs. */ > @@ -566,6 +607,10 @@ #define DEFUN(lsym, csym, amin, amax, doc, data) \ > DEFUN ("mod-test-add-nanosecond", Fmod_test_add_nanosecond, 1, 1, NULL, NULL); > DEFUN ("mod-test-nanoseconds", Fmod_test_nanoseconds, 1, 1, NULL, NULL); > DEFUN ("mod-test-double", Fmod_test_double, 1, 1, NULL, NULL); > + DEFUN ("mod-test-make-function-with-finalizer", > + Fmod_test_make_function_with_finalizer, 0, 0, NULL, NULL); > + DEFUN ("mod-test-function-finalizer-calls", > + Fmod_test_function_finalizer_calls, 0, 0, NULL, NULL); > > #undef DEFUN > > diff --git a/test/src/emacs-module-tests.el b/test/src/emacs-module-tests.el > index 322500ff60..d9a57aecf6 100644 > --- a/test/src/emacs-module-tests.el > +++ b/test/src/emacs-module-tests.el > @@ -402,4 +402,12 @@ module-darwin-secondary-suffix > (load so nil nil :nosuffix :must-suffix) > (delete-file so)))) > > +(ert-deftest module/function-finalizer () > + (mod-test-make-function-with-finalizer) > + (let* ((previous-calls (mod-test-function-finalizer-calls)) > + (expected-calls (copy-sequence previous-calls))) > + (cl-incf (car expected-calls)) > + (garbage-collect) > + (should (equal (mod-test-function-finalizer-calls) expected-calls)))) > + > ;;; emacs-module-tests.el ends here > -- > 2.21.0 (Apple Git-122.2) > > > >
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.