diff options
| author | Mattias EngdegÄrd | 2022-05-30 12:25:19 +0200 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2022-05-30 15:52:02 +0200 |
| commit | 169797a3002fae1e86ee799475cd4f1b7ef9a3d1 (patch) | |
| tree | 10a3b1f0b2509520dc4839e41f8d112317377f33 /src | |
| parent | 78e8893f5d4b1c9ca5742fbe20bc5d05a843ed4e (diff) | |
| download | emacs-169797a3002fae1e86ee799475cd4f1b7ef9a3d1.tar.gz emacs-169797a3002fae1e86ee799475cd4f1b7ef9a3d1.zip | |
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).
Diffstat (limited to 'src')
| -rw-r--r-- | src/atimer.c | 33 |
1 files changed, 16 insertions, 17 deletions
diff --git a/src/atimer.c b/src/atimer.c index 1c6c881fc02..c26904e1f01 100644 --- a/src/atimer.c +++ b/src/atimer.c | |||
| @@ -297,11 +297,6 @@ set_alarm (void) | |||
| 297 | { | 297 | { |
| 298 | if (atimers) | 298 | if (atimers) |
| 299 | { | 299 | { |
| 300 | #ifdef HAVE_SETITIMER | ||
| 301 | struct itimerval it; | ||
| 302 | #endif | ||
| 303 | struct timespec now, interval; | ||
| 304 | |||
| 305 | #ifdef HAVE_ITIMERSPEC | 300 | #ifdef HAVE_ITIMERSPEC |
| 306 | if (0 <= timerfd || alarm_timer_ok) | 301 | if (0 <= timerfd || alarm_timer_ok) |
| 307 | { | 302 | { |
| @@ -337,20 +332,24 @@ set_alarm (void) | |||
| 337 | } | 332 | } |
| 338 | #endif | 333 | #endif |
| 339 | 334 | ||
| 340 | /* Determine interval till the next timer is ripe. | 335 | /* Determine interval till the next timer is ripe. */ |
| 341 | Don't set the interval to 0; this disables the timer. */ | 336 | struct timespec now = current_timespec (); |
| 342 | now = current_timespec (); | 337 | if (timespec_cmp (atimers->expiration, now) <= 0) |
| 343 | interval = (timespec_cmp (atimers->expiration, now) <= 0 | 338 | { |
| 344 | ? make_timespec (0, 1000 * 1000) | 339 | /* Timer is (over)due -- just trigger the signal right way. */ |
| 345 | : timespec_sub (atimers->expiration, now)); | 340 | raise (SIGALRM); |
| 341 | } | ||
| 342 | else | ||
| 343 | { | ||
| 344 | struct timespec interval = timespec_sub (atimers->expiration, now); | ||
| 346 | 345 | ||
| 347 | #ifdef HAVE_SETITIMER | 346 | #ifdef HAVE_SETITIMER |
| 348 | 347 | struct itimerval it = {.it_value = make_timeval (interval)}; | |
| 349 | memset (&it, 0, sizeof it); | 348 | setitimer (ITIMER_REAL, &it, 0); |
| 350 | it.it_value = make_timeval (interval); | 349 | #else |
| 351 | setitimer (ITIMER_REAL, &it, 0); | 350 | alarm (max (interval.tv_sec, 1)); |
| 352 | #endif /* not HAVE_SETITIMER */ | 351 | #endif |
| 353 | alarm (max (interval.tv_sec, 1)); | 352 | } |
| 354 | } | 353 | } |
| 355 | } | 354 | } |
| 356 | 355 | ||