emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 50765f3: Make run-at-time try harder to run at integral multiples


From: Lars Ingebrigtsen
Subject: master 50765f3: Make run-at-time try harder to run at integral multiples
Date: Mon, 30 Aug 2021 21:04:40 -0400 (EDT)

branch: master
commit 50765f3f511d467ff024dda7c84530c759253d18
Author: Lars Ingebrigtsen <larsi@gnus.org>
Commit: Lars Ingebrigtsen <larsi@gnus.org>

    Make run-at-time try harder to run at integral multiples
    
    * lisp/emacs-lisp/timer.el (timer): Add new slot integral-multiple.
    (timerp): Adjust.
    (timer-event-handler): Recompute the delay if requested
    (bug#39099).
    (run-at-time): Mark the timer as recomputable if given a t
    parameter.
    
    * src/keyboard.c (decode_timer): Adjust.
---
 etc/NEWS                 | 11 +++++++
 lisp/emacs-lisp/timer.el | 81 ++++++++++++++++++++++++++++--------------------
 src/keyboard.c           |  2 +-
 3 files changed, 59 insertions(+), 35 deletions(-)

diff --git a/etc/NEWS b/etc/NEWS
index 657e129..66006db 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -3146,6 +3146,17 @@ work for `context-menu-mode` in Xterm.
 * Incompatible Lisp Changes in Emacs 28.1
 
 ---
+** 'run-at-time' now tries harder to implement the t TIME parameter.
+If TIME is t, the timer runs at an integral multiple of REPEAT.
+(I.e., if given a REPEAT of 60, it'll run at 08:11:00, 08:12:00,
+08:13:00.)  However, when a machine goes to sleep (or otherwise didn't
+get a time slot to run when the timer was scheduled), the timer would
+then fire every 60 seconds after the time the timer was fired.  This
+has now changed, and the timer code now recomputes the integral
+multiple every time it runs, which means that if the laptop wakes at
+08:16:43, it'll fire at that time, but then at 08:17:00, 08:18:00...
+
+---
 ** 'parse-partial-sexp' now signals an error if TO is smaller than FROM.
 Previously this would lead to the function interpreting FROM as TO and
 vice versa, which would be confusing when passing in OLDSTATE, which
diff --git a/lisp/emacs-lisp/timer.el b/lisp/emacs-lisp/timer.el
index 36de29a..f771510 100644
--- a/lisp/emacs-lisp/timer.el
+++ b/lisp/emacs-lisp/timer.el
@@ -29,6 +29,8 @@
 
 (eval-when-compile (require 'cl-lib))
 
+;; If you change this structure, you also have to change `timerp'
+;; (below) and decode_timer in keyboard.c.
 (cl-defstruct (timer
                (:constructor nil)
                (:copier nil)
@@ -46,11 +48,16 @@
   repeat-delay
   function args                         ;What to do when triggered.
   idle-delay                            ;If non-nil, this is an idle-timer.
-  psecs)
+  psecs
+  ;; A timer may be created with `t' as the TIME, which means that we
+  ;; want to run at specific integral multiples of `repeat-delay'.  We
+  ;; then have to recompute this (because the machine may have gone to
+  ;; sleep, etc).
+  integral-multiple)
 
 (defun timerp (object)
   "Return t if OBJECT is a timer."
-  (and (vectorp object) (= (length object) 9)))
+  (and (vectorp object) (= (length object) 10)))
 
 (defsubst timer--check (timer)
   (or (timerp timer) (signal 'wrong-type-argument (list #'timerp timer))))
@@ -284,6 +291,13 @@ This function is called, by name, directly by the C code."
                     (if (> repeats timer-max-repeats)
                         (timer-inc-time timer (* (timer--repeat-delay timer)
                                                  repeats)))))
+              ;; If we want integral multiples, we have to recompute
+              ;; the repetition.
+              (when (and (timer--integral-multiple timer)
+                         (not (timer--idle-delay timer)))
+                (setf (timer--time timer)
+                      (timer-next-integral-multiple-of-time
+                       (current-time) (timer--repeat-delay timer))))
               ;; Place it back on the timer-list before running
               ;; timer--function, so it can cancel-timer itself.
               (timer-activate timer t cell)
@@ -340,45 +354,44 @@ This function returns a timer object which you can use in
 `cancel-timer'."
   (interactive "sRun at time: \nNRepeat interval: \naFunction: ")
 
-  (or (null repeat)
-      (and (numberp repeat) (< 0 repeat))
-      (error "Invalid repetition interval"))
+  (when (and repeat
+             (numberp repeat)
+             (< repeat 0))
+    (error "Invalid repetition interval"))
 
-  ;; Special case: nil means "now" and is useful when repeating.
-  (if (null time)
+  (let ((timer (timer-create)))
+    ;; Special case: nil means "now" and is useful when repeating.
+    (unless time
       (setq time (current-time)))
 
-  ;; Special case: t means the next integral multiple of REPEAT.
-  (if (and (eq time t) repeat)
-      (setq time (timer-next-integral-multiple-of-time (current-time) repeat)))
+    ;; Special case: t means the next integral multiple of REPEAT.
+    (when (and (eq time t) repeat)
+      (setq time (timer-next-integral-multiple-of-time (current-time) repeat))
+      (setf (timer--integral-multiple timer) t))
 
-  ;; Handle numbers as relative times in seconds.
-  (if (numberp time)
+    ;; Handle numbers as relative times in seconds.
+    (when (numberp time)
       (setq time (timer-relative-time nil time)))
 
-  ;; Handle relative times like "2 hours 35 minutes"
-  (if (stringp time)
-      (let ((secs (timer-duration time)))
-       (if secs
-           (setq time (timer-relative-time nil secs)))))
-
-  ;; Handle "11:23pm" and the like.  Interpret it as meaning today
-  ;; which admittedly is rather stupid if we have passed that time
-  ;; already.  (Though only Emacs hackers hack Emacs at that time.)
-  (if (stringp time)
-      (progn
-       (require 'diary-lib)
-       (let ((hhmm (diary-entry-time time))
-             (now (decode-time)))
-         (if (>= hhmm 0)
-             (setq time
-                   (encode-time 0 (% hhmm 100) (/ hhmm 100)
-                                 (decoded-time-day now)
-                                (decoded-time-month now)
-                                 (decoded-time-year now)
-                                 (decoded-time-zone now)))))))
+    ;; Handle relative times like "2 hours 35 minutes".
+    (when (stringp time)
+      (when-let ((secs (timer-duration time)))
+       (setq time (timer-relative-time nil secs))))
+
+    ;; Handle "11:23pm" and the like.  Interpret it as meaning today
+    ;; which admittedly is rather stupid if we have passed that time
+    ;; already.  (Though only Emacs hackers hack Emacs at that time.)
+    (when (stringp time)
+      (require 'diary-lib)
+      (let ((hhmm (diary-entry-time time))
+           (now (decode-time)))
+       (when (>= hhmm 0)
+         (setq time (encode-time 0 (% hhmm 100) (/ hhmm 100)
+                                  (decoded-time-day now)
+                                 (decoded-time-month now)
+                                  (decoded-time-year now)
+                                  (decoded-time-zone now))))))
 
-  (let ((timer (timer-create)))
     (timer-set-time timer time repeat)
     (timer-set-function timer function args)
     (timer-activate timer)
diff --git a/src/keyboard.c b/src/keyboard.c
index 2e4c4e6..81ff9df 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -4234,7 +4234,7 @@ decode_timer (Lisp_Object timer, struct timespec *result)
 {
   Lisp_Object *vec;
 
-  if (! (VECTORP (timer) && ASIZE (timer) == 9))
+  if (! (VECTORP (timer) && ASIZE (timer) == 10))
     return false;
   vec = XVECTOR (timer)->contents;
   if (! NILP (vec[0]))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]