aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Ingebrigtsen2021-08-31 03:04:22 +0200
committerLars Ingebrigtsen2021-08-31 03:04:22 +0200
commit50765f3f511d467ff024dda7c84530c759253d18 (patch)
tree4e2d2c790599d7ba2a34433977557deb4cedb31b
parentd2ad64b7a524450bd1a4f59a5e0801abb0637b32 (diff)
downloademacs-50765f3f511d467ff024dda7c84530c759253d18.tar.gz
emacs-50765f3f511d467ff024dda7c84530c759253d18.zip
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.
-rw-r--r--etc/NEWS11
-rw-r--r--lisp/emacs-lisp/timer.el81
-rw-r--r--src/keyboard.c2
3 files changed, 59 insertions, 35 deletions
diff --git a/etc/NEWS b/etc/NEWS
index 657e12900fa..66006db8e0a 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -3146,6 +3146,17 @@ work for `context-menu-mode` in Xterm.
3146* Incompatible Lisp Changes in Emacs 28.1 3146* Incompatible Lisp Changes in Emacs 28.1
3147 3147
3148--- 3148---
3149** 'run-at-time' now tries harder to implement the t TIME parameter.
3150If TIME is t, the timer runs at an integral multiple of REPEAT.
3151(I.e., if given a REPEAT of 60, it'll run at 08:11:00, 08:12:00,
315208:13:00.) However, when a machine goes to sleep (or otherwise didn't
3153get a time slot to run when the timer was scheduled), the timer would
3154then fire every 60 seconds after the time the timer was fired. This
3155has now changed, and the timer code now recomputes the integral
3156multiple every time it runs, which means that if the laptop wakes at
315708:16:43, it'll fire at that time, but then at 08:17:00, 08:18:00...
3158
3159---
3149** 'parse-partial-sexp' now signals an error if TO is smaller than FROM. 3160** 'parse-partial-sexp' now signals an error if TO is smaller than FROM.
3150Previously this would lead to the function interpreting FROM as TO and 3161Previously this would lead to the function interpreting FROM as TO and
3151vice versa, which would be confusing when passing in OLDSTATE, which 3162vice 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 36de29a73a8..f7715109c82 100644
--- a/lisp/emacs-lisp/timer.el
+++ b/lisp/emacs-lisp/timer.el
@@ -29,6 +29,8 @@
29 29
30(eval-when-compile (require 'cl-lib)) 30(eval-when-compile (require 'cl-lib))
31 31
32;; If you change this structure, you also have to change `timerp'
33;; (below) and decode_timer in keyboard.c.
32(cl-defstruct (timer 34(cl-defstruct (timer
33 (:constructor nil) 35 (:constructor nil)
34 (:copier nil) 36 (:copier nil)
@@ -46,11 +48,16 @@
46 repeat-delay 48 repeat-delay
47 function args ;What to do when triggered. 49 function args ;What to do when triggered.
48 idle-delay ;If non-nil, this is an idle-timer. 50 idle-delay ;If non-nil, this is an idle-timer.
49 psecs) 51 psecs
52 ;; A timer may be created with `t' as the TIME, which means that we
53 ;; want to run at specific integral multiples of `repeat-delay'. We
54 ;; then have to recompute this (because the machine may have gone to
55 ;; sleep, etc).
56 integral-multiple)
50 57
51(defun timerp (object) 58(defun timerp (object)
52 "Return t if OBJECT is a timer." 59 "Return t if OBJECT is a timer."
53 (and (vectorp object) (= (length object) 9))) 60 (and (vectorp object) (= (length object) 10)))
54 61
55(defsubst timer--check (timer) 62(defsubst timer--check (timer)
56 (or (timerp timer) (signal 'wrong-type-argument (list #'timerp timer)))) 63 (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."
284 (if (> repeats timer-max-repeats) 291 (if (> repeats timer-max-repeats)
285 (timer-inc-time timer (* (timer--repeat-delay timer) 292 (timer-inc-time timer (* (timer--repeat-delay timer)
286 repeats))))) 293 repeats)))))
294 ;; If we want integral multiples, we have to recompute
295 ;; the repetition.
296 (when (and (timer--integral-multiple timer)
297 (not (timer--idle-delay timer)))
298 (setf (timer--time timer)
299 (timer-next-integral-multiple-of-time
300 (current-time) (timer--repeat-delay timer))))
287 ;; Place it back on the timer-list before running 301 ;; Place it back on the timer-list before running
288 ;; timer--function, so it can cancel-timer itself. 302 ;; timer--function, so it can cancel-timer itself.
289 (timer-activate timer t cell) 303 (timer-activate timer t cell)
@@ -340,45 +354,44 @@ This function returns a timer object which you can use in
340`cancel-timer'." 354`cancel-timer'."
341 (interactive "sRun at time: \nNRepeat interval: \naFunction: ") 355 (interactive "sRun at time: \nNRepeat interval: \naFunction: ")
342 356
343 (or (null repeat) 357 (when (and repeat
344 (and (numberp repeat) (< 0 repeat)) 358 (numberp repeat)
345 (error "Invalid repetition interval")) 359 (< repeat 0))
360 (error "Invalid repetition interval"))
346 361
347 ;; Special case: nil means "now" and is useful when repeating. 362 (let ((timer (timer-create)))
348 (if (null time) 363 ;; Special case: nil means "now" and is useful when repeating.
364 (unless time
349 (setq time (current-time))) 365 (setq time (current-time)))
350 366
351 ;; Special case: t means the next integral multiple of REPEAT. 367 ;; Special case: t means the next integral multiple of REPEAT.
352 (if (and (eq time t) repeat) 368 (when (and (eq time t) repeat)
353 (setq time (timer-next-integral-multiple-of-time (current-time) repeat))) 369 (setq time (timer-next-integral-multiple-of-time (current-time) repeat))
370 (setf (timer--integral-multiple timer) t))
354 371
355 ;; Handle numbers as relative times in seconds. 372 ;; Handle numbers as relative times in seconds.
356 (if (numberp time) 373 (when (numberp time)
357 (setq time (timer-relative-time nil time))) 374 (setq time (timer-relative-time nil time)))
358 375
359 ;; Handle relative times like "2 hours 35 minutes" 376 ;; Handle relative times like "2 hours 35 minutes".
360 (if (stringp time) 377 (when (stringp time)
361 (let ((secs (timer-duration time))) 378 (when-let ((secs (timer-duration time)))
362 (if secs 379 (setq time (timer-relative-time nil secs))))
363 (setq time (timer-relative-time nil secs))))) 380
364 381 ;; Handle "11:23pm" and the like. Interpret it as meaning today
365 ;; Handle "11:23pm" and the like. Interpret it as meaning today 382 ;; which admittedly is rather stupid if we have passed that time
366 ;; which admittedly is rather stupid if we have passed that time 383 ;; already. (Though only Emacs hackers hack Emacs at that time.)
367 ;; already. (Though only Emacs hackers hack Emacs at that time.) 384 (when (stringp time)
368 (if (stringp time) 385 (require 'diary-lib)
369 (progn 386 (let ((hhmm (diary-entry-time time))
370 (require 'diary-lib) 387 (now (decode-time)))
371 (let ((hhmm (diary-entry-time time)) 388 (when (>= hhmm 0)
372 (now (decode-time))) 389 (setq time (encode-time 0 (% hhmm 100) (/ hhmm 100)
373 (if (>= hhmm 0) 390 (decoded-time-day now)
374 (setq time 391 (decoded-time-month now)
375 (encode-time 0 (% hhmm 100) (/ hhmm 100) 392 (decoded-time-year now)
376 (decoded-time-day now) 393 (decoded-time-zone now))))))
377 (decoded-time-month now)
378 (decoded-time-year now)
379 (decoded-time-zone now)))))))
380 394
381 (let ((timer (timer-create)))
382 (timer-set-time timer time repeat) 395 (timer-set-time timer time repeat)
383 (timer-set-function timer function args) 396 (timer-set-function timer function args)
384 (timer-activate timer) 397 (timer-activate timer)
diff --git a/src/keyboard.c b/src/keyboard.c
index 2e4c4e6aabf..81ff9df153d 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -4234,7 +4234,7 @@ decode_timer (Lisp_Object timer, struct timespec *result)
4234{ 4234{
4235 Lisp_Object *vec; 4235 Lisp_Object *vec;
4236 4236
4237 if (! (VECTORP (timer) && ASIZE (timer) == 9)) 4237 if (! (VECTORP (timer) && ASIZE (timer) == 10))
4238 return false; 4238 return false;
4239 vec = XVECTOR (timer)->contents; 4239 vec = XVECTOR (timer)->contents;
4240 if (! NILP (vec[0])) 4240 if (! NILP (vec[0]))