mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-04-27 16:51:06 -07:00
Fix atimer setting and overdue expiration (bug#55628)
* src/atimer.c (set_alarm): If the atimer has already expired, signal it right away instead of postponing it further. Previously this could occur repeatedly, blocking atimers indefinitely. Also only use `alarm` as fallback if `setitimer` is unavailable, not both at the same time (which makes no sense, and they both typically use the same mechanism behind the curtains). * test/src/eval-tests.el (eval-tests/funcall-with-delayed-message): New test, verifying proper functioning of funcall-with-delayed-message which also serves as test for this bug (which also caused debug-timer-check to fail, but that test is only run when Emacs is built with enable-checking).
This commit is contained in:
parent
78e8893f5d
commit
169797a300
2 changed files with 43 additions and 17 deletions
33
src/atimer.c
33
src/atimer.c
|
|
@ -297,11 +297,6 @@ set_alarm (void)
|
|||
{
|
||||
if (atimers)
|
||||
{
|
||||
#ifdef HAVE_SETITIMER
|
||||
struct itimerval it;
|
||||
#endif
|
||||
struct timespec now, interval;
|
||||
|
||||
#ifdef HAVE_ITIMERSPEC
|
||||
if (0 <= timerfd || alarm_timer_ok)
|
||||
{
|
||||
|
|
@ -337,20 +332,24 @@ set_alarm (void)
|
|||
}
|
||||
#endif
|
||||
|
||||
/* Determine interval till the next timer is ripe.
|
||||
Don't set the interval to 0; this disables the timer. */
|
||||
now = current_timespec ();
|
||||
interval = (timespec_cmp (atimers->expiration, now) <= 0
|
||||
? make_timespec (0, 1000 * 1000)
|
||||
: timespec_sub (atimers->expiration, now));
|
||||
/* Determine interval till the next timer is ripe. */
|
||||
struct timespec now = current_timespec ();
|
||||
if (timespec_cmp (atimers->expiration, now) <= 0)
|
||||
{
|
||||
/* Timer is (over)due -- just trigger the signal right way. */
|
||||
raise (SIGALRM);
|
||||
}
|
||||
else
|
||||
{
|
||||
struct timespec interval = timespec_sub (atimers->expiration, now);
|
||||
|
||||
#ifdef HAVE_SETITIMER
|
||||
|
||||
memset (&it, 0, sizeof it);
|
||||
it.it_value = make_timeval (interval);
|
||||
setitimer (ITIMER_REAL, &it, 0);
|
||||
#endif /* not HAVE_SETITIMER */
|
||||
alarm (max (interval.tv_sec, 1));
|
||||
struct itimerval it = {.it_value = make_timeval (interval)};
|
||||
setitimer (ITIMER_REAL, &it, 0);
|
||||
#else
|
||||
alarm (max (interval.tv_sec, 1));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -240,4 +240,31 @@ expressions works for identifiers starting with period."
|
|||
(should (equal (string-trim (buffer-string))
|
||||
"Error: (error \"Boo\")")))))
|
||||
|
||||
(ert-deftest eval-tests/funcall-with-delayed-message ()
|
||||
;; Check that `funcall-with-delayed-message' displays its message before
|
||||
;; its function terminates iff the timeout is short enough.
|
||||
|
||||
;; This also serves as regression test for bug#55628 where a short
|
||||
;; timeout was rounded up to the next whole second.
|
||||
(dolist (params '((0.8 0.4)
|
||||
(0.1 0.8)))
|
||||
(let ((timeout (nth 0 params))
|
||||
(work-time (nth 1 params)))
|
||||
(ert-info ((prin1-to-string params) :prefix "params: ")
|
||||
(with-current-buffer "*Messages*"
|
||||
(let ((inhibit-read-only t))
|
||||
(erase-buffer))
|
||||
(let ((stop (+ (float-time) work-time)))
|
||||
(funcall-with-delayed-message
|
||||
timeout "timed out"
|
||||
(lambda ()
|
||||
(while (< (float-time) stop))
|
||||
(message "finished"))))
|
||||
(let ((expected-messages
|
||||
(if (< timeout work-time)
|
||||
"timed out\nfinished"
|
||||
"finished")))
|
||||
(should (equal (string-trim (buffer-string))
|
||||
expected-messages))))))))
|
||||
|
||||
;;; eval-tests.el ends here
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue