From mboxrd@z Thu Jan 1 00:00:00 1970
Path: news.gmane.org!.POSTED.blaine.gmane.org!not-for-mail
From: Philipp Stephani
Newsgroups: gmane.emacs.devel
Subject: [PATCH 1/2] Add conversions to and from struct timespec to module
interface.
Date: Tue, 23 Apr 2019 23:32:17 +0200
Message-ID: <20190423213218.35618-1-phst@google.com>
References: <329aec43-8272-f39a-e7ef-e77804103a50@cs.ucla.edu>
Mime-Version: 1.0
Content-Transfer-Encoding: 8bit
Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226";
logging-data="172682"; mail-complaints-to="usenet@blaine.gmane.org"
Cc: Philipp Stephani
To: eggert@cs.ucla.edu,
eliz@gnu.org,
emacs-devel@gnu.org
Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Tue Apr 23 23:33:18 2019
Return-path:
Envelope-to: ged-emacs-devel@m.gmane.org
Original-Received: from lists.gnu.org ([209.51.188.17])
by blaine.gmane.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:256)
(Exim 4.89)
(envelope-from )
id 1hJ32T-000ilp-N8
for ged-emacs-devel@m.gmane.org; Tue, 23 Apr 2019 23:33:17 +0200
Original-Received: from localhost ([127.0.0.1]:59792 helo=lists.gnu.org)
by lists.gnu.org with esmtp (Exim 4.71)
(envelope-from )
id 1hJ32S-00017w-Dd
for ged-emacs-devel@m.gmane.org; Tue, 23 Apr 2019 17:33:16 -0400
Original-Received: from eggs.gnu.org ([209.51.188.92]:53647)
by lists.gnu.org with esmtp (Exim 4.71)
(envelope-from ) id 1hJ31h-00017c-L2
for emacs-devel@gnu.org; Tue, 23 Apr 2019 17:32:32 -0400
Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71)
(envelope-from ) id 1hJ31c-0007uo-SI
for emacs-devel@gnu.org; Tue, 23 Apr 2019 17:32:28 -0400
Original-Received: from mail-wm1-x341.google.com ([2a00:1450:4864:20::341]:37380)
by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16)
(Exim 4.71) (envelope-from )
id 1hJ31U-0007n2-7a; Tue, 23 Apr 2019 17:32:16 -0400
Original-Received: by mail-wm1-x341.google.com with SMTP id v14so1921530wmf.2;
Tue, 23 Apr 2019 14:32:16 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025;
h=from:to:cc:subject:date:message-id:in-reply-to:references
:mime-version:content-transfer-encoding;
bh=fK1VyIFQ3L1A4hKiDfTnC0vDsDkjhFnjiPzT40PCtUI=;
b=CUzHVIHfYpLHtpl6guCjjPDwRF6CO2+p9tTe6KuikUwzpiU+y6VdyRRs6yXf0YGre1
af5SXimRiVtnSyQdi0V0+wIYlZzoCDtGfnNfr/iHkm9Wun7fF+mK+Wa7+EGUYxM5ZE4j
znK6+MX0J0fScOzVGCvKZC58zq2o96aoiKpLubtAqR2+jP7Rv+7wAR/JgE6CTvqXT9mU
iQU7nD5Le5eeje9MjgcrOLTiC7bV28L5VZ7aZEgapygfftr9nDf7Mco7wZkmoPrObQ0d
cThwMjegwbA3psq4Tbkne8unJ3ZRm/hTPUoX5J+zGiaVPsx6rPWaf7wrqlTTer93Ro3p
2Idw==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=1e100.net; s=20161025;
h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to
:references:mime-version:content-transfer-encoding;
bh=fK1VyIFQ3L1A4hKiDfTnC0vDsDkjhFnjiPzT40PCtUI=;
b=qLgO3FCpJ7QNy7jvCFwqKjpjOhJMH1PrIH6O+k8HvlBhV1HfPVnxNylANdqELSiEYB
gOuSR1DVfaqmxW4g43JqkIPc7FTZVhxC/ZAaYZOKW6zL/q5fJb2K6XyIfwfh8VsFKwxe
MF1fYAabJ9jvL0Z58Sih8VRibRh+cjwURDDV/1fcKsf08U93mlFyPxpPrvcf/hUNBV5M
m5jnTxqPq8LQSqmcmCLEWz4qkDH/M12quVbOAEMaZbr1YBapRhhhIzhlS8ACBncgrrT8
3KpWOmQNai41lt5yLmo0f7ZLwhzh+BIosILSgP5bElI0dWYqTvMAZ5gJvkYZFO3q3pqb
ghBw==
X-Gm-Message-State: APjAAAUGBsNDIFOryJxSl61v0xZq/mV9Q4OKd2w2Y4ILn55KY+cBPOjf
CQl0mCG2Uy+3UWLKMmasYvs=
X-Google-Smtp-Source: APXvYqwhurSmzUjL9XMOk8wAx/4NrrLEJUM/LhNRPPmC16MIgAiEJuKRq6Rpd3z7TC3wU7Dad+MkfA==
X-Received: by 2002:a1c:9d46:: with SMTP id g67mr3575183wme.99.1556055134754;
Tue, 23 Apr 2019 14:32:14 -0700 (PDT)
Original-Received: from p.cm.cablesurf.de (85.233.42.145.dynamic.cablesurf.de.
[85.233.42.145]) by smtp.gmail.com with ESMTPSA id
c2sm15087307wrr.13.2019.04.23.14.32.13
(version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128);
Tue, 23 Apr 2019 14:32:13 -0700 (PDT)
X-Google-Original-From: Philipp Stephani
X-Mailer: git-send-email 2.20.1 (Apple Git-117)
In-Reply-To: <329aec43-8272-f39a-e7ef-e77804103a50@cs.ucla.edu>
X-detected-operating-system: by eggs.gnu.org: Genre and OS details not
recognized.
X-Received-From: 2a00:1450:4864:20::341
X-BeenThere: emacs-devel@gnu.org
X-Mailman-Version: 2.1.21
Precedence: list
List-Id: "Emacs development discussions."
List-Unsubscribe: ,
List-Archive:
List-Post:
List-Help:
List-Subscribe: ,
Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org
Original-Sender: "Emacs-devel"
Xref: news.gmane.org gmane.emacs.devel:235839
Archived-At:
Time values are a fundamental data type, and such conversions are hard
to implement within modules because of the various forms of time
values in Emacs Lisp. Adding dedicated conversion functions can
significantly simplify module code dealing with times.
This approach uses nanosecond precision. While Emacs in theory has
support for higher-precision time values, in practice most languages
and standards, such as POSIX, C, Java, and Go, have settled on
nanosecond-precision integers to represent time.
* src/emacs-module.h.in: Add header for struct timespec.
* src/module-env-27.h: Add module functions for time conversion.
* src/emacs-module.c (module_extract_time, module_make_time): New
functions.
(initialize_environment): Use them.
* test/data/emacs-module/mod-test.c (Fmod_test_add_nanosecond): New
test function.
(emacs_module_init): Define it.
* test/src/emacs-module-tests.el (mod-test-add-nanosecond/valid)
(mod-test-add-nanosecond/nil, mod-test-add-nanosecond/invalid): New
unit tests.
* doc/lispref/internals.texi (Module Values): Document time
conversion functions.
---
doc/lispref/internals.texi | 22 ++++++++++++++++++++++
etc/NEWS | 3 +++
src/emacs-module.c | 17 +++++++++++++++++
src/emacs-module.h.in | 1 +
src/module-env-27.h | 6 ++++++
test/data/emacs-module/mod-test.c | 13 +++++++++++++
test/src/emacs-module-tests.el | 28 ++++++++++++++++++++++++++++
7 files changed, 90 insertions(+)
diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi
index 25892d4b57..fb838113bc 100644
--- a/doc/lispref/internals.texi
+++ b/doc/lispref/internals.texi
@@ -1387,6 +1387,15 @@ Module Values
@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 time value and returns the corresponding
+@code{struct timespec}. @xref{Time of Day}. This function signals an
+error if @var{time} is out of range for @code{struct timespec}. If
+@var{time} has higher precision than nanoseconds, then this function
+truncates it to nanosecond precision.
+@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 +1461,19 @@ Module Values
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. @xref{Time of Day} for the possible return value formats.
+It is not specified in which timestamp format the time is returned,
+but it is always a valid Emacs timestamp. The return value is exactly
+the same timestamp as @var{time}: all input values are representable,
+and there is never a loss of precision. @code{time.tv_sec} and
+@code{time.tv_nsec} can be arbitrary values. In particular, there's
+no requirement that @var{time} be normalized. This means that
+@code{time.tv_nsec} doesn't have to be in the range [0, 999999999].
+@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 b13ab47768..2534262b62 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 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 d7704efcf6..b798789351 100644
--- a/src/emacs-module.c
+++ b/src/emacs-module.c
@@ -74,6 +74,7 @@ To add a new module function, proceed as follows:
#include
#include
#include
+#include
#include "lisp.h"
#include "dynlib.h"
@@ -734,6 +735,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. */
@@ -1137,6 +1152,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 009d1583fe..bfbe226dd9 100644
--- a/src/emacs-module.h.in
+++ b/src/emacs-module.h.in
@@ -22,6 +22,7 @@ along with GNU Emacs. If not, see . */
#include
#include
+#include
#ifndef __cplusplus
#include
diff --git a/src/module-env-27.h b/src/module-env-27.h
index b491b60fbb..e63843f8d6 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 a39e41afee..dbdbfecfe6 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 35aaaa64b6..eea4c61165 100644
--- a/test/src/emacs-module-tests.el
+++ b/test/src/emacs-module-tests.el
@@ -310,4 +310,32 @@ module--test-assertion
'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
--
2.20.1 (Apple Git-117)