From 6e66d1f90a078099911c52b5ed00b7385d095957 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Tue, 8 Mar 2022 18:46:47 -0800 Subject: [PATCH] Decouple mod-test.c from Gnulib MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 ) 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. --- src/Makefile.in | 3 +- test/Makefile.in | 22 ++++++------ test/src/emacs-module-resources/mod-test.c | 42 ++++++++++++++-------- test/src/emacs-module-tests.el | 3 ++ 4 files changed, 44 insertions(+), 26 deletions(-) diff --git a/src/Makefile.in b/src/Makefile.in index 3353fb16d79..2b7c4bb316c 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -146,6 +146,7 @@ M17N_FLT_LIBS = @M17N_FLT_LIBS@ LIB_ACL=@LIB_ACL@ LIB_CLOCK_GETTIME=@LIB_CLOCK_GETTIME@ LIB_EACCESS=@LIB_EACCESS@ +LIB_NANOSLEEP=@LIB_NANOSLEEP@ LIB_TIMER_TIME=@LIB_TIMER_TIME@ DBUS_CFLAGS = @DBUS_CFLAGS@ @@ -548,7 +549,7 @@ lisp = $(addprefix ${lispsource}/,${shortlisp}) LIBES = $(LIBS) $(W32_LIBS) $(LIBS_GNUSTEP) $(PGTK_LIBS) $(LIBX_BASE) $(LIBIMAGE) \ $(LIBX_OTHER) $(LIBSOUND) \ $(RSVG_LIBS) $(IMAGEMAGICK_LIBS) $(LIB_ACL) $(LIB_CLOCK_GETTIME) \ - $(WEBKIT_LIBS) \ + $(LIB_NANOSLEEP) $(WEBKIT_LIBS) \ $(LIB_EACCESS) $(LIB_TIMER_TIME) $(DBUS_LIBS) \ $(LIB_EXECINFO) $(XRANDR_LIBS) $(XINERAMA_LIBS) $(XFIXES_LIBS) \ $(XDBE_LIBS) $(XSYNC_LIBS) \ diff --git a/test/Makefile.in b/test/Makefile.in index 79d3dcf92f8..3b6e116e65f 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -49,8 +49,6 @@ SEPCHAR = @SEPCHAR@ HAVE_NATIVE_COMP = @HAVE_NATIVE_COMP@ -REPLACE_FREE = @REPLACE_FREE@ - -include ${top_builddir}/src/verbose.mk # We never change directory before running Emacs, so a relative file @@ -265,27 +263,29 @@ endif GMP_H = @GMP_H@ LIBGMP = @LIBGMP@ +LIB_CLOCK_GETTIME = @LIB_CLOCK_GETTIME@ +LIB_NANOSLEEP = @LIB_NANOSLEEP@ -MODULE_CFLAGS = -I../src -I$(srcdir)/../src -I../lib -I$(srcdir)/../lib \ +MODULE_CFLAGS = $(and $(GMP_H),-I.) -I../src -I$(srcdir)/../src \ $(FPIC_CFLAGS) $(PROFILING_CFLAGS) \ $(WARN_CFLAGS) $(WERROR_CFLAGS) $(CFLAGS) +gmp.h: + echo '#include "$(srcdir)/../lib/mini-gmp.h"' >$@ + test_module = $(test_module_dir)/mod-test${SO} src/emacs-module-tests.log src/emacs-module-tests.elc: $(test_module) -FREE_SOURCE_0 = -FREE_SOURCE_1 = $(srcdir)/../lib/free.c - # In the compilation command, we can't use any object or archive file # as source because those are not compiled with -fPIC. Therefore we # use only source files. -$(test_module): $(test_module:${SO}=.c) ../src/emacs-module.h +$(test_module): $(test_module:${SO}=.c) ../src/emacs-module.h \ + ../src/config.h $(and $(GMP_H),gmp.h) $(AM_V_CCLD)${MKDIR_P} $(dir $@) $(AM_V_at)$(CC) -shared $(CPPFLAGS) $(MODULE_CFLAGS) $(LDFLAGS) \ -o $@ $< $(LIBGMP) \ - $(and $(GMP_H),$(srcdir)/../lib/mini-gmp-gnulib.c) \ - $(FREE_SOURCE_$(REPLACE_FREE)) \ - ../lib/libgnu.a + $(and $(GMP_H),$(srcdir)/../lib/mini-gmp.c) \ + $(LIB_CLOCK_GETTIME) $(LIB_NANOSLEEP) endif src/emacs-tests.log: ../lib-src/seccomp-filter.c @@ -345,7 +345,7 @@ clean: find . '(' -name '*.xml' -a ! -path '*resources*' ')' $(FIND_DELETE) rm -f ${srcdir}/lisp/gnus/mml-sec-resources/random_seed rm -f $(test_module_dir)/*.o $(test_module_dir)/*.so \ - $(test_module_dir)/*.dll + $(test_module_dir)/*.dll gmp.h bootstrap-clean: clean find $(srcdir) -name '*.elc' $(FIND_DELETE) diff --git a/test/src/emacs-module-resources/mod-test.c b/test/src/emacs-module-resources/mod-test.c index 015c1efd978..187af821c22 100644 --- a/test/src/emacs-module-resources/mod-test.c +++ b/test/src/emacs-module-resources/mod-test.c @@ -47,8 +47,6 @@ uintptr_t _beginthread (void (__cdecl *)(void *), unsigned, void *); #include #include -#include "timespec.h" - int plugin_is_GPL_compatible; #if INTPTR_MAX <= 0 @@ -74,9 +72,6 @@ int plugin_is_GPL_compatible; # error "INTPTR_MAX too large" #endif -/* Smoke test to verify that EMACS_LIMB_MAX is defined. */ -_Static_assert (0 < EMACS_LIMB_MAX, "EMACS_LIMB_MAX missing or incorrect"); - /* Always return symbol 't'. */ static emacs_value Fmod_test_return_t (emacs_env *env, ptrdiff_t nargs, emacs_value args[], @@ -422,6 +417,16 @@ signal_errno (emacs_env *env, const char *function) signal_system_error (env, errno, function); } +#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)); +} + /* A long-running operation that occasionally calls `should_quit' or `process_input'. */ @@ -434,11 +439,13 @@ Fmod_test_sleep_until (emacs_env *env, ptrdiff_t nargs, emacs_value *args, if (env->non_local_exit_check (env)) return NULL; const bool process_input = env->is_not_nil (env, args[1]); - const struct timespec amount = make_timespec(0, 10000000); + const struct timespec amount = { .tv_nsec = 10000000 }; while (true) { - const struct timespec now = current_timespec (); - if (timespec_cmp (now, until) >= 0) + struct timespec now; + if (clock_gettime (CLOCK_REALTIME, &now) != 0) + return NULL; + if (timespec_le (until, now)) break; if (nanosleep (&amount, NULL) && errno != EINTR) { @@ -452,6 +459,7 @@ Fmod_test_sleep_until (emacs_env *env, ptrdiff_t nargs, emacs_value *args, } return env->intern (env, "finished"); } +#endif static emacs_value Fmod_test_add_nanosecond (emacs_env *env, ptrdiff_t nargs, emacs_value *args, @@ -553,6 +561,7 @@ make_big_integer (emacs_env *env, const mpz_t value) return result; } +#ifdef CLOCK_REALTIME static emacs_value Fmod_test_nanoseconds (emacs_env *env, ptrdiff_t nargs, emacs_value *args, void *data) { assert (nargs == 1); @@ -560,11 +569,6 @@ Fmod_test_nanoseconds (emacs_env *env, ptrdiff_t nargs, emacs_value *args, void mpz_t nanoseconds; assert (LONG_MIN <= time.tv_sec && time.tv_sec <= LONG_MAX); mpz_init_set_si (nanoseconds, time.tv_sec); -#ifdef __MINGW32__ - _Static_assert (1000000000 <= ULONG_MAX, "unsupported architecture"); -#else - static_assert (1000000000 <= ULONG_MAX, "unsupported architecture"); -#endif mpz_mul_ui (nanoseconds, nanoseconds, 1000000000); assert (0 <= time.tv_nsec && time.tv_nsec <= ULONG_MAX); mpz_add_ui (nanoseconds, nanoseconds, time.tv_nsec); @@ -572,6 +576,7 @@ Fmod_test_nanoseconds (emacs_env *env, ptrdiff_t nargs, emacs_value *args, void mpz_clear (nanoseconds); return result; } +#endif static emacs_value Fmod_test_double (emacs_env *env, ptrdiff_t nargs, emacs_value *args, @@ -631,7 +636,7 @@ sleep_for_half_second (void) #ifdef WINDOWSNT Sleep (500); #else - const struct timespec sleep = {0, 500000000}; + const struct timespec sleep = { .tv_nsec = 500000000 }; if (nanosleep (&sleep, NULL) != 0) perror ("nanosleep"); #endif @@ -763,6 +768,11 @@ bind_function (emacs_env *env, const char *name, emacs_value Sfun) int emacs_module_init (struct emacs_runtime *ert) { + /* 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); + /* Check that EMACS_MAJOR_VERSION is defined and an integral constant. */ char dummy[EMACS_MAJOR_VERSION]; @@ -815,9 +825,13 @@ emacs_module_init (struct emacs_runtime *ert) DEFUN ("mod-test-invalid-load", Fmod_test_invalid_load, 0, 0, NULL, NULL); DEFUN ("mod-test-invalid-finalizer", Fmod_test_invalid_finalizer, 0, 0, NULL, NULL); +#ifdef CLOCK_REALTIME DEFUN ("mod-test-sleep-until", Fmod_test_sleep_until, 2, 2, NULL, NULL); +#endif DEFUN ("mod-test-add-nanosecond", Fmod_test_add_nanosecond, 1, 1, NULL, NULL); +#ifdef CLOCK_REALTIME DEFUN ("mod-test-nanoseconds", Fmod_test_nanoseconds, 1, 1, NULL, NULL); +#endif DEFUN ("mod-test-double", Fmod_test_double, 1, 1, NULL, NULL); DEFUN ("mod-test-make-function-with-finalizer", Fmod_test_make_function_with_finalizer, 0, 0, NULL, NULL); diff --git a/test/src/emacs-module-tests.el b/test/src/emacs-module-tests.el index ec83f91f003..1099fd04678 100644 --- a/test/src/emacs-module-tests.el +++ b/test/src/emacs-module-tests.el @@ -336,6 +336,7 @@ Return A + B (ert-deftest mod-test-sleep-until () "Check that `mod-test-sleep-until' either returns normally or quits. Interactively, you can try hitting \\[keyboard-quit] to quit." + (skip-unless (fboundp 'mod-test-sleep-until)) (dolist (arg '(nil t)) ;; Guard against some caller setting `inhibit-quit'. (with-local-quit @@ -390,6 +391,7 @@ Interactively, you can try hitting \\[keyboard-quit] to quit." (ert-deftest mod-test-nanoseconds () "Test truncation when converting to `struct timespec'." + (skip-unless (fboundp 'mod-test-nanoseconds)) (dolist (test-case '((0 . 0) (-1 . -1000000000) ((1 . 1000000000) . 1) @@ -408,6 +410,7 @@ Interactively, you can try hitting \\[keyboard-quit] to quit." (should (= (mod-test-nanoseconds input) expected)))))) (ert-deftest mod-test-double () + (skip-unless (fboundp 'mod-test-double)) (dolist (input (list 0 1 2 -1 42 12345678901234567890 most-positive-fixnum (1+ most-positive-fixnum) most-negative-fixnum (1- most-negative-fixnum))) -- 2.39.2