From c4bacb1215bfdf058b374312256c27eaea1304a4 Mon Sep 17 00:00:00 2001 From: Philipp Stephani Date: Wed, 24 Apr 2019 13:41:05 +0200 Subject: [PATCH] Clarify rounding mode when converting to struct timespec. * doc/lispref/internals.texi (Module Values): Clarify that the truncation is towards negative infinity. * test/data/emacs-module/mod-test.c (Fmod_test_nanoseconds): Add test function. (emacs_module_init): Define it. * test/src/emacs-module-tests.el (mod-test-nanoseconds): New unit test. --- doc/lispref/internals.texi | 12 ++++++------ test/data/emacs-module/mod-test.c | 17 +++++++++++++++++ test/src/emacs-module-tests.el | 19 +++++++++++++++++++ 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi index 10f49c569fa..3e6488a5ccf 100644 --- a/doc/lispref/internals.texi +++ b/doc/lispref/internals.texi @@ -1406,12 +1406,12 @@ billion. @xref{Elapsed Time,,,libc}. If @var{time} has higher precision than nanoseconds, then this -function truncates it to nanosecond precision. This function signals -an error if @var{time} (truncated to nanoseconds) cannot be -represented by @code{struct timespec}. For example, if @code{time_t} -is a 32-bit integral type, then a @var{time} value of ten billion -seconds would signal an error, but a @var{time} value of 600 -picoseconds would get truncated to zero. +function truncates it to nanosecond precision towards negative +infinity. This function signals an error if @var{time} (truncated to +nanoseconds) cannot be represented by @code{struct timespec}. For +example, if @code{time_t} is a 32-bit integral type, then a @var{time} +value of ten billion seconds would signal an error, but a @var{time} +value of 600 picoseconds would get truncated to zero. If you need to deal with time values that are not representable by @code{struct timespec}, or if you want higher precision, call the Lisp diff --git a/test/data/emacs-module/mod-test.c b/test/data/emacs-module/mod-test.c index 85a7f28e50d..8ac08f71534 100644 --- a/test/data/emacs-module/mod-test.c +++ b/test/data/emacs-module/mod-test.c @@ -381,6 +381,22 @@ Fmod_test_add_nanosecond (emacs_env *env, ptrdiff_t nargs, emacs_value *args, return env->make_time (env, time); } +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]); + struct emacs_mpz nanoseconds; + assert (LONG_MIN <= time.tv_sec && time.tv_sec <= LONG_MAX); + mpz_init_set_si (nanoseconds.value, time.tv_sec); + static_assert (1000000000 <= ULONG_MAX, "unsupported architecture"); + mpz_mul_ui (nanoseconds.value, nanoseconds.value, 1000000000); + assert (0 <= time.tv_nsec && time.tv_nsec <= ULONG_MAX); + mpz_add_ui (nanoseconds.value, nanoseconds.value, time.tv_nsec); + emacs_value result = env->make_big_integer (env, &nanoseconds); + mpz_clear (nanoseconds.value); + return result; +} + static emacs_value Fmod_test_double (emacs_env *env, ptrdiff_t nargs, emacs_value *args, void *data) @@ -465,6 +481,7 @@ emacs_module_init (struct emacs_runtime *ert) NULL, NULL); DEFUN ("mod-test-sleep-until", Fmod_test_sleep_until, 2, 2, NULL, NULL); DEFUN ("mod-test-add-nanosecond", Fmod_test_add_nanosecond, 1, 1, NULL, NULL); + DEFUN ("mod-test-nanoseconds", Fmod_test_nanoseconds, 1, 1, NULL, NULL); DEFUN ("mod-test-double", Fmod_test_double, 1, 1, NULL, NULL); #undef DEFUN diff --git a/test/src/emacs-module-tests.el b/test/src/emacs-module-tests.el index 9eb38cd4548..173b63670fc 100644 --- a/test/src/emacs-module-tests.el +++ b/test/src/emacs-module-tests.el @@ -342,6 +342,25 @@ Interactively, you can try hitting \\[keyboard-quit] to quit." (ert-info ((format "input: %s" input)) (should-error (mod-test-add-nanosecond input))))) +(ert-deftest mod-test-nanoseconds () + "Test truncation when converting to `struct timespec'." + (dolist (test-case '((0 . 0) + (-1 . -1000000000) + ((1 . 1000000000) . 1) + ((-1 . 1000000000) . -1) + ((1 . 1000000000000) . 0) + ((-1 . 1000000000000) . -1) + ((999 . 1000000000000) . 0) + ((-999 . 1000000000000) . -1) + ((1000 . 1000000000000) . 1) + ((-1000 . 1000000000000) . -1) + ((0 0 0 1) . 0) + ((0 0 0 -1) . -1))) + (let ((input (car test-case)) + (expected (cdr test-case))) + (ert-info ((format "input: %S, expected result: %d" input expected)) + (should (eq (mod-test-nanoseconds input) expected)))))) + (ert-deftest mod-test-double () (dolist (input (list 0 1 2 -1 42 12345678901234567890 most-positive-fixnum (1+ most-positive-fixnum) -- 2.39.2