summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/lispref/internals.texi44
-rw-r--r--etc/NEWS3
-rw-r--r--src/emacs-module.c17
-rw-r--r--src/emacs-module.h.in1
-rw-r--r--src/module-env-27.h6
-rw-r--r--test/data/emacs-module/mod-test.c13
-rw-r--r--test/src/emacs-module-tests.el28
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
diff --git a/etc/NEWS b/etc/NEWS
index b13ab47768b..fc9b828baa1 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -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