diff options
-rw-r--r-- | doc/lispref/internals.texi | 44 | ||||
-rw-r--r-- | etc/NEWS | 3 | ||||
-rw-r--r-- | src/emacs-module.c | 17 | ||||
-rw-r--r-- | src/emacs-module.h.in | 1 | ||||
-rw-r--r-- | src/module-env-27.h | 6 | ||||
-rw-r--r-- | test/data/emacs-module/mod-test.c | 13 | ||||
-rw-r--r-- | test/src/emacs-module-tests.el | 28 |
7 files changed, 112 insertions, 0 deletions
diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi index 25892d4b57c..0e7a1339e76 100644 --- a/doc/lispref/internals.texi +++ b/doc/lispref/internals.texi @@ -1387,6 +1387,38 @@ This function returns the value of a Lisp float specified by @var{arg}, as a C @code{double} value. @end deftypefn +@deftypefn Function struct timespec extract_time (emacs_env *@var{env}, emacs_value @var{time}) +This function, which is available since Emacs 27, interprets +@var{time} as an Emacs Lisp time value and returns the corresponding +@code{struct timespec}. @xref{Time of Day}. @code{struct timespec} +represents a timestamp with nanosecond precision. It has the +following members: + +@table @code +@item time_t tv_sec +Whole number of seconds. +@item long tv_nsec +Fractional seconds as number of nanoseconds, always less than one +billion. +@end table + +@noindent +@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. + +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 +function @code{encode-time} and work with its return value. +@xref{Time Conversion}. +@end deftypefn + @deftypefn Function bool copy_string_contents (emacs_env *@var{env}, emacs_value @var{arg}, char *@var{buf}, ptrdiff_t *@var{len}) This function stores the UTF-8 encoded text of a Lisp string specified by @var{arg} in the array of @code{char} pointed by @var{buf}, which @@ -1452,6 +1484,18 @@ This function takes a @code{double} argument @var{d} and returns the corresponding Emacs floating-point value. @end deftypefn +@deftypefn Function emacs_value make_time (emacs_env *@var{env}, struct timespec @var{time}) +This function, which is available since Emacs 27, takes a @code{struct +timespec} argument @var{time} and returns the corresponding Emacs +timestamp as a pair @code{(@var{ticks} . @var{hz})}. @xref{Time of +Day}. The return value represents exactly the same timestamp as +@var{time}: all input values are representable, and there is never a +loss of precision. @code{@var{time}.tv_sec} and +@code{@var{time}.tv_nsec} can be arbitrary values. In particular, +there's no requirement that @var{time} be normalized. This means that +@code{@var{time}.tv_nsec} can be negative or larger than 999,999,999. +@end deftypefn + @deftypefn Function emacs_value make_string (emacs_env *@var{env}, const char *@var{str}, ptrdiff_t @var{strlen}) This function creates an Emacs string from C text string pointed by @var{str} whose length in bytes, not including the terminating null @@ -1910,6 +1910,9 @@ returns a regexp that never matches anything, which is an identity for this operation. Previously, the empty string was returned in this case. +** New module environment functions 'make_time' and 'extract_time' to +convert between timespec structures and Emacs Lisp time values. + * Changes in Emacs 27.1 on Non-Free Operating Systems diff --git a/src/emacs-module.c b/src/emacs-module.c index b812fdc2df4..e46af30ce84 100644 --- a/src/emacs-module.c +++ b/src/emacs-module.c @@ -77,6 +77,7 @@ To add a new module function, proceed as follows: #include <stdint.h> #include <stdio.h> #include <stdlib.h> +#include <time.h> #include "lisp.h" #include "dynlib.h" @@ -737,6 +738,20 @@ module_process_input (emacs_env *env) return emacs_process_input_continue; } +static struct timespec +module_extract_time (emacs_env *env, emacs_value value) +{ + MODULE_FUNCTION_BEGIN ((struct timespec) {0}); + return lisp_time_argument (value_to_lisp (value)); +} + +static emacs_value +module_make_time (emacs_env *env, struct timespec time) +{ + MODULE_FUNCTION_BEGIN (NULL); + return lisp_to_value (env, make_lisp_time (time)); +} + /* Subroutines. */ @@ -1140,6 +1155,8 @@ initialize_environment (emacs_env *env, struct emacs_env_private *priv) env->vec_size = module_vec_size; env->should_quit = module_should_quit; env->process_input = module_process_input; + env->extract_time = module_extract_time; + env->make_time = module_make_time; Vmodule_environments = Fcons (make_mint_ptr (env), Vmodule_environments); return env; } diff --git a/src/emacs-module.h.in b/src/emacs-module.h.in index 009d1583fef..bfbe226dd90 100644 --- a/src/emacs-module.h.in +++ b/src/emacs-module.h.in @@ -22,6 +22,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ #include <stdint.h> #include <stddef.h> +#include <time.h> #ifndef __cplusplus #include <stdbool.h> diff --git a/src/module-env-27.h b/src/module-env-27.h index b491b60fbbc..e63843f8d63 100644 --- a/src/module-env-27.h +++ b/src/module-env-27.h @@ -2,3 +2,9 @@ function should quit. */ enum emacs_process_input_result (*process_input) (emacs_env *env) EMACS_ATTRIBUTE_NONNULL (1); + + struct timespec (*extract_time) (emacs_env *env, emacs_value value) + EMACS_ATTRIBUTE_NONNULL (1); + + emacs_value (*make_time) (emacs_env *env, struct timespec time) + EMACS_ATTRIBUTE_NONNULL (1); diff --git a/test/data/emacs-module/mod-test.c b/test/data/emacs-module/mod-test.c index a39e41afee6..dbdbfecfe6a 100644 --- a/test/data/emacs-module/mod-test.c +++ b/test/data/emacs-module/mod-test.c @@ -366,6 +366,18 @@ Fmod_test_sleep_until (emacs_env *env, ptrdiff_t nargs, emacs_value *args, return env->intern (env, "finished"); } +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); +} + /* Lisp utilities for easier readability (simple wrappers). */ /* Provide FEATURE to Emacs. */ @@ -434,6 +446,7 @@ emacs_module_init (struct emacs_runtime *ert) DEFUN ("mod-test-invalid-finalizer", Fmod_test_invalid_finalizer, 0, 0, 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); #undef DEFUN diff --git a/test/src/emacs-module-tests.el b/test/src/emacs-module-tests.el index 35aaaa64b65..eea4c611655 100644 --- a/test/src/emacs-module-tests.el +++ b/test/src/emacs-module-tests.el @@ -310,4 +310,32 @@ Interactively, you can try hitting \\[keyboard-quit] to quit." 'finished)) (quit))))) +(ert-deftest mod-test-add-nanosecond/valid () + (dolist (input (list + ;; Some realistic examples. + (current-time) (time-to-seconds) + (encode-time 12 34 5 6 7 2019 t) + ;; Various legacy timestamp forms. + '(123 456) '(123 456 789) '(123 456 789 6000) + ;; Corner case: this will result in a nanosecond + ;; value of 1000000000 after addition. The module + ;; code should handle this correctly. + '(123 65535 999999 999000) + ;; Seconds since the epoch. + 123 123.45 + ;; New (TICKS . HZ) format. + '(123456789 . 1000000000))) + (ert-info ((format "input: %s" input)) + (should (time-equal-p (mod-test-add-nanosecond input) + (time-add input '(0 0 0 1000))))))) + +(ert-deftest mod-test-add-nanosecond/nil () + (should (<= (float-time (mod-test-add-nanosecond nil)) + (+ (float-time) 1e-9)))) + +(ert-deftest mod-test-add-nanosecond/invalid () + (dolist (input '(1.0e+INF 1.0e-INF 0.0e+NaN (123) (123.45 6 7) "foo" [1 2])) + (ert-info ((format "input: %s" input)) + (should-error (mod-test-add-nanosecond input))))) + ;;; emacs-module-tests.el ends here |