2015-11-19 08:14:00 -08:00
|
|
|
/* Test GNU Emacs modules.
|
|
|
|
|
2024-01-02 09:47:10 +08:00
|
|
|
Copyright 2015-2024 Free Software Foundation, Inc.
|
2015-11-19 08:14:00 -08:00
|
|
|
|
|
|
|
This file is part of GNU Emacs.
|
|
|
|
|
|
|
|
GNU Emacs is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
2016-03-10 07:34:52 -08:00
|
|
|
the Free Software Foundation, either version 3 of the License, or (at
|
|
|
|
your option) any later version.
|
2015-11-19 08:14:00 -08:00
|
|
|
|
|
|
|
GNU Emacs is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
2017-09-13 15:52:52 -07:00
|
|
|
along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
2015-11-19 08:14:00 -08:00
|
|
|
|
2019-01-02 22:04:56 +01:00
|
|
|
#include "config.h"
|
|
|
|
|
2019-05-05 09:07:44 -07:00
|
|
|
#undef NDEBUG
|
2015-11-16 01:00:25 +01:00
|
|
|
#include <assert.h>
|
2019-05-05 09:07:44 -07:00
|
|
|
|
2019-01-02 22:04:56 +01:00
|
|
|
#include <errno.h>
|
|
|
|
#include <limits.h>
|
2020-01-05 16:05:14 +01:00
|
|
|
#include <stdint.h>
|
2015-11-16 01:00:25 +01:00
|
|
|
#include <stdio.h>
|
2015-11-20 13:37:25 +02:00
|
|
|
#include <stdlib.h>
|
2019-01-02 22:04:56 +01:00
|
|
|
#include <string.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
2020-03-27 15:43:20 +03:00
|
|
|
#ifdef WINDOWSNT
|
|
|
|
/* Cannot include <process.h> because of the local header by the same
|
|
|
|
name, sigh. */
|
2024-01-20 16:52:31 -08:00
|
|
|
uintptr_t _beginthread (void (__cdecl *) (void *), unsigned, void *);
|
2020-03-27 15:43:20 +03:00
|
|
|
# if !defined __x86_64__
|
2024-01-20 16:52:31 -08:00
|
|
|
# define ALIGN_STACK __attribute__ ((force_align_arg_pointer))
|
2020-03-27 15:43:20 +03:00
|
|
|
# endif
|
|
|
|
# include <windows.h> /* for Sleep */
|
|
|
|
#else /* !WINDOWSNT */
|
|
|
|
# include <pthread.h>
|
|
|
|
# include <unistd.h>
|
|
|
|
#endif
|
2020-03-26 17:22:25 +01:00
|
|
|
|
2019-04-24 19:35:36 +02:00
|
|
|
#include <gmp.h>
|
2015-11-19 13:50:23 -08:00
|
|
|
#include <emacs-module.h>
|
2015-11-16 01:00:25 +01:00
|
|
|
|
|
|
|
int plugin_is_GPL_compatible;
|
|
|
|
|
2018-01-19 11:20:12 +02:00
|
|
|
#if INTPTR_MAX <= 0
|
|
|
|
# error "INTPTR_MAX misconfigured"
|
|
|
|
#elif INTPTR_MAX <= INT_MAX || INTPTR_MAX <= LONG_MAX
|
|
|
|
# define pT "ld"
|
|
|
|
# define pZ "lu"
|
|
|
|
# define T_TYPE long
|
|
|
|
# define Z_TYPE unsigned long
|
|
|
|
#elif INTPTR_MAX <= INT64_MAX
|
|
|
|
# ifdef __MINGW32__
|
|
|
|
# define pT "lld"
|
|
|
|
# define pZ "llu"
|
|
|
|
# define T_TYPE long long
|
|
|
|
# define Z_TYPE unsigned long long
|
|
|
|
# else
|
|
|
|
# define pT "ld"
|
|
|
|
# define pZ "lu"
|
|
|
|
# define T_TYPE long
|
|
|
|
# define Z_TYPE unsigned long
|
|
|
|
# endif
|
|
|
|
#else
|
|
|
|
# error "INTPTR_MAX too large"
|
|
|
|
#endif
|
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Always return symbol 't'. */
|
|
|
|
static emacs_value
|
2015-11-20 12:17:55 -08:00
|
|
|
Fmod_test_return_t (emacs_env *env, ptrdiff_t nargs, emacs_value args[],
|
|
|
|
void *data)
|
2015-11-16 01:00:25 +01:00
|
|
|
{
|
|
|
|
return env->intern (env, "t");
|
|
|
|
}
|
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Expose simple sum function. */
|
2015-11-19 14:03:29 -08:00
|
|
|
static intmax_t
|
|
|
|
sum (intmax_t a, intmax_t b)
|
2015-11-16 01:00:25 +01:00
|
|
|
{
|
|
|
|
return a + b;
|
|
|
|
}
|
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
static emacs_value
|
2015-11-20 12:17:55 -08:00
|
|
|
Fmod_test_sum (emacs_env *env, ptrdiff_t nargs, emacs_value args[], void *data)
|
2015-11-16 01:00:25 +01:00
|
|
|
{
|
2015-11-24 21:08:22 +02:00
|
|
|
assert (nargs == 2);
|
2020-01-05 16:05:14 +01:00
|
|
|
assert ((uintptr_t) data == 0x1234);
|
2015-11-24 21:08:22 +02:00
|
|
|
|
2015-11-19 14:03:29 -08:00
|
|
|
intmax_t a = env->extract_integer (env, args[0]);
|
|
|
|
intmax_t b = env->extract_integer (env, args[1]);
|
2015-11-16 01:00:25 +01:00
|
|
|
|
2015-11-19 14:03:29 -08:00
|
|
|
intmax_t r = sum (a, b);
|
2015-11-16 01:00:25 +01:00
|
|
|
|
|
|
|
return env->make_integer (env, r);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Signal '(error 56). */
|
|
|
|
static emacs_value
|
2015-11-20 12:17:55 -08:00
|
|
|
Fmod_test_signal (emacs_env *env, ptrdiff_t nargs, emacs_value args[],
|
|
|
|
void *data)
|
2015-11-16 01:00:25 +01:00
|
|
|
{
|
|
|
|
assert (env->non_local_exit_check (env) == emacs_funcall_exit_return);
|
2015-11-19 11:31:45 -08:00
|
|
|
env->non_local_exit_signal (env, env->intern (env, "error"),
|
|
|
|
env->make_integer (env, 56));
|
2019-03-22 11:02:46 +03:00
|
|
|
return NULL;
|
2015-11-16 01:00:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Throw '(tag 65). */
|
|
|
|
static emacs_value
|
2015-11-20 12:17:55 -08:00
|
|
|
Fmod_test_throw (emacs_env *env, ptrdiff_t nargs, emacs_value args[],
|
|
|
|
void *data)
|
2015-11-16 01:00:25 +01:00
|
|
|
{
|
|
|
|
assert (env->non_local_exit_check (env) == emacs_funcall_exit_return);
|
2015-11-19 11:31:45 -08:00
|
|
|
env->non_local_exit_throw (env, env->intern (env, "tag"),
|
|
|
|
env->make_integer (env, 65));
|
2019-03-22 11:02:46 +03:00
|
|
|
return NULL;
|
2015-11-16 01:00:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Call argument function, catch all non-local exists and return
|
|
|
|
either normal result or a list describing the non-local exit. */
|
|
|
|
static emacs_value
|
2015-11-20 12:17:55 -08:00
|
|
|
Fmod_test_non_local_exit_funcall (emacs_env *env, ptrdiff_t nargs,
|
|
|
|
emacs_value args[], void *data)
|
2015-11-16 01:00:25 +01:00
|
|
|
{
|
|
|
|
assert (nargs == 1);
|
Omit ‘const’ on locals
Remove ‘const’ qualifier from locals that were newly added.
We don’t normally bother declaring locals with ‘const’ even
though they are not modified, for the same reason we don’t
bother declaring them with ‘register’ even though their
addresses are not taken; the advantage in compile-time
checking isn’t worth the loss of readability.
* modules/mod-test/mod-test.c (Fmod_test_non_local_exit_funcall)
(Fmod_test_vector_fill, Fmod_test_vector_eq):
* src/emacs-module.c (MODULE_SETJMP_1)
(module_make_global_ref, module_free_global_ref)
(module_non_local_exit_get, module_make_function)
(module_extract_integer, module_extract_float)
(module_get_user_ptr, module_set_user_ptr)
(module_get_user_finalizer, module_set_user_finalizer)
(module_vec_get, Fmodule_call)
(module_non_local_exit_signal_1)
(module_non_local_exit_throw_1, lisp_to_value)
(finalize_storage, allocate_emacs_value, mark_modules)
(module_handle_signal, module_handle_throw)
(module_format_fun_env):
* src/eval.c (push_handler, push_handler_nosignal)
(init_handler):
* src/lread.c (suffix_p):
Omit unnecessary ‘const’.
2015-11-19 14:24:50 -08:00
|
|
|
emacs_value result = env->funcall (env, args[0], 0, NULL);
|
2015-11-16 01:00:25 +01:00
|
|
|
emacs_value non_local_exit_symbol, non_local_exit_data;
|
2015-11-19 11:31:45 -08:00
|
|
|
enum emacs_funcall_exit code
|
|
|
|
= env->non_local_exit_get (env, &non_local_exit_symbol,
|
|
|
|
&non_local_exit_data);
|
2015-11-16 01:00:25 +01:00
|
|
|
switch (code)
|
|
|
|
{
|
|
|
|
case emacs_funcall_exit_return:
|
|
|
|
return result;
|
|
|
|
case emacs_funcall_exit_signal:
|
|
|
|
{
|
|
|
|
env->non_local_exit_clear (env);
|
Omit ‘const’ on locals
Remove ‘const’ qualifier from locals that were newly added.
We don’t normally bother declaring locals with ‘const’ even
though they are not modified, for the same reason we don’t
bother declaring them with ‘register’ even though their
addresses are not taken; the advantage in compile-time
checking isn’t worth the loss of readability.
* modules/mod-test/mod-test.c (Fmod_test_non_local_exit_funcall)
(Fmod_test_vector_fill, Fmod_test_vector_eq):
* src/emacs-module.c (MODULE_SETJMP_1)
(module_make_global_ref, module_free_global_ref)
(module_non_local_exit_get, module_make_function)
(module_extract_integer, module_extract_float)
(module_get_user_ptr, module_set_user_ptr)
(module_get_user_finalizer, module_set_user_finalizer)
(module_vec_get, Fmodule_call)
(module_non_local_exit_signal_1)
(module_non_local_exit_throw_1, lisp_to_value)
(finalize_storage, allocate_emacs_value, mark_modules)
(module_handle_signal, module_handle_throw)
(module_format_fun_env):
* src/eval.c (push_handler, push_handler_nosignal)
(init_handler):
* src/lread.c (suffix_p):
Omit unnecessary ‘const’.
2015-11-19 14:24:50 -08:00
|
|
|
emacs_value Flist = env->intern (env, "list");
|
2015-11-19 11:31:45 -08:00
|
|
|
emacs_value list_args[] = {env->intern (env, "signal"),
|
|
|
|
non_local_exit_symbol, non_local_exit_data};
|
2015-11-16 01:00:25 +01:00
|
|
|
return env->funcall (env, Flist, 3, list_args);
|
|
|
|
}
|
|
|
|
case emacs_funcall_exit_throw:
|
|
|
|
{
|
|
|
|
env->non_local_exit_clear (env);
|
Omit ‘const’ on locals
Remove ‘const’ qualifier from locals that were newly added.
We don’t normally bother declaring locals with ‘const’ even
though they are not modified, for the same reason we don’t
bother declaring them with ‘register’ even though their
addresses are not taken; the advantage in compile-time
checking isn’t worth the loss of readability.
* modules/mod-test/mod-test.c (Fmod_test_non_local_exit_funcall)
(Fmod_test_vector_fill, Fmod_test_vector_eq):
* src/emacs-module.c (MODULE_SETJMP_1)
(module_make_global_ref, module_free_global_ref)
(module_non_local_exit_get, module_make_function)
(module_extract_integer, module_extract_float)
(module_get_user_ptr, module_set_user_ptr)
(module_get_user_finalizer, module_set_user_finalizer)
(module_vec_get, Fmodule_call)
(module_non_local_exit_signal_1)
(module_non_local_exit_throw_1, lisp_to_value)
(finalize_storage, allocate_emacs_value, mark_modules)
(module_handle_signal, module_handle_throw)
(module_format_fun_env):
* src/eval.c (push_handler, push_handler_nosignal)
(init_handler):
* src/lread.c (suffix_p):
Omit unnecessary ‘const’.
2015-11-19 14:24:50 -08:00
|
|
|
emacs_value Flist = env->intern (env, "list");
|
2015-11-19 11:31:45 -08:00
|
|
|
emacs_value list_args[] = {env->intern (env, "throw"),
|
|
|
|
non_local_exit_symbol, non_local_exit_data};
|
2015-11-16 01:00:25 +01:00
|
|
|
return env->funcall (env, Flist, 3, list_args);
|
|
|
|
}
|
|
|
|
}
|
2015-11-19 11:31:45 -08:00
|
|
|
|
|
|
|
/* Never reached. */
|
2015-11-16 01:00:25 +01:00
|
|
|
return env->intern (env, "nil");;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-29 21:50:59 -08:00
|
|
|
/* Return a global reference. */
|
2015-11-19 11:31:45 -08:00
|
|
|
static emacs_value
|
2015-11-20 12:17:55 -08:00
|
|
|
Fmod_test_globref_make (emacs_env *env, ptrdiff_t nargs, emacs_value args[],
|
2015-11-19 11:31:45 -08:00
|
|
|
void *data)
|
2015-11-16 01:00:25 +01:00
|
|
|
{
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Make a big string and make it global. */
|
|
|
|
char str[26 * 100];
|
2015-11-19 15:01:26 -08:00
|
|
|
for (int i = 0; i < sizeof str; i++)
|
2015-11-19 11:31:45 -08:00
|
|
|
str[i] = 'a' + (i % 26);
|
2015-11-16 01:00:25 +01:00
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* We don't need to null-terminate str. */
|
|
|
|
emacs_value lisp_str = env->make_string (env, str, sizeof str);
|
2015-11-16 01:00:25 +01:00
|
|
|
return env->make_global_ref (env, lisp_str);
|
|
|
|
}
|
|
|
|
|
2018-08-19 21:31:01 +01:00
|
|
|
/* Create a few global references from arguments and free them. */
|
|
|
|
static emacs_value
|
|
|
|
Fmod_test_globref_free (emacs_env *env, ptrdiff_t nargs, emacs_value args[],
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
emacs_value refs[10];
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
|
|
{
|
|
|
|
refs[i] = env->make_global_ref (env, args[i % nargs]);
|
|
|
|
}
|
|
|
|
for (int i = 0; i < 10; i++)
|
|
|
|
{
|
|
|
|
env->free_global_ref (env, refs[i]);
|
|
|
|
}
|
|
|
|
return env->intern (env, "ok");
|
|
|
|
}
|
|
|
|
|
2020-07-25 23:23:19 +02:00
|
|
|
/* Treat a local reference as global and free it. Module assertions
|
|
|
|
should detect this case even if a global reference representing the
|
|
|
|
same object also exists. */
|
2018-08-19 21:31:01 +01:00
|
|
|
|
2020-07-25 23:23:19 +02:00
|
|
|
static emacs_value
|
|
|
|
Fmod_test_globref_invalid_free (emacs_env *env, ptrdiff_t nargs,
|
|
|
|
emacs_value *args, void *data)
|
|
|
|
{
|
|
|
|
emacs_value local = env->make_integer (env, 9876);
|
|
|
|
env->make_global_ref (env, local);
|
|
|
|
env->free_global_ref (env, local); /* Not allowed. */
|
|
|
|
return env->intern (env, "nil");
|
|
|
|
}
|
2015-11-16 01:00:25 +01:00
|
|
|
|
2020-07-26 22:54:33 +02:00
|
|
|
/* Allocate and free global references in a different order. */
|
|
|
|
|
|
|
|
static emacs_value
|
|
|
|
Fmod_test_globref_reordered (emacs_env *env, ptrdiff_t nargs,
|
|
|
|
emacs_value *args, void *data)
|
|
|
|
{
|
|
|
|
emacs_value booleans[2] = {
|
|
|
|
env->intern (env, "nil"),
|
|
|
|
env->intern (env, "t"),
|
|
|
|
};
|
|
|
|
emacs_value local = env->intern (env, "foo");
|
|
|
|
emacs_value globals[4] = {
|
|
|
|
env->make_global_ref (env, local),
|
|
|
|
env->make_global_ref (env, local),
|
|
|
|
env->make_global_ref (env, env->intern (env, "foo")),
|
|
|
|
env->make_global_ref (env, env->intern (env, "bar")),
|
|
|
|
};
|
|
|
|
emacs_value elements[4];
|
|
|
|
for (int i = 0; i < 4; ++i)
|
|
|
|
elements[i] = booleans[env->eq (env, globals[i], local)];
|
|
|
|
emacs_value ret = env->funcall (env, env->intern (env, "list"), 4, elements);
|
|
|
|
env->free_global_ref (env, globals[2]);
|
|
|
|
env->free_global_ref (env, globals[1]);
|
|
|
|
env->free_global_ref (env, globals[3]);
|
|
|
|
env->free_global_ref (env, globals[0]);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Return a copy of the argument string where every 'a' is replaced
|
|
|
|
with 'b'. */
|
|
|
|
static emacs_value
|
2015-11-20 12:17:55 -08:00
|
|
|
Fmod_test_string_a_to_b (emacs_env *env, ptrdiff_t nargs, emacs_value args[],
|
2015-11-19 11:31:45 -08:00
|
|
|
void *data)
|
2015-11-16 01:00:25 +01:00
|
|
|
{
|
|
|
|
emacs_value lisp_str = args[0];
|
2015-11-19 15:01:26 -08:00
|
|
|
ptrdiff_t size = 0;
|
2015-11-16 01:00:25 +01:00
|
|
|
char * buf = NULL;
|
|
|
|
|
|
|
|
env->copy_string_contents (env, lisp_str, buf, &size);
|
|
|
|
buf = malloc (size);
|
|
|
|
env->copy_string_contents (env, lisp_str, buf, &size);
|
|
|
|
|
2015-11-19 15:01:26 -08:00
|
|
|
for (ptrdiff_t i = 0; i + 1 < size; i++)
|
2015-11-16 01:00:25 +01:00
|
|
|
if (buf[i] == 'a')
|
|
|
|
buf[i] = 'b';
|
|
|
|
|
2020-08-01 14:10:33 +02:00
|
|
|
emacs_value ret = env->make_string (env, buf, size - 1);
|
|
|
|
free (buf);
|
|
|
|
return ret;
|
2015-11-16 01:00:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-10-13 06:51:06 +02:00
|
|
|
/* Return a unibyte string. */
|
|
|
|
static emacs_value
|
|
|
|
Fmod_test_return_unibyte (emacs_env *env, ptrdiff_t nargs, emacs_value args[],
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
const char *string = "foo\x00zot";
|
|
|
|
return env->make_unibyte_string (env, string, 7);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Embedded pointers in lisp objects. */
|
2015-11-16 01:00:25 +01:00
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* C struct (pointer to) that will be embedded. */
|
2015-11-16 01:00:25 +01:00
|
|
|
struct super_struct
|
|
|
|
{
|
|
|
|
int amazing_int;
|
|
|
|
char large_unused_buffer[512];
|
|
|
|
};
|
|
|
|
|
2021-07-12 00:06:34 -07:00
|
|
|
static void signal_errno (emacs_env *, char const *);
|
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Return a new user-pointer to a super_struct, with amazing_int set
|
|
|
|
to the passed parameter. */
|
|
|
|
static emacs_value
|
2015-11-20 12:17:55 -08:00
|
|
|
Fmod_test_userptr_make (emacs_env *env, ptrdiff_t nargs, emacs_value args[],
|
2015-11-19 11:31:45 -08:00
|
|
|
void *data)
|
2015-11-16 01:00:25 +01:00
|
|
|
{
|
2015-11-19 11:31:45 -08:00
|
|
|
struct super_struct *p = calloc (1, sizeof *p);
|
2021-07-12 00:06:34 -07:00
|
|
|
if (!p)
|
2021-10-12 17:10:46 -07:00
|
|
|
{
|
|
|
|
signal_errno (env, "calloc");
|
|
|
|
return NULL;
|
|
|
|
}
|
2015-11-16 01:00:25 +01:00
|
|
|
p->amazing_int = env->extract_integer (env, args[0]);
|
2015-11-19 11:31:45 -08:00
|
|
|
return env->make_user_ptr (env, free, p);
|
2015-11-16 01:00:25 +01:00
|
|
|
}
|
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Return the amazing_int of a passed 'user-pointer to a super_struct'. */
|
|
|
|
static emacs_value
|
2015-11-20 12:17:55 -08:00
|
|
|
Fmod_test_userptr_get (emacs_env *env, ptrdiff_t nargs, emacs_value args[],
|
|
|
|
void *data)
|
2015-11-16 01:00:25 +01:00
|
|
|
{
|
|
|
|
struct super_struct *p = env->get_user_ptr (env, args[0]);
|
|
|
|
return env->make_integer (env, p->amazing_int);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Fill vector in args[0] with value in args[1]. */
|
|
|
|
static emacs_value
|
2015-11-20 12:17:55 -08:00
|
|
|
Fmod_test_vector_fill (emacs_env *env, ptrdiff_t nargs, emacs_value args[],
|
|
|
|
void *data)
|
2015-11-16 01:00:25 +01:00
|
|
|
{
|
|
|
|
emacs_value vec = args[0];
|
|
|
|
emacs_value val = args[1];
|
2015-11-19 15:01:26 -08:00
|
|
|
ptrdiff_t size = env->vec_size (env, vec);
|
|
|
|
for (ptrdiff_t i = 0; i < size; i++)
|
2015-11-16 01:00:25 +01:00
|
|
|
env->vec_set (env, vec, i, val);
|
|
|
|
return env->intern (env, "t");
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Return whether all elements of vector in args[0] are 'eq' to value
|
|
|
|
in args[1]. */
|
|
|
|
static emacs_value
|
2015-11-20 12:17:55 -08:00
|
|
|
Fmod_test_vector_eq (emacs_env *env, ptrdiff_t nargs, emacs_value args[],
|
|
|
|
void *data)
|
2015-11-16 01:00:25 +01:00
|
|
|
{
|
|
|
|
emacs_value vec = args[0];
|
|
|
|
emacs_value val = args[1];
|
2015-11-19 15:01:26 -08:00
|
|
|
ptrdiff_t size = env->vec_size (env, vec);
|
|
|
|
for (ptrdiff_t i = 0; i < size; i++)
|
2015-11-16 01:00:25 +01:00
|
|
|
if (!env->eq (env, env->vec_get (env, vec, i), val))
|
|
|
|
return env->intern (env, "nil");
|
|
|
|
return env->intern (env, "t");
|
|
|
|
}
|
|
|
|
|
Implement module assertions for users
Add a new command-line option '-module-assertions' that users can
enable developing or debugging a module. If this option is present,
Emacs performs additional checks to verify that modules fulfill their
requirements. These checks are expensive and crash Emacs if modules
are invalid, so disable them by default.
This is a command-line option instead of an ordinary variable because
changing it while Emacs is running would cause data structure
imbalances.
* src/emacs.c (main): New command line option '-module-assertions'.
* src/emacs-module.c (module_assert_main_thread)
(module_assert_runtime, module_assert_env, module_assert_value):
New functions to assert module requirements.
(syms_of_module): New uninterned variable 'module-runtimes'.
(init_module_assertions, in_main_thread, module_abort): New helper
functions.
(initialize_environment): Initialize value list. If assertions are
enabled, use a heap-allocated environment object.
(finalize_environment): Add assertion that environment list is never
empty.
(finalize_runtime_unwind): Pop module runtime object stack.
(value_to_lisp): Assert that the value is valid.
(lisp_to_value): Record new value if assertions are enabled.
(mark_modules): Mark allocated object list.
(MODULE_FUNCTION_BEGIN_NO_CATCH)
(module_non_local_exit_check, module_non_local_exit_clear)
(module_non_local_exit_get, module_non_local_exit_signal)
(module_non_local_exit_throw): Assert thread and environment.
(module_get_environment): Assert thread and runtime.
(module_make_function, module_funcall, module_intern)
(module_funcall, module_make_integer, module_make_float)
(module_make_string, module_make_user_ptr, module_vec_get)
(funcall_module, Fmodule_load): Adapt callers.
(module_make_global_ref): If assertions are enabled, use the global
environment to store global values.
(module_free_global_ref): Remove value from global value list.
* test/Makefile.in (EMACSOPT): Enable module assertions when testing
modules.
* test/data/emacs-module/mod-test.c (Fmod_test_invalid_store)
(Fmod_test_invalid_load): New functions to test module assertions.
(emacs_module_init): Bind the new functions.
* test/src/emacs-module-tests.el (mod-test-emacs): New constant for
the Emacs binary file.
(mod-test-file): New constant for the test module file name.
(module--test-assertions): New unit test.
2017-06-05 13:29:14 +02:00
|
|
|
static emacs_value invalid_stored_value;
|
|
|
|
|
|
|
|
/* The next two functions perform a possibly-invalid operation: they
|
|
|
|
store a value in a static variable and load it. This causes
|
|
|
|
undefined behavior if the environment that the value was created
|
|
|
|
from is no longer live. The module assertions check for this
|
|
|
|
error. */
|
|
|
|
|
|
|
|
static emacs_value
|
|
|
|
Fmod_test_invalid_store (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
return invalid_stored_value = env->make_integer (env, 123);
|
|
|
|
}
|
|
|
|
|
|
|
|
static emacs_value
|
|
|
|
Fmod_test_invalid_load (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
return invalid_stored_value;
|
|
|
|
}
|
|
|
|
|
2020-07-25 23:04:05 +02:00
|
|
|
/* The next function works in conjunction with the two previous ones.
|
|
|
|
It stows away a copy of the object created by
|
|
|
|
`Fmod_test_invalid_store' in a global reference. Module assertions
|
|
|
|
should still detect the invalid load of the local reference. */
|
|
|
|
|
|
|
|
static emacs_value global_copy_of_invalid_stored_value;
|
|
|
|
|
|
|
|
static emacs_value
|
|
|
|
Fmod_test_invalid_store_copy (emacs_env *env, ptrdiff_t nargs,
|
|
|
|
emacs_value *args, void *data)
|
|
|
|
{
|
|
|
|
emacs_value local = Fmod_test_invalid_store (env, 0, NULL, NULL);
|
|
|
|
return global_copy_of_invalid_stored_value
|
|
|
|
= env->make_global_ref (env, local);
|
|
|
|
}
|
|
|
|
|
2017-07-04 22:50:46 +02:00
|
|
|
/* An invalid finalizer: Finalizers are run during garbage collection,
|
2020-03-27 15:43:20 +03:00
|
|
|
where Lisp code can't be executed. -module-assertions tests for
|
2017-07-04 22:50:46 +02:00
|
|
|
this case. */
|
|
|
|
|
|
|
|
static emacs_env *current_env;
|
|
|
|
|
|
|
|
static void
|
|
|
|
invalid_finalizer (void *ptr)
|
|
|
|
{
|
|
|
|
current_env->intern (current_env, "nil");
|
|
|
|
}
|
|
|
|
|
|
|
|
static emacs_value
|
|
|
|
Fmod_test_invalid_finalizer (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
current_env = env;
|
|
|
|
env->make_user_ptr (env, invalid_finalizer, NULL);
|
2019-03-22 11:02:46 +03:00
|
|
|
return env->intern (env, "nil");
|
2017-07-04 22:50:46 +02:00
|
|
|
}
|
|
|
|
|
2019-01-02 22:04:56 +01:00
|
|
|
static void
|
2020-03-26 17:22:25 +01:00
|
|
|
signal_system_error (emacs_env *env, int error, const char *function)
|
2019-01-02 22:04:56 +01:00
|
|
|
{
|
2020-03-26 17:22:25 +01:00
|
|
|
const char *message = strerror (error);
|
2019-01-02 22:04:56 +01:00
|
|
|
emacs_value message_value = env->make_string (env, message, strlen (message));
|
|
|
|
emacs_value symbol = env->intern (env, "file-error");
|
|
|
|
emacs_value elements[2]
|
|
|
|
= {env->make_string (env, function, strlen (function)), message_value};
|
|
|
|
emacs_value data = env->funcall (env, env->intern (env, "list"), 2, elements);
|
|
|
|
env->non_local_exit_signal (env, symbol, data);
|
|
|
|
}
|
|
|
|
|
2020-03-26 17:22:25 +01:00
|
|
|
static void
|
|
|
|
signal_errno (emacs_env *env, const char *function)
|
|
|
|
{
|
|
|
|
signal_system_error (env, errno, function);
|
|
|
|
}
|
|
|
|
|
Decouple mod-test.c from Gnulib
mod-test.c should not use Gnulib code, as that creates
unnecessary coupling between Emacs internals and this test module.
Also Gnulib code is compiled without -fPIC whereas mod-test.c
needs -fPIC and recompiling Gnulib with -fPIC would be too painful.
* src/Makefile.in (LIB_NANOSLEEP): New macro.
(LIBES): Use it.
* test/Makefile.in (REPLACE_FREE, FREE_SOURCE_0, FREE_SOURCE_0):
Remove. All uses removed.
(LIB_CLOCK_GETTIME, LIB_NANOSLEEP): New macros.
(MODULE_CFLAGS): Do not -I from lib as that would include Gnulib
modifications to standard .h files (e.g., "#define nanosleep
rpl_nanosleep") and we don’t want the Gnulib replacements.
Instead, for gmp.h (on platforms lacking <gmp.h>) simply '-I.'
with a suitable gmp.h.
(gmp.h): New rule to create a suitable gmp.h.
($(test_module)): Depend on config.h since the code uses config.h.
Depend on gmp.h if we need to create a suitable one.
If compiling mini-gmp.h, compile the original one and not
the Emacs-specific one, to lessen coupling with Emacs internals.
Link with LIB_CLOCK_GETTIME and LIB_NANOSLEEP.
(clean): Remove gmp.h.
* test/src/emacs-module-resources/mod-test.c: Don’t include timespec.h.
All uses of timespec.h APIs changed to use system-supplied APIs.
Change _Static_assert to plain assert, so that we needn’t rely
on Gnulib’s _Static_assert.
(timespec_le) [CLOCK_REALTIME]: New function.
Change use of timespec_cmp changed to use this instead.
(Fmod_test_sleep_until, Fmod_test_nanoseconds):
Define these functions and their Lisp names mod-test-sleep-until
and mod-test-nanoseconds only if CLOCK_REALTIME,
since they now won’t work on platforms lacking CLOCK_REALTIME.
(Fmod_test_nanoseconds): Just use _Static_assert since it
should work on all platforms.
* test/src/emacs-module-tests.el (mod-test-sleep-until)
(mod-test-nanoseconds, mod-test-double):
Skip test if the corresponding functione is not defined.
2022-03-08 18:46:47 -08:00
|
|
|
#ifdef CLOCK_REALTIME
|
|
|
|
|
|
|
|
/* Whether A <= B. */
|
|
|
|
static bool
|
|
|
|
timespec_le (struct timespec a, struct timespec b)
|
|
|
|
{
|
|
|
|
return (a.tv_sec < b.tv_sec
|
|
|
|
|| (a.tv_sec == b.tv_sec && a.tv_nsec <= b.tv_nsec));
|
|
|
|
}
|
|
|
|
|
2019-01-02 22:04:56 +01:00
|
|
|
/* A long-running operation that occasionally calls `should_quit' or
|
|
|
|
`process_input'. */
|
|
|
|
|
|
|
|
static emacs_value
|
|
|
|
Fmod_test_sleep_until (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
assert (nargs == 2);
|
2019-05-05 01:23:44 +02:00
|
|
|
const struct timespec until = env->extract_time (env, args[0]);
|
2019-01-02 22:04:56 +01:00
|
|
|
if (env->non_local_exit_check (env))
|
|
|
|
return NULL;
|
|
|
|
const bool process_input = env->is_not_nil (env, args[1]);
|
Decouple mod-test.c from Gnulib
mod-test.c should not use Gnulib code, as that creates
unnecessary coupling between Emacs internals and this test module.
Also Gnulib code is compiled without -fPIC whereas mod-test.c
needs -fPIC and recompiling Gnulib with -fPIC would be too painful.
* src/Makefile.in (LIB_NANOSLEEP): New macro.
(LIBES): Use it.
* test/Makefile.in (REPLACE_FREE, FREE_SOURCE_0, FREE_SOURCE_0):
Remove. All uses removed.
(LIB_CLOCK_GETTIME, LIB_NANOSLEEP): New macros.
(MODULE_CFLAGS): Do not -I from lib as that would include Gnulib
modifications to standard .h files (e.g., "#define nanosleep
rpl_nanosleep") and we don’t want the Gnulib replacements.
Instead, for gmp.h (on platforms lacking <gmp.h>) simply '-I.'
with a suitable gmp.h.
(gmp.h): New rule to create a suitable gmp.h.
($(test_module)): Depend on config.h since the code uses config.h.
Depend on gmp.h if we need to create a suitable one.
If compiling mini-gmp.h, compile the original one and not
the Emacs-specific one, to lessen coupling with Emacs internals.
Link with LIB_CLOCK_GETTIME and LIB_NANOSLEEP.
(clean): Remove gmp.h.
* test/src/emacs-module-resources/mod-test.c: Don’t include timespec.h.
All uses of timespec.h APIs changed to use system-supplied APIs.
Change _Static_assert to plain assert, so that we needn’t rely
on Gnulib’s _Static_assert.
(timespec_le) [CLOCK_REALTIME]: New function.
Change use of timespec_cmp changed to use this instead.
(Fmod_test_sleep_until, Fmod_test_nanoseconds):
Define these functions and their Lisp names mod-test-sleep-until
and mod-test-nanoseconds only if CLOCK_REALTIME,
since they now won’t work on platforms lacking CLOCK_REALTIME.
(Fmod_test_nanoseconds): Just use _Static_assert since it
should work on all platforms.
* test/src/emacs-module-tests.el (mod-test-sleep-until)
(mod-test-nanoseconds, mod-test-double):
Skip test if the corresponding functione is not defined.
2022-03-08 18:46:47 -08:00
|
|
|
const struct timespec amount = { .tv_nsec = 10000000 };
|
2019-01-02 22:04:56 +01:00
|
|
|
while (true)
|
|
|
|
{
|
Decouple mod-test.c from Gnulib
mod-test.c should not use Gnulib code, as that creates
unnecessary coupling between Emacs internals and this test module.
Also Gnulib code is compiled without -fPIC whereas mod-test.c
needs -fPIC and recompiling Gnulib with -fPIC would be too painful.
* src/Makefile.in (LIB_NANOSLEEP): New macro.
(LIBES): Use it.
* test/Makefile.in (REPLACE_FREE, FREE_SOURCE_0, FREE_SOURCE_0):
Remove. All uses removed.
(LIB_CLOCK_GETTIME, LIB_NANOSLEEP): New macros.
(MODULE_CFLAGS): Do not -I from lib as that would include Gnulib
modifications to standard .h files (e.g., "#define nanosleep
rpl_nanosleep") and we don’t want the Gnulib replacements.
Instead, for gmp.h (on platforms lacking <gmp.h>) simply '-I.'
with a suitable gmp.h.
(gmp.h): New rule to create a suitable gmp.h.
($(test_module)): Depend on config.h since the code uses config.h.
Depend on gmp.h if we need to create a suitable one.
If compiling mini-gmp.h, compile the original one and not
the Emacs-specific one, to lessen coupling with Emacs internals.
Link with LIB_CLOCK_GETTIME and LIB_NANOSLEEP.
(clean): Remove gmp.h.
* test/src/emacs-module-resources/mod-test.c: Don’t include timespec.h.
All uses of timespec.h APIs changed to use system-supplied APIs.
Change _Static_assert to plain assert, so that we needn’t rely
on Gnulib’s _Static_assert.
(timespec_le) [CLOCK_REALTIME]: New function.
Change use of timespec_cmp changed to use this instead.
(Fmod_test_sleep_until, Fmod_test_nanoseconds):
Define these functions and their Lisp names mod-test-sleep-until
and mod-test-nanoseconds only if CLOCK_REALTIME,
since they now won’t work on platforms lacking CLOCK_REALTIME.
(Fmod_test_nanoseconds): Just use _Static_assert since it
should work on all platforms.
* test/src/emacs-module-tests.el (mod-test-sleep-until)
(mod-test-nanoseconds, mod-test-double):
Skip test if the corresponding functione is not defined.
2022-03-08 18:46:47 -08:00
|
|
|
struct timespec now;
|
|
|
|
if (clock_gettime (CLOCK_REALTIME, &now) != 0)
|
|
|
|
return NULL;
|
|
|
|
if (timespec_le (until, now))
|
2019-01-02 22:04:56 +01:00
|
|
|
break;
|
|
|
|
if (nanosleep (&amount, NULL) && errno != EINTR)
|
|
|
|
{
|
|
|
|
signal_errno (env, "nanosleep");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if ((process_input
|
|
|
|
&& env->process_input (env) == emacs_process_input_quit)
|
|
|
|
|| env->should_quit (env))
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return env->intern (env, "finished");
|
|
|
|
}
|
Decouple mod-test.c from Gnulib
mod-test.c should not use Gnulib code, as that creates
unnecessary coupling between Emacs internals and this test module.
Also Gnulib code is compiled without -fPIC whereas mod-test.c
needs -fPIC and recompiling Gnulib with -fPIC would be too painful.
* src/Makefile.in (LIB_NANOSLEEP): New macro.
(LIBES): Use it.
* test/Makefile.in (REPLACE_FREE, FREE_SOURCE_0, FREE_SOURCE_0):
Remove. All uses removed.
(LIB_CLOCK_GETTIME, LIB_NANOSLEEP): New macros.
(MODULE_CFLAGS): Do not -I from lib as that would include Gnulib
modifications to standard .h files (e.g., "#define nanosleep
rpl_nanosleep") and we don’t want the Gnulib replacements.
Instead, for gmp.h (on platforms lacking <gmp.h>) simply '-I.'
with a suitable gmp.h.
(gmp.h): New rule to create a suitable gmp.h.
($(test_module)): Depend on config.h since the code uses config.h.
Depend on gmp.h if we need to create a suitable one.
If compiling mini-gmp.h, compile the original one and not
the Emacs-specific one, to lessen coupling with Emacs internals.
Link with LIB_CLOCK_GETTIME and LIB_NANOSLEEP.
(clean): Remove gmp.h.
* test/src/emacs-module-resources/mod-test.c: Don’t include timespec.h.
All uses of timespec.h APIs changed to use system-supplied APIs.
Change _Static_assert to plain assert, so that we needn’t rely
on Gnulib’s _Static_assert.
(timespec_le) [CLOCK_REALTIME]: New function.
Change use of timespec_cmp changed to use this instead.
(Fmod_test_sleep_until, Fmod_test_nanoseconds):
Define these functions and their Lisp names mod-test-sleep-until
and mod-test-nanoseconds only if CLOCK_REALTIME,
since they now won’t work on platforms lacking CLOCK_REALTIME.
(Fmod_test_nanoseconds): Just use _Static_assert since it
should work on all platforms.
* test/src/emacs-module-tests.el (mod-test-sleep-until)
(mod-test-nanoseconds, mod-test-double):
Skip test if the corresponding functione is not defined.
2022-03-08 18:46:47 -08:00
|
|
|
#endif
|
2015-11-16 01:00:25 +01:00
|
|
|
|
2019-04-18 17:42:45 +02:00
|
|
|
static emacs_value
|
|
|
|
Fmod_test_add_nanosecond (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
assert (nargs == 1);
|
|
|
|
struct timespec time = env->extract_time (env, args[0]);
|
|
|
|
assert (time.tv_nsec >= 0);
|
|
|
|
assert (time.tv_nsec < 2000000000); /* possible leap second */
|
|
|
|
time.tv_nsec++;
|
|
|
|
return env->make_time (env, time);
|
|
|
|
}
|
|
|
|
|
Change module interface to no longer use GMP objects directly.
As described in the new comment added to emacs-module.c, using GMP
directly in the module interface has significant downsides: it couples
the module interface directly to the implementation and requires
module authors to link their module against the same GMP library as
Emacs itself, which is often difficult and an unnecessary burden. By
picking a representation for the magnitude that often matches the one
used by GMP, we can avoid overhead when converting from and to GMP in
most cases.
Loading the test module in test/data/emacs-module and evaluating
(dotimes (_ 10000)
(mod-test-double (* 2 most-negative-fixnum)))
under Callgrind shows that on my (GNU/Linux) machine Emacs only spends
10% of the CPU time of mod-test-double in mpz_import and mpz_export
combined, even though that function does little else. (By contrast,
30% is spent in allocate_pseudovector.)
* src/emacs-module.h.in: Don't check EMACS_MODULE_GMP. Don't include
gmp.h. Remove emacs_mpz structure. Instead, define type alias
emacs_limb_t and macro EMACS_LIMB_MAX.
* src/module-env-27.h: Change interface of extract_big_integer and
make_big_integer to take a sign-magnitude representation instead of
mpz_t.
* src/emacs-module.c: Don't check EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T. Add a comment about the chosen
implementation.
(module_extract_big_integer, module_make_big_integer): Reimplement
without using mpz_t in the interface.
* doc/lispref/internals.texi (Module Values): Adapt function
documentation and example. Stop mentioning GMP and EMACS_MODULE_GMP.
* test/data/emacs-module/mod-test.c: Don't define EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T.
(memory_full, extract_big_integer, make_big_integer): New helper
functions, identical to example in the Info documentation.
(Fmod_test_nanoseconds, Fmod_test_double): Adapt to new interface.
2019-11-02 10:54:57 +01:00
|
|
|
static void
|
2018-02-11 21:38:22 +01:00
|
|
|
signal_error (emacs_env *env, const char *message)
|
Change module interface to no longer use GMP objects directly.
As described in the new comment added to emacs-module.c, using GMP
directly in the module interface has significant downsides: it couples
the module interface directly to the implementation and requires
module authors to link their module against the same GMP library as
Emacs itself, which is often difficult and an unnecessary burden. By
picking a representation for the magnitude that often matches the one
used by GMP, we can avoid overhead when converting from and to GMP in
most cases.
Loading the test module in test/data/emacs-module and evaluating
(dotimes (_ 10000)
(mod-test-double (* 2 most-negative-fixnum)))
under Callgrind shows that on my (GNU/Linux) machine Emacs only spends
10% of the CPU time of mod-test-double in mpz_import and mpz_export
combined, even though that function does little else. (By contrast,
30% is spent in allocate_pseudovector.)
* src/emacs-module.h.in: Don't check EMACS_MODULE_GMP. Don't include
gmp.h. Remove emacs_mpz structure. Instead, define type alias
emacs_limb_t and macro EMACS_LIMB_MAX.
* src/module-env-27.h: Change interface of extract_big_integer and
make_big_integer to take a sign-magnitude representation instead of
mpz_t.
* src/emacs-module.c: Don't check EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T. Add a comment about the chosen
implementation.
(module_extract_big_integer, module_make_big_integer): Reimplement
without using mpz_t in the interface.
* doc/lispref/internals.texi (Module Values): Adapt function
documentation and example. Stop mentioning GMP and EMACS_MODULE_GMP.
* test/data/emacs-module/mod-test.c: Don't define EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T.
(memory_full, extract_big_integer, make_big_integer): New helper
functions, identical to example in the Info documentation.
(Fmod_test_nanoseconds, Fmod_test_double): Adapt to new interface.
2019-11-02 10:54:57 +01:00
|
|
|
{
|
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2018-02-11 21:38:22 +01:00
|
|
|
static void
|
|
|
|
memory_full (emacs_env *env)
|
|
|
|
{
|
|
|
|
signal_error (env, "Memory exhausted");
|
|
|
|
}
|
|
|
|
|
Change module interface to no longer use GMP objects directly.
As described in the new comment added to emacs-module.c, using GMP
directly in the module interface has significant downsides: it couples
the module interface directly to the implementation and requires
module authors to link their module against the same GMP library as
Emacs itself, which is often difficult and an unnecessary burden. By
picking a representation for the magnitude that often matches the one
used by GMP, we can avoid overhead when converting from and to GMP in
most cases.
Loading the test module in test/data/emacs-module and evaluating
(dotimes (_ 10000)
(mod-test-double (* 2 most-negative-fixnum)))
under Callgrind shows that on my (GNU/Linux) machine Emacs only spends
10% of the CPU time of mod-test-double in mpz_import and mpz_export
combined, even though that function does little else. (By contrast,
30% is spent in allocate_pseudovector.)
* src/emacs-module.h.in: Don't check EMACS_MODULE_GMP. Don't include
gmp.h. Remove emacs_mpz structure. Instead, define type alias
emacs_limb_t and macro EMACS_LIMB_MAX.
* src/module-env-27.h: Change interface of extract_big_integer and
make_big_integer to take a sign-magnitude representation instead of
mpz_t.
* src/emacs-module.c: Don't check EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T. Add a comment about the chosen
implementation.
(module_extract_big_integer, module_make_big_integer): Reimplement
without using mpz_t in the interface.
* doc/lispref/internals.texi (Module Values): Adapt function
documentation and example. Stop mentioning GMP and EMACS_MODULE_GMP.
* test/data/emacs-module/mod-test.c: Don't define EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T.
(memory_full, extract_big_integer, make_big_integer): New helper
functions, identical to example in the Info documentation.
(Fmod_test_nanoseconds, Fmod_test_double): Adapt to new interface.
2019-11-02 10:54:57 +01:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
max_count = ((SIZE_MAX < PTRDIFF_MAX ? SIZE_MAX : PTRDIFF_MAX)
|
|
|
|
/ sizeof (emacs_limb_t))
|
|
|
|
};
|
|
|
|
|
|
|
|
static bool
|
|
|
|
extract_big_integer (emacs_env *env, emacs_value arg, mpz_t result)
|
|
|
|
{
|
|
|
|
int sign;
|
|
|
|
ptrdiff_t count;
|
|
|
|
bool success = env->extract_big_integer (env, arg, &sign, &count, NULL);
|
|
|
|
if (!success)
|
|
|
|
return false;
|
|
|
|
if (sign == 0)
|
|
|
|
{
|
|
|
|
mpz_set_ui (result, 0);
|
|
|
|
return true;
|
|
|
|
}
|
2019-12-05 16:38:17 +02:00
|
|
|
enum { order = -1, size = sizeof (emacs_limb_t), endian = 0, nails = 0 };
|
Change module interface to no longer use GMP objects directly.
As described in the new comment added to emacs-module.c, using GMP
directly in the module interface has significant downsides: it couples
the module interface directly to the implementation and requires
module authors to link their module against the same GMP library as
Emacs itself, which is often difficult and an unnecessary burden. By
picking a representation for the magnitude that often matches the one
used by GMP, we can avoid overhead when converting from and to GMP in
most cases.
Loading the test module in test/data/emacs-module and evaluating
(dotimes (_ 10000)
(mod-test-double (* 2 most-negative-fixnum)))
under Callgrind shows that on my (GNU/Linux) machine Emacs only spends
10% of the CPU time of mod-test-double in mpz_import and mpz_export
combined, even though that function does little else. (By contrast,
30% is spent in allocate_pseudovector.)
* src/emacs-module.h.in: Don't check EMACS_MODULE_GMP. Don't include
gmp.h. Remove emacs_mpz structure. Instead, define type alias
emacs_limb_t and macro EMACS_LIMB_MAX.
* src/module-env-27.h: Change interface of extract_big_integer and
make_big_integer to take a sign-magnitude representation instead of
mpz_t.
* src/emacs-module.c: Don't check EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T. Add a comment about the chosen
implementation.
(module_extract_big_integer, module_make_big_integer): Reimplement
without using mpz_t in the interface.
* doc/lispref/internals.texi (Module Values): Adapt function
documentation and example. Stop mentioning GMP and EMACS_MODULE_GMP.
* test/data/emacs-module/mod-test.c: Don't define EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T.
(memory_full, extract_big_integer, make_big_integer): New helper
functions, identical to example in the Info documentation.
(Fmod_test_nanoseconds, Fmod_test_double): Adapt to new interface.
2019-11-02 10:54:57 +01:00
|
|
|
assert (0 < count && count <= max_count);
|
|
|
|
emacs_limb_t *magnitude = malloc (count * size);
|
|
|
|
if (magnitude == NULL)
|
|
|
|
{
|
|
|
|
memory_full (env);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
success = env->extract_big_integer (env, arg, NULL, &count, magnitude);
|
|
|
|
assert (success);
|
|
|
|
mpz_import (result, count, order, size, endian, nails, magnitude);
|
|
|
|
free (magnitude);
|
|
|
|
if (sign < 0)
|
|
|
|
mpz_neg (result, result);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static emacs_value
|
|
|
|
make_big_integer (emacs_env *env, const mpz_t value)
|
|
|
|
{
|
|
|
|
if (mpz_sgn (value) == 0)
|
|
|
|
return env->make_integer (env, 0);
|
|
|
|
/* See
|
|
|
|
https://gmplib.org/manual/Integer-Import-and-Export.html#index-Export. */
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
order = -1,
|
|
|
|
size = sizeof (emacs_limb_t),
|
|
|
|
endian = 0,
|
|
|
|
nails = 0,
|
|
|
|
numb = 8 * size - nails
|
|
|
|
};
|
|
|
|
size_t count = (mpz_sizeinbase (value, 2) + numb - 1) / numb;
|
|
|
|
if (max_count < count)
|
|
|
|
{
|
|
|
|
memory_full (env);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
emacs_limb_t *magnitude = malloc (count * size);
|
|
|
|
if (magnitude == NULL)
|
|
|
|
{
|
|
|
|
memory_full (env);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
size_t written;
|
|
|
|
mpz_export (magnitude, &written, order, size, endian, nails, value);
|
|
|
|
assert (written == count);
|
|
|
|
assert (count <= PTRDIFF_MAX);
|
|
|
|
emacs_value result = env->make_big_integer (env, mpz_sgn (value),
|
|
|
|
(ptrdiff_t) count, magnitude);
|
|
|
|
free (magnitude);
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
Decouple mod-test.c from Gnulib
mod-test.c should not use Gnulib code, as that creates
unnecessary coupling between Emacs internals and this test module.
Also Gnulib code is compiled without -fPIC whereas mod-test.c
needs -fPIC and recompiling Gnulib with -fPIC would be too painful.
* src/Makefile.in (LIB_NANOSLEEP): New macro.
(LIBES): Use it.
* test/Makefile.in (REPLACE_FREE, FREE_SOURCE_0, FREE_SOURCE_0):
Remove. All uses removed.
(LIB_CLOCK_GETTIME, LIB_NANOSLEEP): New macros.
(MODULE_CFLAGS): Do not -I from lib as that would include Gnulib
modifications to standard .h files (e.g., "#define nanosleep
rpl_nanosleep") and we don’t want the Gnulib replacements.
Instead, for gmp.h (on platforms lacking <gmp.h>) simply '-I.'
with a suitable gmp.h.
(gmp.h): New rule to create a suitable gmp.h.
($(test_module)): Depend on config.h since the code uses config.h.
Depend on gmp.h if we need to create a suitable one.
If compiling mini-gmp.h, compile the original one and not
the Emacs-specific one, to lessen coupling with Emacs internals.
Link with LIB_CLOCK_GETTIME and LIB_NANOSLEEP.
(clean): Remove gmp.h.
* test/src/emacs-module-resources/mod-test.c: Don’t include timespec.h.
All uses of timespec.h APIs changed to use system-supplied APIs.
Change _Static_assert to plain assert, so that we needn’t rely
on Gnulib’s _Static_assert.
(timespec_le) [CLOCK_REALTIME]: New function.
Change use of timespec_cmp changed to use this instead.
(Fmod_test_sleep_until, Fmod_test_nanoseconds):
Define these functions and their Lisp names mod-test-sleep-until
and mod-test-nanoseconds only if CLOCK_REALTIME,
since they now won’t work on platforms lacking CLOCK_REALTIME.
(Fmod_test_nanoseconds): Just use _Static_assert since it
should work on all platforms.
* test/src/emacs-module-tests.el (mod-test-sleep-until)
(mod-test-nanoseconds, mod-test-double):
Skip test if the corresponding functione is not defined.
2022-03-08 18:46:47 -08:00
|
|
|
#ifdef CLOCK_REALTIME
|
2019-04-24 13:41:05 +02:00
|
|
|
static emacs_value
|
|
|
|
Fmod_test_nanoseconds (emacs_env *env, ptrdiff_t nargs, emacs_value *args, void *data) {
|
|
|
|
assert (nargs == 1);
|
|
|
|
struct timespec time = env->extract_time (env, args[0]);
|
Change module interface to no longer use GMP objects directly.
As described in the new comment added to emacs-module.c, using GMP
directly in the module interface has significant downsides: it couples
the module interface directly to the implementation and requires
module authors to link their module against the same GMP library as
Emacs itself, which is often difficult and an unnecessary burden. By
picking a representation for the magnitude that often matches the one
used by GMP, we can avoid overhead when converting from and to GMP in
most cases.
Loading the test module in test/data/emacs-module and evaluating
(dotimes (_ 10000)
(mod-test-double (* 2 most-negative-fixnum)))
under Callgrind shows that on my (GNU/Linux) machine Emacs only spends
10% of the CPU time of mod-test-double in mpz_import and mpz_export
combined, even though that function does little else. (By contrast,
30% is spent in allocate_pseudovector.)
* src/emacs-module.h.in: Don't check EMACS_MODULE_GMP. Don't include
gmp.h. Remove emacs_mpz structure. Instead, define type alias
emacs_limb_t and macro EMACS_LIMB_MAX.
* src/module-env-27.h: Change interface of extract_big_integer and
make_big_integer to take a sign-magnitude representation instead of
mpz_t.
* src/emacs-module.c: Don't check EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T. Add a comment about the chosen
implementation.
(module_extract_big_integer, module_make_big_integer): Reimplement
without using mpz_t in the interface.
* doc/lispref/internals.texi (Module Values): Adapt function
documentation and example. Stop mentioning GMP and EMACS_MODULE_GMP.
* test/data/emacs-module/mod-test.c: Don't define EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T.
(memory_full, extract_big_integer, make_big_integer): New helper
functions, identical to example in the Info documentation.
(Fmod_test_nanoseconds, Fmod_test_double): Adapt to new interface.
2019-11-02 10:54:57 +01:00
|
|
|
mpz_t nanoseconds;
|
2019-04-24 13:41:05 +02:00
|
|
|
assert (LONG_MIN <= time.tv_sec && time.tv_sec <= LONG_MAX);
|
Change module interface to no longer use GMP objects directly.
As described in the new comment added to emacs-module.c, using GMP
directly in the module interface has significant downsides: it couples
the module interface directly to the implementation and requires
module authors to link their module against the same GMP library as
Emacs itself, which is often difficult and an unnecessary burden. By
picking a representation for the magnitude that often matches the one
used by GMP, we can avoid overhead when converting from and to GMP in
most cases.
Loading the test module in test/data/emacs-module and evaluating
(dotimes (_ 10000)
(mod-test-double (* 2 most-negative-fixnum)))
under Callgrind shows that on my (GNU/Linux) machine Emacs only spends
10% of the CPU time of mod-test-double in mpz_import and mpz_export
combined, even though that function does little else. (By contrast,
30% is spent in allocate_pseudovector.)
* src/emacs-module.h.in: Don't check EMACS_MODULE_GMP. Don't include
gmp.h. Remove emacs_mpz structure. Instead, define type alias
emacs_limb_t and macro EMACS_LIMB_MAX.
* src/module-env-27.h: Change interface of extract_big_integer and
make_big_integer to take a sign-magnitude representation instead of
mpz_t.
* src/emacs-module.c: Don't check EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T. Add a comment about the chosen
implementation.
(module_extract_big_integer, module_make_big_integer): Reimplement
without using mpz_t in the interface.
* doc/lispref/internals.texi (Module Values): Adapt function
documentation and example. Stop mentioning GMP and EMACS_MODULE_GMP.
* test/data/emacs-module/mod-test.c: Don't define EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T.
(memory_full, extract_big_integer, make_big_integer): New helper
functions, identical to example in the Info documentation.
(Fmod_test_nanoseconds, Fmod_test_double): Adapt to new interface.
2019-11-02 10:54:57 +01:00
|
|
|
mpz_init_set_si (nanoseconds, time.tv_sec);
|
|
|
|
mpz_mul_ui (nanoseconds, nanoseconds, 1000000000);
|
2019-04-24 13:41:05 +02:00
|
|
|
assert (0 <= time.tv_nsec && time.tv_nsec <= ULONG_MAX);
|
Change module interface to no longer use GMP objects directly.
As described in the new comment added to emacs-module.c, using GMP
directly in the module interface has significant downsides: it couples
the module interface directly to the implementation and requires
module authors to link their module against the same GMP library as
Emacs itself, which is often difficult and an unnecessary burden. By
picking a representation for the magnitude that often matches the one
used by GMP, we can avoid overhead when converting from and to GMP in
most cases.
Loading the test module in test/data/emacs-module and evaluating
(dotimes (_ 10000)
(mod-test-double (* 2 most-negative-fixnum)))
under Callgrind shows that on my (GNU/Linux) machine Emacs only spends
10% of the CPU time of mod-test-double in mpz_import and mpz_export
combined, even though that function does little else. (By contrast,
30% is spent in allocate_pseudovector.)
* src/emacs-module.h.in: Don't check EMACS_MODULE_GMP. Don't include
gmp.h. Remove emacs_mpz structure. Instead, define type alias
emacs_limb_t and macro EMACS_LIMB_MAX.
* src/module-env-27.h: Change interface of extract_big_integer and
make_big_integer to take a sign-magnitude representation instead of
mpz_t.
* src/emacs-module.c: Don't check EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T. Add a comment about the chosen
implementation.
(module_extract_big_integer, module_make_big_integer): Reimplement
without using mpz_t in the interface.
* doc/lispref/internals.texi (Module Values): Adapt function
documentation and example. Stop mentioning GMP and EMACS_MODULE_GMP.
* test/data/emacs-module/mod-test.c: Don't define EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T.
(memory_full, extract_big_integer, make_big_integer): New helper
functions, identical to example in the Info documentation.
(Fmod_test_nanoseconds, Fmod_test_double): Adapt to new interface.
2019-11-02 10:54:57 +01:00
|
|
|
mpz_add_ui (nanoseconds, nanoseconds, time.tv_nsec);
|
|
|
|
emacs_value result = make_big_integer (env, nanoseconds);
|
|
|
|
mpz_clear (nanoseconds);
|
2019-04-24 13:41:05 +02:00
|
|
|
return result;
|
|
|
|
}
|
Decouple mod-test.c from Gnulib
mod-test.c should not use Gnulib code, as that creates
unnecessary coupling between Emacs internals and this test module.
Also Gnulib code is compiled without -fPIC whereas mod-test.c
needs -fPIC and recompiling Gnulib with -fPIC would be too painful.
* src/Makefile.in (LIB_NANOSLEEP): New macro.
(LIBES): Use it.
* test/Makefile.in (REPLACE_FREE, FREE_SOURCE_0, FREE_SOURCE_0):
Remove. All uses removed.
(LIB_CLOCK_GETTIME, LIB_NANOSLEEP): New macros.
(MODULE_CFLAGS): Do not -I from lib as that would include Gnulib
modifications to standard .h files (e.g., "#define nanosleep
rpl_nanosleep") and we don’t want the Gnulib replacements.
Instead, for gmp.h (on platforms lacking <gmp.h>) simply '-I.'
with a suitable gmp.h.
(gmp.h): New rule to create a suitable gmp.h.
($(test_module)): Depend on config.h since the code uses config.h.
Depend on gmp.h if we need to create a suitable one.
If compiling mini-gmp.h, compile the original one and not
the Emacs-specific one, to lessen coupling with Emacs internals.
Link with LIB_CLOCK_GETTIME and LIB_NANOSLEEP.
(clean): Remove gmp.h.
* test/src/emacs-module-resources/mod-test.c: Don’t include timespec.h.
All uses of timespec.h APIs changed to use system-supplied APIs.
Change _Static_assert to plain assert, so that we needn’t rely
on Gnulib’s _Static_assert.
(timespec_le) [CLOCK_REALTIME]: New function.
Change use of timespec_cmp changed to use this instead.
(Fmod_test_sleep_until, Fmod_test_nanoseconds):
Define these functions and their Lisp names mod-test-sleep-until
and mod-test-nanoseconds only if CLOCK_REALTIME,
since they now won’t work on platforms lacking CLOCK_REALTIME.
(Fmod_test_nanoseconds): Just use _Static_assert since it
should work on all platforms.
* test/src/emacs-module-tests.el (mod-test-sleep-until)
(mod-test-nanoseconds, mod-test-double):
Skip test if the corresponding functione is not defined.
2022-03-08 18:46:47 -08:00
|
|
|
#endif
|
2019-04-24 13:41:05 +02:00
|
|
|
|
2019-04-18 22:38:29 +02:00
|
|
|
static emacs_value
|
|
|
|
Fmod_test_double (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
assert (nargs == 1);
|
|
|
|
emacs_value arg = args[0];
|
Change module interface to no longer use GMP objects directly.
As described in the new comment added to emacs-module.c, using GMP
directly in the module interface has significant downsides: it couples
the module interface directly to the implementation and requires
module authors to link their module against the same GMP library as
Emacs itself, which is often difficult and an unnecessary burden. By
picking a representation for the magnitude that often matches the one
used by GMP, we can avoid overhead when converting from and to GMP in
most cases.
Loading the test module in test/data/emacs-module and evaluating
(dotimes (_ 10000)
(mod-test-double (* 2 most-negative-fixnum)))
under Callgrind shows that on my (GNU/Linux) machine Emacs only spends
10% of the CPU time of mod-test-double in mpz_import and mpz_export
combined, even though that function does little else. (By contrast,
30% is spent in allocate_pseudovector.)
* src/emacs-module.h.in: Don't check EMACS_MODULE_GMP. Don't include
gmp.h. Remove emacs_mpz structure. Instead, define type alias
emacs_limb_t and macro EMACS_LIMB_MAX.
* src/module-env-27.h: Change interface of extract_big_integer and
make_big_integer to take a sign-magnitude representation instead of
mpz_t.
* src/emacs-module.c: Don't check EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T. Add a comment about the chosen
implementation.
(module_extract_big_integer, module_make_big_integer): Reimplement
without using mpz_t in the interface.
* doc/lispref/internals.texi (Module Values): Adapt function
documentation and example. Stop mentioning GMP and EMACS_MODULE_GMP.
* test/data/emacs-module/mod-test.c: Don't define EMACS_MODULE_GMP or
EMACS_MODULE_HAVE_MPZ_T.
(memory_full, extract_big_integer, make_big_integer): New helper
functions, identical to example in the Info documentation.
(Fmod_test_nanoseconds, Fmod_test_double): Adapt to new interface.
2019-11-02 10:54:57 +01:00
|
|
|
mpz_t value;
|
|
|
|
mpz_init (value);
|
|
|
|
extract_big_integer (env, arg, value);
|
|
|
|
mpz_mul_ui (value, value, 2);
|
|
|
|
emacs_value result = make_big_integer (env, value);
|
|
|
|
mpz_clear (value);
|
2019-04-18 22:38:29 +02:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2018-02-11 21:38:22 +01:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-03-27 15:43:20 +03:00
|
|
|
static void
|
|
|
|
sleep_for_half_second (void)
|
|
|
|
{
|
|
|
|
/* mingw.org's MinGW has nanosleep, but MinGW64 doesn't. */
|
|
|
|
#ifdef WINDOWSNT
|
|
|
|
Sleep (500);
|
|
|
|
#else
|
Decouple mod-test.c from Gnulib
mod-test.c should not use Gnulib code, as that creates
unnecessary coupling between Emacs internals and this test module.
Also Gnulib code is compiled without -fPIC whereas mod-test.c
needs -fPIC and recompiling Gnulib with -fPIC would be too painful.
* src/Makefile.in (LIB_NANOSLEEP): New macro.
(LIBES): Use it.
* test/Makefile.in (REPLACE_FREE, FREE_SOURCE_0, FREE_SOURCE_0):
Remove. All uses removed.
(LIB_CLOCK_GETTIME, LIB_NANOSLEEP): New macros.
(MODULE_CFLAGS): Do not -I from lib as that would include Gnulib
modifications to standard .h files (e.g., "#define nanosleep
rpl_nanosleep") and we don’t want the Gnulib replacements.
Instead, for gmp.h (on platforms lacking <gmp.h>) simply '-I.'
with a suitable gmp.h.
(gmp.h): New rule to create a suitable gmp.h.
($(test_module)): Depend on config.h since the code uses config.h.
Depend on gmp.h if we need to create a suitable one.
If compiling mini-gmp.h, compile the original one and not
the Emacs-specific one, to lessen coupling with Emacs internals.
Link with LIB_CLOCK_GETTIME and LIB_NANOSLEEP.
(clean): Remove gmp.h.
* test/src/emacs-module-resources/mod-test.c: Don’t include timespec.h.
All uses of timespec.h APIs changed to use system-supplied APIs.
Change _Static_assert to plain assert, so that we needn’t rely
on Gnulib’s _Static_assert.
(timespec_le) [CLOCK_REALTIME]: New function.
Change use of timespec_cmp changed to use this instead.
(Fmod_test_sleep_until, Fmod_test_nanoseconds):
Define these functions and their Lisp names mod-test-sleep-until
and mod-test-nanoseconds only if CLOCK_REALTIME,
since they now won’t work on platforms lacking CLOCK_REALTIME.
(Fmod_test_nanoseconds): Just use _Static_assert since it
should work on all platforms.
* test/src/emacs-module-tests.el (mod-test-sleep-until)
(mod-test-nanoseconds, mod-test-double):
Skip test if the corresponding functione is not defined.
2022-03-08 18:46:47 -08:00
|
|
|
const struct timespec sleep = { .tv_nsec = 500000000 };
|
2020-03-27 15:43:20 +03:00
|
|
|
if (nanosleep (&sleep, NULL) != 0)
|
|
|
|
perror ("nanosleep");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WINDOWSNT
|
|
|
|
static void ALIGN_STACK
|
|
|
|
#else
|
2020-03-26 17:22:25 +01:00
|
|
|
static void *
|
2020-03-27 15:43:20 +03:00
|
|
|
#endif
|
2020-03-26 17:22:25 +01:00
|
|
|
write_to_pipe (void *arg)
|
|
|
|
{
|
|
|
|
/* We sleep a bit to test that writing to a pipe is indeed possible
|
|
|
|
if no environment is active. */
|
2020-03-27 15:43:20 +03:00
|
|
|
sleep_for_half_second ();
|
2020-03-26 17:22:25 +01:00
|
|
|
FILE *stream = arg;
|
2020-03-27 15:43:20 +03:00
|
|
|
/* The string below should be identical to the one we compare with
|
|
|
|
in emacs-module-tests.el:module/async-pipe. */
|
2020-03-26 17:22:25 +01:00
|
|
|
if (fputs ("data from thread", stream) < 0)
|
|
|
|
perror ("fputs");
|
|
|
|
if (fclose (stream) != 0)
|
|
|
|
perror ("close");
|
2020-03-27 15:43:20 +03:00
|
|
|
#ifndef WINDOWSNT
|
2020-03-26 17:22:25 +01:00
|
|
|
return NULL;
|
2020-03-27 15:43:20 +03:00
|
|
|
#endif
|
2020-03-26 17:22:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static emacs_value
|
|
|
|
Fmod_test_async_pipe (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
assert (nargs == 1);
|
|
|
|
int fd = env->open_channel (env, args[0]);
|
|
|
|
if (env->non_local_exit_check (env) != emacs_funcall_exit_return)
|
|
|
|
return NULL;
|
|
|
|
FILE *stream = fdopen (fd, "w");
|
|
|
|
if (stream == NULL)
|
|
|
|
{
|
|
|
|
signal_errno (env, "fdopen");
|
|
|
|
return NULL;
|
|
|
|
}
|
2020-03-27 15:43:20 +03:00
|
|
|
#ifdef WINDOWSNT
|
|
|
|
uintptr_t thd = _beginthread (write_to_pipe, 0, stream);
|
|
|
|
int error = (thd == (uintptr_t)-1L) ? errno : 0;
|
|
|
|
#else /* !WINDOWSNT */
|
2020-03-26 17:22:25 +01:00
|
|
|
pthread_t thread;
|
|
|
|
int error
|
|
|
|
= pthread_create (&thread, NULL, write_to_pipe, stream);
|
2020-03-27 15:43:20 +03:00
|
|
|
#endif
|
2020-03-26 17:22:25 +01:00
|
|
|
if (error != 0)
|
|
|
|
{
|
2020-03-27 15:43:20 +03:00
|
|
|
signal_system_error (env, error, "thread create");
|
2020-03-26 17:22:25 +01:00
|
|
|
if (fclose (stream) != 0)
|
|
|
|
perror ("fclose");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return env->intern (env, "nil");
|
|
|
|
}
|
|
|
|
|
2020-09-13 20:21:41 +02:00
|
|
|
static emacs_value
|
|
|
|
Fmod_test_identity (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
assert (nargs == 1);
|
|
|
|
return args[0];
|
|
|
|
}
|
|
|
|
|
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.
2020-11-27 19:08:55 +01:00
|
|
|
static emacs_value
|
|
|
|
Fmod_test_funcall (emacs_env *env, ptrdiff_t nargs, emacs_value *args,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
assert (0 < nargs);
|
|
|
|
return env->funcall (env, args[0], nargs - 1, args + 1);
|
|
|
|
}
|
|
|
|
|
2020-12-12 23:21:18 +01:00
|
|
|
static emacs_value
|
|
|
|
Fmod_test_make_string (emacs_env *env, ptrdiff_t nargs,
|
|
|
|
emacs_value *args, void *data)
|
|
|
|
{
|
|
|
|
assert (nargs == 2);
|
|
|
|
intmax_t length_arg = env->extract_integer (env, args[0]);
|
|
|
|
if (env->non_local_exit_check (env) != emacs_funcall_exit_return)
|
|
|
|
return args[0];
|
|
|
|
if (length_arg < 0 || SIZE_MAX < length_arg)
|
|
|
|
{
|
|
|
|
signal_error (env, "Invalid string length");
|
|
|
|
return args[0];
|
|
|
|
}
|
|
|
|
size_t length = (size_t) length_arg;
|
|
|
|
bool multibyte = env->is_not_nil (env, args[1]);
|
|
|
|
char *buffer = length == 0 ? NULL : malloc (length);
|
|
|
|
if (buffer == NULL && length != 0)
|
|
|
|
{
|
|
|
|
memory_full (env);
|
|
|
|
return args[0];
|
|
|
|
}
|
|
|
|
memset (buffer, 'a', length);
|
|
|
|
emacs_value ret = multibyte ? env->make_string (env, buffer, length)
|
|
|
|
: env->make_unibyte_string (env, buffer, length);
|
|
|
|
free (buffer);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Lisp utilities for easier readability (simple wrappers). */
|
2015-11-16 01:00:25 +01:00
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Provide FEATURE to Emacs. */
|
|
|
|
static void
|
|
|
|
provide (emacs_env *env, const char *feature)
|
2015-11-16 01:00:25 +01:00
|
|
|
{
|
|
|
|
emacs_value Qfeat = env->intern (env, feature);
|
|
|
|
emacs_value Qprovide = env->intern (env, "provide");
|
|
|
|
emacs_value args[] = { Qfeat };
|
|
|
|
|
|
|
|
env->funcall (env, Qprovide, 1, args);
|
|
|
|
}
|
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Bind NAME to FUN. */
|
|
|
|
static void
|
|
|
|
bind_function (emacs_env *env, const char *name, emacs_value Sfun)
|
2015-11-16 01:00:25 +01:00
|
|
|
{
|
2018-02-02 20:40:10 +01:00
|
|
|
emacs_value Qdefalias = env->intern (env, "defalias");
|
2015-11-16 01:00:25 +01:00
|
|
|
emacs_value Qsym = env->intern (env, name);
|
|
|
|
emacs_value args[] = { Qsym, Sfun };
|
|
|
|
|
2018-02-02 20:40:10 +01:00
|
|
|
env->funcall (env, Qdefalias, 2, args);
|
2015-11-16 01:00:25 +01:00
|
|
|
}
|
|
|
|
|
2015-11-19 11:31:45 -08:00
|
|
|
/* Module init function. */
|
|
|
|
int
|
|
|
|
emacs_module_init (struct emacs_runtime *ert)
|
2015-11-16 01:00:25 +01:00
|
|
|
{
|
Decouple mod-test.c from Gnulib
mod-test.c should not use Gnulib code, as that creates
unnecessary coupling between Emacs internals and this test module.
Also Gnulib code is compiled without -fPIC whereas mod-test.c
needs -fPIC and recompiling Gnulib with -fPIC would be too painful.
* src/Makefile.in (LIB_NANOSLEEP): New macro.
(LIBES): Use it.
* test/Makefile.in (REPLACE_FREE, FREE_SOURCE_0, FREE_SOURCE_0):
Remove. All uses removed.
(LIB_CLOCK_GETTIME, LIB_NANOSLEEP): New macros.
(MODULE_CFLAGS): Do not -I from lib as that would include Gnulib
modifications to standard .h files (e.g., "#define nanosleep
rpl_nanosleep") and we don’t want the Gnulib replacements.
Instead, for gmp.h (on platforms lacking <gmp.h>) simply '-I.'
with a suitable gmp.h.
(gmp.h): New rule to create a suitable gmp.h.
($(test_module)): Depend on config.h since the code uses config.h.
Depend on gmp.h if we need to create a suitable one.
If compiling mini-gmp.h, compile the original one and not
the Emacs-specific one, to lessen coupling with Emacs internals.
Link with LIB_CLOCK_GETTIME and LIB_NANOSLEEP.
(clean): Remove gmp.h.
* test/src/emacs-module-resources/mod-test.c: Don’t include timespec.h.
All uses of timespec.h APIs changed to use system-supplied APIs.
Change _Static_assert to plain assert, so that we needn’t rely
on Gnulib’s _Static_assert.
(timespec_le) [CLOCK_REALTIME]: New function.
Change use of timespec_cmp changed to use this instead.
(Fmod_test_sleep_until, Fmod_test_nanoseconds):
Define these functions and their Lisp names mod-test-sleep-until
and mod-test-nanoseconds only if CLOCK_REALTIME,
since they now won’t work on platforms lacking CLOCK_REALTIME.
(Fmod_test_nanoseconds): Just use _Static_assert since it
should work on all platforms.
* test/src/emacs-module-tests.el (mod-test-sleep-until)
(mod-test-nanoseconds, mod-test-double):
Skip test if the corresponding functione is not defined.
2022-03-08 18:46:47 -08:00
|
|
|
/* These smoke tests don't use _Static_assert because too many
|
|
|
|
compilers lack support for _Static_assert. */
|
|
|
|
assert (0 < EMACS_LIMB_MAX);
|
|
|
|
assert (1000000000 <= ULONG_MAX);
|
|
|
|
|
2019-04-24 10:22:18 +02:00
|
|
|
/* Check that EMACS_MAJOR_VERSION is defined and an integral
|
|
|
|
constant. */
|
|
|
|
char dummy[EMACS_MAJOR_VERSION];
|
|
|
|
assert (27 <= sizeof dummy);
|
|
|
|
|
2017-06-12 16:28:16 +02:00
|
|
|
if (ert->size < sizeof *ert)
|
2017-06-12 23:45:18 +02:00
|
|
|
{
|
2018-01-19 11:20:12 +02:00
|
|
|
fprintf (stderr, "Runtime size of runtime structure (%"pT" bytes) "
|
|
|
|
"smaller than compile-time size (%"pZ" bytes)",
|
|
|
|
(T_TYPE) ert->size, (Z_TYPE) sizeof (*ert));
|
2017-06-12 23:45:18 +02:00
|
|
|
return 1;
|
|
|
|
}
|
2017-06-12 16:28:16 +02:00
|
|
|
|
2015-11-16 01:00:25 +01:00
|
|
|
emacs_env *env = ert->get_environment (ert);
|
|
|
|
|
2017-06-12 23:35:23 +02:00
|
|
|
if (env->size < sizeof *env)
|
2017-06-12 23:45:18 +02:00
|
|
|
{
|
2018-01-19 11:20:12 +02:00
|
|
|
fprintf (stderr, "Runtime size of environment structure (%"pT" bytes) "
|
|
|
|
"smaller than compile-time size (%"pZ" bytes)",
|
|
|
|
(T_TYPE) env->size, (Z_TYPE) sizeof (*env));
|
2017-06-12 23:45:18 +02:00
|
|
|
return 2;
|
|
|
|
}
|
2017-06-12 16:28:16 +02:00
|
|
|
|
2015-11-16 01:00:25 +01:00
|
|
|
#define DEFUN(lsym, csym, amin, amax, doc, data) \
|
2015-11-19 11:31:45 -08:00
|
|
|
bind_function (env, lsym, \
|
|
|
|
env->make_function (env, amin, amax, csym, doc, data))
|
2015-11-16 01:00:25 +01:00
|
|
|
|
|
|
|
DEFUN ("mod-test-return-t", Fmod_test_return_t, 1, 1, NULL, NULL);
|
2020-01-05 16:05:14 +01:00
|
|
|
DEFUN ("mod-test-sum", Fmod_test_sum, 2, 2, "Return A + B\n\n(fn a b)",
|
|
|
|
(void *) (uintptr_t) 0x1234);
|
2015-11-16 01:00:25 +01:00
|
|
|
DEFUN ("mod-test-signal", Fmod_test_signal, 0, 0, NULL, NULL);
|
|
|
|
DEFUN ("mod-test-throw", Fmod_test_throw, 0, 0, NULL, NULL);
|
2015-11-19 11:31:45 -08:00
|
|
|
DEFUN ("mod-test-non-local-exit-funcall", Fmod_test_non_local_exit_funcall,
|
|
|
|
1, 1, NULL, NULL);
|
2015-11-16 01:00:25 +01:00
|
|
|
DEFUN ("mod-test-globref-make", Fmod_test_globref_make, 0, 0, NULL, NULL);
|
2018-08-19 21:31:01 +01:00
|
|
|
DEFUN ("mod-test-globref-free", Fmod_test_globref_free, 4, 4, NULL, NULL);
|
2020-07-25 23:23:19 +02:00
|
|
|
DEFUN ("mod-test-globref-invalid-free", Fmod_test_globref_invalid_free, 0, 0,
|
|
|
|
NULL, NULL);
|
2020-07-26 22:54:33 +02:00
|
|
|
DEFUN ("mod-test-globref-reordered", Fmod_test_globref_reordered, 0, 0, NULL,
|
|
|
|
NULL);
|
2015-11-16 01:00:25 +01:00
|
|
|
DEFUN ("mod-test-string-a-to-b", Fmod_test_string_a_to_b, 1, 1, NULL, NULL);
|
2020-10-13 06:51:06 +02:00
|
|
|
DEFUN ("mod-test-return-unibyte", Fmod_test_return_unibyte, 0, 0, NULL, NULL);
|
2015-11-16 01:00:25 +01:00
|
|
|
DEFUN ("mod-test-userptr-make", Fmod_test_userptr_make, 1, 1, NULL, NULL);
|
|
|
|
DEFUN ("mod-test-userptr-get", Fmod_test_userptr_get, 1, 1, NULL, NULL);
|
|
|
|
DEFUN ("mod-test-vector-fill", Fmod_test_vector_fill, 2, 2, NULL, NULL);
|
|
|
|
DEFUN ("mod-test-vector-eq", Fmod_test_vector_eq, 2, 2, NULL, NULL);
|
Implement module assertions for users
Add a new command-line option '-module-assertions' that users can
enable developing or debugging a module. If this option is present,
Emacs performs additional checks to verify that modules fulfill their
requirements. These checks are expensive and crash Emacs if modules
are invalid, so disable them by default.
This is a command-line option instead of an ordinary variable because
changing it while Emacs is running would cause data structure
imbalances.
* src/emacs.c (main): New command line option '-module-assertions'.
* src/emacs-module.c (module_assert_main_thread)
(module_assert_runtime, module_assert_env, module_assert_value):
New functions to assert module requirements.
(syms_of_module): New uninterned variable 'module-runtimes'.
(init_module_assertions, in_main_thread, module_abort): New helper
functions.
(initialize_environment): Initialize value list. If assertions are
enabled, use a heap-allocated environment object.
(finalize_environment): Add assertion that environment list is never
empty.
(finalize_runtime_unwind): Pop module runtime object stack.
(value_to_lisp): Assert that the value is valid.
(lisp_to_value): Record new value if assertions are enabled.
(mark_modules): Mark allocated object list.
(MODULE_FUNCTION_BEGIN_NO_CATCH)
(module_non_local_exit_check, module_non_local_exit_clear)
(module_non_local_exit_get, module_non_local_exit_signal)
(module_non_local_exit_throw): Assert thread and environment.
(module_get_environment): Assert thread and runtime.
(module_make_function, module_funcall, module_intern)
(module_funcall, module_make_integer, module_make_float)
(module_make_string, module_make_user_ptr, module_vec_get)
(funcall_module, Fmodule_load): Adapt callers.
(module_make_global_ref): If assertions are enabled, use the global
environment to store global values.
(module_free_global_ref): Remove value from global value list.
* test/Makefile.in (EMACSOPT): Enable module assertions when testing
modules.
* test/data/emacs-module/mod-test.c (Fmod_test_invalid_store)
(Fmod_test_invalid_load): New functions to test module assertions.
(emacs_module_init): Bind the new functions.
* test/src/emacs-module-tests.el (mod-test-emacs): New constant for
the Emacs binary file.
(mod-test-file): New constant for the test module file name.
(module--test-assertions): New unit test.
2017-06-05 13:29:14 +02:00
|
|
|
DEFUN ("mod-test-invalid-store", Fmod_test_invalid_store, 0, 0, NULL, NULL);
|
2020-07-25 23:04:05 +02:00
|
|
|
DEFUN ("mod-test-invalid-store-copy", Fmod_test_invalid_store_copy, 0, 0,
|
|
|
|
NULL, NULL);
|
Implement module assertions for users
Add a new command-line option '-module-assertions' that users can
enable developing or debugging a module. If this option is present,
Emacs performs additional checks to verify that modules fulfill their
requirements. These checks are expensive and crash Emacs if modules
are invalid, so disable them by default.
This is a command-line option instead of an ordinary variable because
changing it while Emacs is running would cause data structure
imbalances.
* src/emacs.c (main): New command line option '-module-assertions'.
* src/emacs-module.c (module_assert_main_thread)
(module_assert_runtime, module_assert_env, module_assert_value):
New functions to assert module requirements.
(syms_of_module): New uninterned variable 'module-runtimes'.
(init_module_assertions, in_main_thread, module_abort): New helper
functions.
(initialize_environment): Initialize value list. If assertions are
enabled, use a heap-allocated environment object.
(finalize_environment): Add assertion that environment list is never
empty.
(finalize_runtime_unwind): Pop module runtime object stack.
(value_to_lisp): Assert that the value is valid.
(lisp_to_value): Record new value if assertions are enabled.
(mark_modules): Mark allocated object list.
(MODULE_FUNCTION_BEGIN_NO_CATCH)
(module_non_local_exit_check, module_non_local_exit_clear)
(module_non_local_exit_get, module_non_local_exit_signal)
(module_non_local_exit_throw): Assert thread and environment.
(module_get_environment): Assert thread and runtime.
(module_make_function, module_funcall, module_intern)
(module_funcall, module_make_integer, module_make_float)
(module_make_string, module_make_user_ptr, module_vec_get)
(funcall_module, Fmodule_load): Adapt callers.
(module_make_global_ref): If assertions are enabled, use the global
environment to store global values.
(module_free_global_ref): Remove value from global value list.
* test/Makefile.in (EMACSOPT): Enable module assertions when testing
modules.
* test/data/emacs-module/mod-test.c (Fmod_test_invalid_store)
(Fmod_test_invalid_load): New functions to test module assertions.
(emacs_module_init): Bind the new functions.
* test/src/emacs-module-tests.el (mod-test-emacs): New constant for
the Emacs binary file.
(mod-test-file): New constant for the test module file name.
(module--test-assertions): New unit test.
2017-06-05 13:29:14 +02:00
|
|
|
DEFUN ("mod-test-invalid-load", Fmod_test_invalid_load, 0, 0, NULL, NULL);
|
2017-07-04 22:50:46 +02:00
|
|
|
DEFUN ("mod-test-invalid-finalizer", Fmod_test_invalid_finalizer, 0, 0,
|
|
|
|
NULL, NULL);
|
Decouple mod-test.c from Gnulib
mod-test.c should not use Gnulib code, as that creates
unnecessary coupling between Emacs internals and this test module.
Also Gnulib code is compiled without -fPIC whereas mod-test.c
needs -fPIC and recompiling Gnulib with -fPIC would be too painful.
* src/Makefile.in (LIB_NANOSLEEP): New macro.
(LIBES): Use it.
* test/Makefile.in (REPLACE_FREE, FREE_SOURCE_0, FREE_SOURCE_0):
Remove. All uses removed.
(LIB_CLOCK_GETTIME, LIB_NANOSLEEP): New macros.
(MODULE_CFLAGS): Do not -I from lib as that would include Gnulib
modifications to standard .h files (e.g., "#define nanosleep
rpl_nanosleep") and we don’t want the Gnulib replacements.
Instead, for gmp.h (on platforms lacking <gmp.h>) simply '-I.'
with a suitable gmp.h.
(gmp.h): New rule to create a suitable gmp.h.
($(test_module)): Depend on config.h since the code uses config.h.
Depend on gmp.h if we need to create a suitable one.
If compiling mini-gmp.h, compile the original one and not
the Emacs-specific one, to lessen coupling with Emacs internals.
Link with LIB_CLOCK_GETTIME and LIB_NANOSLEEP.
(clean): Remove gmp.h.
* test/src/emacs-module-resources/mod-test.c: Don’t include timespec.h.
All uses of timespec.h APIs changed to use system-supplied APIs.
Change _Static_assert to plain assert, so that we needn’t rely
on Gnulib’s _Static_assert.
(timespec_le) [CLOCK_REALTIME]: New function.
Change use of timespec_cmp changed to use this instead.
(Fmod_test_sleep_until, Fmod_test_nanoseconds):
Define these functions and their Lisp names mod-test-sleep-until
and mod-test-nanoseconds only if CLOCK_REALTIME,
since they now won’t work on platforms lacking CLOCK_REALTIME.
(Fmod_test_nanoseconds): Just use _Static_assert since it
should work on all platforms.
* test/src/emacs-module-tests.el (mod-test-sleep-until)
(mod-test-nanoseconds, mod-test-double):
Skip test if the corresponding functione is not defined.
2022-03-08 18:46:47 -08:00
|
|
|
#ifdef CLOCK_REALTIME
|
2019-01-02 22:04:56 +01:00
|
|
|
DEFUN ("mod-test-sleep-until", Fmod_test_sleep_until, 2, 2, NULL, NULL);
|
Decouple mod-test.c from Gnulib
mod-test.c should not use Gnulib code, as that creates
unnecessary coupling between Emacs internals and this test module.
Also Gnulib code is compiled without -fPIC whereas mod-test.c
needs -fPIC and recompiling Gnulib with -fPIC would be too painful.
* src/Makefile.in (LIB_NANOSLEEP): New macro.
(LIBES): Use it.
* test/Makefile.in (REPLACE_FREE, FREE_SOURCE_0, FREE_SOURCE_0):
Remove. All uses removed.
(LIB_CLOCK_GETTIME, LIB_NANOSLEEP): New macros.
(MODULE_CFLAGS): Do not -I from lib as that would include Gnulib
modifications to standard .h files (e.g., "#define nanosleep
rpl_nanosleep") and we don’t want the Gnulib replacements.
Instead, for gmp.h (on platforms lacking <gmp.h>) simply '-I.'
with a suitable gmp.h.
(gmp.h): New rule to create a suitable gmp.h.
($(test_module)): Depend on config.h since the code uses config.h.
Depend on gmp.h if we need to create a suitable one.
If compiling mini-gmp.h, compile the original one and not
the Emacs-specific one, to lessen coupling with Emacs internals.
Link with LIB_CLOCK_GETTIME and LIB_NANOSLEEP.
(clean): Remove gmp.h.
* test/src/emacs-module-resources/mod-test.c: Don’t include timespec.h.
All uses of timespec.h APIs changed to use system-supplied APIs.
Change _Static_assert to plain assert, so that we needn’t rely
on Gnulib’s _Static_assert.
(timespec_le) [CLOCK_REALTIME]: New function.
Change use of timespec_cmp changed to use this instead.
(Fmod_test_sleep_until, Fmod_test_nanoseconds):
Define these functions and their Lisp names mod-test-sleep-until
and mod-test-nanoseconds only if CLOCK_REALTIME,
since they now won’t work on platforms lacking CLOCK_REALTIME.
(Fmod_test_nanoseconds): Just use _Static_assert since it
should work on all platforms.
* test/src/emacs-module-tests.el (mod-test-sleep-until)
(mod-test-nanoseconds, mod-test-double):
Skip test if the corresponding functione is not defined.
2022-03-08 18:46:47 -08:00
|
|
|
#endif
|
2019-04-18 17:42:45 +02:00
|
|
|
DEFUN ("mod-test-add-nanosecond", Fmod_test_add_nanosecond, 1, 1, NULL, NULL);
|
Decouple mod-test.c from Gnulib
mod-test.c should not use Gnulib code, as that creates
unnecessary coupling between Emacs internals and this test module.
Also Gnulib code is compiled without -fPIC whereas mod-test.c
needs -fPIC and recompiling Gnulib with -fPIC would be too painful.
* src/Makefile.in (LIB_NANOSLEEP): New macro.
(LIBES): Use it.
* test/Makefile.in (REPLACE_FREE, FREE_SOURCE_0, FREE_SOURCE_0):
Remove. All uses removed.
(LIB_CLOCK_GETTIME, LIB_NANOSLEEP): New macros.
(MODULE_CFLAGS): Do not -I from lib as that would include Gnulib
modifications to standard .h files (e.g., "#define nanosleep
rpl_nanosleep") and we don’t want the Gnulib replacements.
Instead, for gmp.h (on platforms lacking <gmp.h>) simply '-I.'
with a suitable gmp.h.
(gmp.h): New rule to create a suitable gmp.h.
($(test_module)): Depend on config.h since the code uses config.h.
Depend on gmp.h if we need to create a suitable one.
If compiling mini-gmp.h, compile the original one and not
the Emacs-specific one, to lessen coupling with Emacs internals.
Link with LIB_CLOCK_GETTIME and LIB_NANOSLEEP.
(clean): Remove gmp.h.
* test/src/emacs-module-resources/mod-test.c: Don’t include timespec.h.
All uses of timespec.h APIs changed to use system-supplied APIs.
Change _Static_assert to plain assert, so that we needn’t rely
on Gnulib’s _Static_assert.
(timespec_le) [CLOCK_REALTIME]: New function.
Change use of timespec_cmp changed to use this instead.
(Fmod_test_sleep_until, Fmod_test_nanoseconds):
Define these functions and their Lisp names mod-test-sleep-until
and mod-test-nanoseconds only if CLOCK_REALTIME,
since they now won’t work on platforms lacking CLOCK_REALTIME.
(Fmod_test_nanoseconds): Just use _Static_assert since it
should work on all platforms.
* test/src/emacs-module-tests.el (mod-test-sleep-until)
(mod-test-nanoseconds, mod-test-double):
Skip test if the corresponding functione is not defined.
2022-03-08 18:46:47 -08:00
|
|
|
#ifdef CLOCK_REALTIME
|
2019-04-24 13:41:05 +02:00
|
|
|
DEFUN ("mod-test-nanoseconds", Fmod_test_nanoseconds, 1, 1, NULL, NULL);
|
Decouple mod-test.c from Gnulib
mod-test.c should not use Gnulib code, as that creates
unnecessary coupling between Emacs internals and this test module.
Also Gnulib code is compiled without -fPIC whereas mod-test.c
needs -fPIC and recompiling Gnulib with -fPIC would be too painful.
* src/Makefile.in (LIB_NANOSLEEP): New macro.
(LIBES): Use it.
* test/Makefile.in (REPLACE_FREE, FREE_SOURCE_0, FREE_SOURCE_0):
Remove. All uses removed.
(LIB_CLOCK_GETTIME, LIB_NANOSLEEP): New macros.
(MODULE_CFLAGS): Do not -I from lib as that would include Gnulib
modifications to standard .h files (e.g., "#define nanosleep
rpl_nanosleep") and we don’t want the Gnulib replacements.
Instead, for gmp.h (on platforms lacking <gmp.h>) simply '-I.'
with a suitable gmp.h.
(gmp.h): New rule to create a suitable gmp.h.
($(test_module)): Depend on config.h since the code uses config.h.
Depend on gmp.h if we need to create a suitable one.
If compiling mini-gmp.h, compile the original one and not
the Emacs-specific one, to lessen coupling with Emacs internals.
Link with LIB_CLOCK_GETTIME and LIB_NANOSLEEP.
(clean): Remove gmp.h.
* test/src/emacs-module-resources/mod-test.c: Don’t include timespec.h.
All uses of timespec.h APIs changed to use system-supplied APIs.
Change _Static_assert to plain assert, so that we needn’t rely
on Gnulib’s _Static_assert.
(timespec_le) [CLOCK_REALTIME]: New function.
Change use of timespec_cmp changed to use this instead.
(Fmod_test_sleep_until, Fmod_test_nanoseconds):
Define these functions and their Lisp names mod-test-sleep-until
and mod-test-nanoseconds only if CLOCK_REALTIME,
since they now won’t work on platforms lacking CLOCK_REALTIME.
(Fmod_test_nanoseconds): Just use _Static_assert since it
should work on all platforms.
* test/src/emacs-module-tests.el (mod-test-sleep-until)
(mod-test-nanoseconds, mod-test-double):
Skip test if the corresponding functione is not defined.
2022-03-08 18:46:47 -08:00
|
|
|
#endif
|
2019-04-18 22:38:29 +02:00
|
|
|
DEFUN ("mod-test-double", Fmod_test_double, 1, 1, NULL, NULL);
|
2018-02-11 21:38:22 +01:00
|
|
|
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);
|
2020-03-26 17:22:25 +01:00
|
|
|
DEFUN ("mod-test-async-pipe", Fmod_test_async_pipe, 1, 1, NULL, NULL);
|
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.
2020-11-27 19:08:55 +01:00
|
|
|
DEFUN ("mod-test-funcall", Fmod_test_funcall, 1, emacs_variadic_function,
|
|
|
|
NULL, NULL);
|
2020-12-12 23:21:18 +01:00
|
|
|
DEFUN ("mod-test-make-string", Fmod_test_make_string, 2, 2, NULL, NULL);
|
2015-11-16 01:00:25 +01:00
|
|
|
|
|
|
|
#undef DEFUN
|
|
|
|
|
2020-09-13 20:21:41 +02:00
|
|
|
emacs_value constant_fn
|
|
|
|
= env->make_function (env, 0, 0, Fmod_test_return_t, NULL, NULL);
|
|
|
|
env->make_interactive (env, constant_fn, env->intern (env, "nil"));
|
|
|
|
bind_function (env, "mod-test-return-t-int", constant_fn);
|
|
|
|
|
|
|
|
emacs_value identity_fn
|
|
|
|
= env->make_function (env, 1, 1, Fmod_test_identity, NULL, NULL);
|
|
|
|
const char *interactive_spec = "i";
|
|
|
|
env->make_interactive (env, identity_fn,
|
|
|
|
env->make_string (env, interactive_spec,
|
|
|
|
strlen (interactive_spec)));
|
|
|
|
bind_function (env, "mod-test-identity", identity_fn);
|
|
|
|
|
2020-11-29 21:13:02 +01:00
|
|
|
/* We allocate lots of values to trigger bugs in the frame allocator during
|
|
|
|
initialization. */
|
|
|
|
int count = 10000; /* larger than value_frame_size in emacs-module.c */
|
|
|
|
for (int i = 0; i < count; ++i)
|
|
|
|
env->make_integer (env, i);
|
|
|
|
|
2015-11-16 01:00:25 +01:00
|
|
|
provide (env, "mod-test");
|
|
|
|
return 0;
|
|
|
|
}
|