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 15:17:41 +0200 Message-ID: <20190423131742.65814-1-phst@google.com> Mime-Version: 1.0 Content-Transfer-Encoding: 8bit Injection-Info: blaine.gmane.org; posting-host="blaine.gmane.org:195.159.176.226"; logging-data="10448"; mail-complaints-to="usenet@blaine.gmane.org" Cc: Philipp Stephani To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Tue Apr 23 15:23:02 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 1hIvO2-0002ZL-0k for ged-emacs-devel@m.gmane.org; Tue, 23 Apr 2019 15:23:02 +0200 Original-Received: from localhost ([127.0.0.1]:53804 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hIvO1-0007Hf-01 for ged-emacs-devel@m.gmane.org; Tue, 23 Apr 2019 09:23:01 -0400 Original-Received: from eggs.gnu.org ([209.51.188.92]:59605) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1hIvJ9-0004da-6H for emacs-devel@gnu.org; Tue, 23 Apr 2019 09:18:01 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1hIvJ7-0002dR-53 for emacs-devel@gnu.org; Tue, 23 Apr 2019 09:17:59 -0400 Original-Received: from mail-wm1-x343.google.com ([2a00:1450:4864:20::343]:52088) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1hIvJ6-0002cV-S9 for emacs-devel@gnu.org; Tue, 23 Apr 2019 09:17:57 -0400 Original-Received: by mail-wm1-x343.google.com with SMTP id 4so29513wmf.1 for ; Tue, 23 Apr 2019 06:17:56 -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:mime-version :content-transfer-encoding; bh=0BfxKR8A/4ZW7lkEGr2bHGvRLbro+fhFpWGnSXQj12k=; b=NwVruS+nHeysjSTq5V1BMy3ovTl/m2ipaykYj4mYpiGf/fI5gvtlfAzAa59vU0HeoR an5y9Ztzv3ZywImNElypUW+TUqWAU/tDMSAzjtXhD92+xEHEInY8RX5rL97Bqakflgav pr0Onxg2B3AkUNiWNrdbV+hIEzfvQqykLNgnqfxcGZfOtDBAzKiLl1MjLv0gxPmLHMFn j58slqiYyrrivEzX7+1nWPgFtxqje7doe6LoANxXq7vudDAzXPmKo/ofZHN0ElS9ZIbN U1QgPmvqM+aNBay1p6Be6TPJKEDfbgN/c5HEIe7q6kzcjdbIEDrtkWx0Yo+niyQ4yoDj lTVw== 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:mime-version :content-transfer-encoding; bh=0BfxKR8A/4ZW7lkEGr2bHGvRLbro+fhFpWGnSXQj12k=; b=g/jNWkTey9fjhiz32nkcZNVYFNX/jHMLfJpZzljGlEdv4+OPRMJ+901DHerWXaaSin bkcNxGEjXM1mM+jA4m+9vSr+LBMNrXm3zbOwbvyZm0eYXR2WoJ2jOnhOtm/z3J1ruL/w kYRReMy+A3Fxp5VVUQPMUDeU+BvsZsKGPMcdDcK+rXc9Ywplz/u1iOgqNXr24C7lsQHx YoV0xD+e75rWwFIr+xg/nGnF9zd6/4kdifsBYmLZQ3vUdRsdlnXyXwhVbTFIb8wUBzhd OXrOkQcVy6kFi7sY3L7wUZj/X0MiO33ToD0wTCdBIek7Q0XSL0DOlQiJkcJCIU95NO1d Z+DA== X-Gm-Message-State: APjAAAVXY9Hw98BODyiqqdgiiq177KKzBrptyabN+sGJ++FOTirw1oqw jdzbfC7rS6m8CoyCMCe0PuUwnDsy X-Google-Smtp-Source: APXvYqzeE9wDWOfwjWnBw0ckeEW5IpLL+zuRU6TJnu6ZHzDO9RhMHqawxsUZwTustXU985+tBnY8Ag== X-Received: by 2002:a1c:2dd2:: with SMTP id t201mr2486539wmt.10.1556025474884; Tue, 23 Apr 2019 06:17:54 -0700 (PDT) Original-Received: from p.fritz.box (p5B13F5EA.dip0.t-ipconnect.de. [91.19.245.234]) by smtp.gmail.com with ESMTPSA id z7sm11983817wml.40.2019.04.23.06.17.53 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Tue, 23 Apr 2019 06:17:53 -0700 (PDT) X-Google-Original-From: Philipp Stephani X-Mailer: git-send-email 2.20.1 (Apple Git-117) X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 2a00:1450:4864:20::343 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:235819 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/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 | 20 ++++++++++++++++++++ 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 | 25 +++++++++++++++++++++++++ 7 files changed, 90 insertions(+) diff --git a/doc/lispref/internals.texi b/doc/lispref/internals.texi index 25892d4b57..c2969d2cd1 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 interprets @var{time} as an Emacs time value and returns +the corresponding @code{struct timespec}. @xref{Time of Day}. +@var{time} may not be @code{nil}. This function raises 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 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 20dcff2b67..fc5a912d85 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" @@ -731,6 +732,22 @@ 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}); + Lisp_Object time = value_to_lisp (value); + CHECK_TYPE (!NILP (time), Qtimep, time); + return lisp_time_argument (time); +} + +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. */ @@ -1134,6 +1151,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; } @@ -1296,6 +1315,7 @@ syms_of_module (void) build_pure_c_string ("Invalid function arity")); DEFSYM (Qmodule_function_p, "module-function-p"); + DEFSYM (Qtimep, "timep"); defsubr (&Smodule_load); } 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..44a28fa18f 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 < 1000000000); + 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..6b986a96e2 100644 --- a/test/src/emacs-module-tests.el +++ b/test/src/emacs-module-tests.el @@ -310,4 +310,29 @@ 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/invalid () + (dolist (input '(#x10000000000000000 ; out of range + (123) (123.45 6 7) nil "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)