diff options
| author | Dmitry Antipov | 2014-07-28 10:28:15 +0400 |
|---|---|---|
| committer | Dmitry Antipov | 2014-07-28 10:28:15 +0400 |
| commit | 768b24eb0e880c0b39e36fd089905cdca572a758 (patch) | |
| tree | 75899b103fedc549e5d17294d39bfcb4ed0a9bc9 /src | |
| parent | 7daa4ff121ad8da6e609b959d5c95796e5d3a9eb (diff) | |
| download | emacs-768b24eb0e880c0b39e36fd089905cdca572a758.tar.gz emacs-768b24eb0e880c0b39e36fd089905cdca572a758.zip | |
On GNU/Linux, use timerfd for asynchronous timers.
* configure.ac (toplevel): Check whether GNU/Linux-specific
timerfd functions and macros are available.
* m4/clock_time.m4 (gl_CLOCK_TIME): Check for clock_getres as well.
* src/atimer.c (toplevel) [HAVE_TIMERFD]: Include sys/timerfd.h.
(toplevel): Rename alarm_timer_ok to special_timer_available.
[HAVE_TIMERFD]: Declare timerfd.
[HAVE_CLOCK_GETRES]: Declare resolution.
(start_atimer) [HAVE_CLOCK_GETRES]: Round up timestamp to
system timer resolution.
(set_alarm) [HAVE_TIMERFD]: Use timerfd_settime.
(timerfd_callback) [HAVE_TIMERFD]: New function.
(atimer_result, debug_timer_callback, Fdebug_timer_check)
[ENABLE_CHECKING]: New function for the sake of automated tests.
(init_atimer) [HAVE_TIMERFD]: Setup timerfd.
[HAVE_CLOCK_GETRES]: Likewise for system timer resolution.
[ENABLE_CHECKING]: Defsubr test function.
* src/atimer.h (timerfd_callback) [HAVE_TIMERFD]: Add prototype.
* src/lisp.h (add_timer_wait_descriptor) [HAVE_TIMERFD]: Likewise.
* src/process.c (add_timer_wait_descriptor) [HAVE_TIMERFD]: New function.
* test/automated/timer-tests.el (timer-tests-debug-timer-check): New test.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 20 | ||||
| -rw-r--r-- | src/atimer.c | 155 | ||||
| -rw-r--r-- | src/atimer.h | 3 | ||||
| -rw-r--r-- | src/lisp.h | 3 | ||||
| -rw-r--r-- | src/process.c | 18 |
5 files changed, 186 insertions, 13 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index b3f3750df75..ebc412c8869 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,23 @@ | |||
| 1 | 2014-07-28 Dmitry Antipov <dmantipov@yandex.ru> | ||
| 2 | |||
| 3 | On GNU/Linux, use timerfd for asynchronous timers. | ||
| 4 | * atimer.c (toplevel) [HAVE_TIMERFD]: Include sys/timerfd.h. | ||
| 5 | (toplevel): Rename alarm_timer_ok to special_timer_available. | ||
| 6 | [HAVE_TIMERFD]: Declare timerfd. | ||
| 7 | [HAVE_CLOCK_GETRES]: Declare resolution. | ||
| 8 | (start_atimer) [HAVE_CLOCK_GETRES]: Round up timestamp to | ||
| 9 | system timer resolution. | ||
| 10 | (set_alarm) [HAVE_TIMERFD]: Use timerfd_settime. | ||
| 11 | (timerfd_callback) [HAVE_TIMERFD]: New function. | ||
| 12 | (atimer_result, debug_timer_callback, Fdebug_timer_check) | ||
| 13 | [ENABLE_CHECKING]: New function for the sake of automated tests. | ||
| 14 | (init_atimer) [HAVE_TIMERFD]: Setup timerfd. | ||
| 15 | [HAVE_CLOCK_GETRES]: Likewise for system timer resolution. | ||
| 16 | [ENABLE_CHECKING]: Defsubr test function. | ||
| 17 | * atimer.h (timerfd_callback) [HAVE_TIMERFD]: Add prototype. | ||
| 18 | * lisp.h (add_timer_wait_descriptor) [HAVE_TIMERFD]: Likewise. | ||
| 19 | * process.c (add_timer_wait_descriptor) [HAVE_TIMERFD]: New function. | ||
| 20 | |||
| 1 | 2014-07-28 Paul Eggert <eggert@cs.ucla.edu> | 21 | 2014-07-28 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 22 | ||
| 3 | * frame.c (x_set_frame_parameters): Don't use uninitialized locals. | 23 | * frame.c (x_set_frame_parameters): Don't use uninitialized locals. |
diff --git a/src/atimer.c b/src/atimer.c index c4f062beb17..9079e7712e0 100644 --- a/src/atimer.c +++ b/src/atimer.c | |||
| @@ -26,6 +26,15 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 26 | #include "atimer.h" | 26 | #include "atimer.h" |
| 27 | #include <unistd.h> | 27 | #include <unistd.h> |
| 28 | 28 | ||
| 29 | #ifdef HAVE_TIMERFD | ||
| 30 | #include <sys/timerfd.h> | ||
| 31 | #ifdef HAVE_TIMERFD_CLOEXEC | ||
| 32 | #define TIMERFD_CREATE_FLAGS TFD_CLOEXEC | ||
| 33 | #else | ||
| 34 | #define TIMERFD_CREATE_FLAGS 0 | ||
| 35 | #endif /* HAVE_TIMERFD_CLOEXEC */ | ||
| 36 | #endif /* HAVE_TIMERFD */ | ||
| 37 | |||
| 29 | /* Free-list of atimer structures. */ | 38 | /* Free-list of atimer structures. */ |
| 30 | 39 | ||
| 31 | static struct atimer *free_atimers; | 40 | static struct atimer *free_atimers; |
| @@ -40,11 +49,23 @@ static struct atimer *stopped_atimers; | |||
| 40 | 49 | ||
| 41 | static struct atimer *atimers; | 50 | static struct atimer *atimers; |
| 42 | 51 | ||
| 43 | /* The alarm timer and whether it was properly initialized, if | 52 | #if defined (HAVE_TIMERFD) |
| 44 | POSIX timers are available. */ | 53 | /* File descriptor returned by timerfd_create. GNU/Linux-specific. */ |
| 45 | #ifdef HAVE_ITIMERSPEC | 54 | static int timerfd; |
| 55 | #elif defined (HAVE_ITIMERSPEC) | ||
| 56 | /* The alarm timer used if POSIX timers are available. */ | ||
| 46 | static timer_t alarm_timer; | 57 | static timer_t alarm_timer; |
| 47 | static bool alarm_timer_ok; | 58 | #endif |
| 59 | |||
| 60 | #if defined (HAVE_TIMERFD) || defined (HAVE_ITIMERSPEC) | ||
| 61 | /* Non-zero if one of the above was successfully initialized. Do not | ||
| 62 | use bool due to special treatment if HAVE_TIMERFD, see below. */ | ||
| 63 | static int special_timer_available; | ||
| 64 | #endif | ||
| 65 | |||
| 66 | #ifdef HAVE_CLOCK_GETRES | ||
| 67 | /* Resolution of CLOCK_REALTIME clock. */ | ||
| 68 | static struct timespec resolution; | ||
| 48 | #endif | 69 | #endif |
| 49 | 70 | ||
| 50 | /* Block/unblock SIGALRM. */ | 71 | /* Block/unblock SIGALRM. */ |
| @@ -96,11 +117,16 @@ start_atimer (enum atimer_type type, struct timespec timestamp, | |||
| 96 | struct atimer *t; | 117 | struct atimer *t; |
| 97 | sigset_t oldset; | 118 | sigset_t oldset; |
| 98 | 119 | ||
| 99 | /* Round TIME up to the next full second if we don't have | 120 | #if !defined (HAVE_SETITIMER) |
| 100 | itimers. */ | 121 | /* Round TIME up to the next full second if we don't have itimers. */ |
| 101 | #ifndef HAVE_SETITIMER | ||
| 102 | if (timestamp.tv_nsec != 0 && timestamp.tv_sec < TYPE_MAXIMUM (time_t)) | 122 | if (timestamp.tv_nsec != 0 && timestamp.tv_sec < TYPE_MAXIMUM (time_t)) |
| 103 | timestamp = make_timespec (timestamp.tv_sec + 1, 0); | 123 | timestamp = make_timespec (timestamp.tv_sec + 1, 0); |
| 124 | #elif defined (HAVE_CLOCK_GETRES) | ||
| 125 | /* Check that the system clock is precise enough. If | ||
| 126 | not, round TIME up to the system clock resolution. */ | ||
| 127 | if (timespec_valid_p (resolution) | ||
| 128 | && timespec_cmp (timestamp, resolution) < 0) | ||
| 129 | timestamp = resolution; | ||
| 104 | #endif /* not HAVE_SETITIMER */ | 130 | #endif /* not HAVE_SETITIMER */ |
| 105 | 131 | ||
| 106 | /* Get an atimer structure from the free-list, or allocate | 132 | /* Get an atimer structure from the free-list, or allocate |
| @@ -285,16 +311,25 @@ set_alarm (void) | |||
| 285 | #endif | 311 | #endif |
| 286 | struct timespec now, interval; | 312 | struct timespec now, interval; |
| 287 | 313 | ||
| 288 | #ifdef HAVE_ITIMERSPEC | 314 | #if defined (HAVE_TIMERFD) || defined (HAVE_ITIMERSPEC) |
| 289 | if (alarm_timer_ok) | 315 | if (special_timer_available) |
| 290 | { | 316 | { |
| 291 | struct itimerspec ispec; | 317 | struct itimerspec ispec; |
| 292 | ispec.it_value = atimers->expiration; | 318 | ispec.it_value = atimers->expiration; |
| 293 | ispec.it_interval.tv_sec = ispec.it_interval.tv_nsec = 0; | 319 | ispec.it_interval.tv_sec = ispec.it_interval.tv_nsec = 0; |
| 320 | #if defined (HAVE_TIMERFD) | ||
| 321 | if (special_timer_available == 1) | ||
| 322 | { | ||
| 323 | add_timer_wait_descriptor (timerfd); | ||
| 324 | special_timer_available++; | ||
| 325 | } | ||
| 326 | if (timerfd_settime (timerfd, TFD_TIMER_ABSTIME, &ispec, 0) == 0) | ||
| 327 | #elif defined (HAVE_ITIMERSPEC) | ||
| 294 | if (timer_settime (alarm_timer, TIMER_ABSTIME, &ispec, 0) == 0) | 328 | if (timer_settime (alarm_timer, TIMER_ABSTIME, &ispec, 0) == 0) |
| 329 | #endif | ||
| 295 | return; | 330 | return; |
| 296 | } | 331 | } |
| 297 | #endif | 332 | #endif /* HAVE_TIMERFD || HAVE_ITIMERSPEC */ |
| 298 | 333 | ||
| 299 | /* Determine interval till the next timer is ripe. | 334 | /* Determine interval till the next timer is ripe. |
| 300 | Don't set the interval to 0; this disables the timer. */ | 335 | Don't set the interval to 0; this disables the timer. */ |
| @@ -373,6 +408,15 @@ handle_alarm_signal (int sig) | |||
| 373 | pending_signals = 1; | 408 | pending_signals = 1; |
| 374 | } | 409 | } |
| 375 | 410 | ||
| 411 | #ifdef HAVE_TIMERFD | ||
| 412 | |||
| 413 | void | ||
| 414 | timerfd_callback (int fd, void *arg) | ||
| 415 | { | ||
| 416 | do_pending_atimers (); | ||
| 417 | } | ||
| 418 | |||
| 419 | #endif /* HAVE_TIMERFD */ | ||
| 376 | 420 | ||
| 377 | /* Do pending timers. */ | 421 | /* Do pending timers. */ |
| 378 | 422 | ||
| @@ -401,21 +445,106 @@ turn_on_atimers (bool on) | |||
| 401 | alarm (0); | 445 | alarm (0); |
| 402 | } | 446 | } |
| 403 | 447 | ||
| 448 | /* This is intended to use from automated tests. */ | ||
| 449 | |||
| 450 | #ifdef ENABLE_CHECKING | ||
| 451 | |||
| 452 | #define MAXTIMERS 10 | ||
| 453 | |||
| 454 | struct atimer_result | ||
| 455 | { | ||
| 456 | /* Time when we expect this timer to trigger. */ | ||
| 457 | struct timespec expected; | ||
| 458 | |||
| 459 | /* Timer status: -1 if not triggered, 0 if triggered | ||
| 460 | too early or too late, 1 if triggered timely. */ | ||
| 461 | int intime; | ||
| 462 | }; | ||
| 463 | |||
| 464 | static void | ||
| 465 | debug_timer_callback (struct atimer *t) | ||
| 466 | { | ||
| 467 | struct timespec now = current_timespec (); | ||
| 468 | struct atimer_result *r = (struct atimer_result *) t->client_data; | ||
| 469 | int result = timespec_cmp (now, r->expected); | ||
| 470 | |||
| 471 | if (result < 0) | ||
| 472 | /* Too early. */ | ||
| 473 | r->intime = 0; | ||
| 474 | else if (result >= 0) | ||
| 475 | { | ||
| 476 | #ifdef HAVE_SETITIMER | ||
| 477 | struct timespec delta = timespec_sub (now, r->expected); | ||
| 478 | /* Too late if later than expected + 0.01s. FIXME: | ||
| 479 | this should depend from system clock resolution. */ | ||
| 480 | if (timespec_cmp (delta, make_timespec (0, 10000000)) > 0) | ||
| 481 | r->intime = 0; | ||
| 482 | else | ||
| 483 | #endif /* HAVE_SETITIMER */ | ||
| 484 | r->intime = 1; | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 488 | DEFUN ("debug-timer-check", Fdebug_timer_check, Sdebug_timer_check, 0, 0, 0, | ||
| 489 | doc: /* Run internal self-tests to check timers subsystem. | ||
| 490 | Return t if all self-tests are passed, nil otherwise. */) | ||
| 491 | (void) | ||
| 492 | { | ||
| 493 | int i, ok; | ||
| 494 | struct atimer *timer; | ||
| 495 | struct atimer_result *results[MAXTIMERS]; | ||
| 496 | struct timespec t = make_timespec (0, 0); | ||
| 497 | |||
| 498 | /* Arm MAXTIMERS relative timers to trigger with 0.1s intervals. */ | ||
| 499 | for (i = 0; i < MAXTIMERS; i++) | ||
| 500 | { | ||
| 501 | results[i] = xmalloc (sizeof (struct atimer_result)); | ||
| 502 | t = timespec_add (t, make_timespec (0, 100000000)); | ||
| 503 | results[i]->expected = timespec_add (current_timespec (), t); | ||
| 504 | results[i]->intime = -1; | ||
| 505 | timer = start_atimer (ATIMER_RELATIVE, t, | ||
| 506 | debug_timer_callback, results[i]); | ||
| 507 | } | ||
| 508 | |||
| 509 | /* Wait for 1s but process timers. */ | ||
| 510 | wait_reading_process_output (1, 0, 0, false, Qnil, NULL, 0); | ||
| 511 | /* Shut up the compiler by "using" this variable. */ | ||
| 512 | (void) timer; | ||
| 513 | |||
| 514 | for (i = 0, ok = 0; i < MAXTIMERS; i++) | ||
| 515 | ok += results[i]->intime, xfree (results[i]); | ||
| 516 | |||
| 517 | return ok == MAXTIMERS ? Qt : Qnil; | ||
| 518 | } | ||
| 519 | |||
| 520 | #endif /* ENABLE_CHECKING */ | ||
| 404 | 521 | ||
| 405 | void | 522 | void |
| 406 | init_atimer (void) | 523 | init_atimer (void) |
| 407 | { | 524 | { |
| 408 | #ifdef HAVE_ITIMERSPEC | 525 | #if defined (HAVE_TIMERFD) |
| 526 | timerfd = timerfd_create (CLOCK_REALTIME, TIMERFD_CREATE_FLAGS); | ||
| 527 | special_timer_available = !!(timerfd != -1); | ||
| 528 | #elif defined (HAVE_ITIMERSPEC) | ||
| 409 | struct sigevent sigev; | 529 | struct sigevent sigev; |
| 410 | sigev.sigev_notify = SIGEV_SIGNAL; | 530 | sigev.sigev_notify = SIGEV_SIGNAL; |
| 411 | sigev.sigev_signo = SIGALRM; | 531 | sigev.sigev_signo = SIGALRM; |
| 412 | sigev.sigev_value.sival_ptr = &alarm_timer; | 532 | sigev.sigev_value.sival_ptr = &alarm_timer; |
| 413 | alarm_timer_ok = timer_create (CLOCK_REALTIME, &sigev, &alarm_timer) == 0; | 533 | special_timer_available |
| 414 | #endif | 534 | = timer_create (CLOCK_REALTIME, &sigev, &alarm_timer) == 0; |
| 535 | #endif /* HAVE_TIMERFD */ | ||
| 536 | #ifdef HAVE_CLOCK_GETRES | ||
| 537 | if (clock_getres (CLOCK_REALTIME, &resolution)) | ||
| 538 | resolution = invalid_timespec (); | ||
| 539 | #endif | ||
| 415 | free_atimers = stopped_atimers = atimers = NULL; | 540 | free_atimers = stopped_atimers = atimers = NULL; |
| 416 | 541 | ||
| 417 | /* pending_signals is initialized in init_keyboard. */ | 542 | /* pending_signals is initialized in init_keyboard. */ |
| 418 | struct sigaction action; | 543 | struct sigaction action; |
| 419 | emacs_sigaction_init (&action, handle_alarm_signal); | 544 | emacs_sigaction_init (&action, handle_alarm_signal); |
| 420 | sigaction (SIGALRM, &action, 0); | 545 | sigaction (SIGALRM, &action, 0); |
| 546 | |||
| 547 | #ifdef ENABLE_CHECKING | ||
| 548 | defsubr (&Sdebug_timer_check); | ||
| 549 | #endif | ||
| 421 | } | 550 | } |
diff --git a/src/atimer.h b/src/atimer.h index 379787abca7..2386977cf87 100644 --- a/src/atimer.h +++ b/src/atimer.h | |||
| @@ -77,5 +77,8 @@ void init_atimer (void); | |||
| 77 | void turn_on_atimers (bool); | 77 | void turn_on_atimers (bool); |
| 78 | void stop_other_atimers (struct atimer *); | 78 | void stop_other_atimers (struct atimer *); |
| 79 | void run_all_atimers (void); | 79 | void run_all_atimers (void); |
| 80 | #ifdef HAVE_TIMERFD | ||
| 81 | void timerfd_callback (int, void *); | ||
| 82 | #endif | ||
| 80 | 83 | ||
| 81 | #endif /* EMACS_ATIMER_H */ | 84 | #endif /* EMACS_ATIMER_H */ |
diff --git a/src/lisp.h b/src/lisp.h index bf25f073d4b..67299706c6b 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -4186,6 +4186,9 @@ extern int wait_reading_process_output (intmax_t, int, int, bool, Lisp_Object, | |||
| 4186 | #else | 4186 | #else |
| 4187 | # define WAIT_READING_MAX INTMAX_MAX | 4187 | # define WAIT_READING_MAX INTMAX_MAX |
| 4188 | #endif | 4188 | #endif |
| 4189 | #ifdef HAVE_TIMERFD | ||
| 4190 | extern void add_timer_wait_descriptor (int); | ||
| 4191 | #endif | ||
| 4189 | extern void add_keyboard_wait_descriptor (int); | 4192 | extern void add_keyboard_wait_descriptor (int); |
| 4190 | extern void delete_keyboard_wait_descriptor (int); | 4193 | extern void delete_keyboard_wait_descriptor (int); |
| 4191 | #ifdef HAVE_GPM | 4194 | #ifdef HAVE_GPM |
diff --git a/src/process.c b/src/process.c index 4449493a2b6..cfc1e189cab 100644 --- a/src/process.c +++ b/src/process.c | |||
| @@ -6827,6 +6827,24 @@ wait_reading_process_output (intmax_t time_limit, int nsecs, int read_kbd, | |||
| 6827 | /* The following functions are needed even if async subprocesses are | 6827 | /* The following functions are needed even if async subprocesses are |
| 6828 | not supported. Some of them are no-op stubs in that case. */ | 6828 | not supported. Some of them are no-op stubs in that case. */ |
| 6829 | 6829 | ||
| 6830 | #ifdef HAVE_TIMERFD | ||
| 6831 | |||
| 6832 | /* Add FD, which is a descriptor returned by timerfd_create, | ||
| 6833 | to the set of non-keyboard input descriptors. */ | ||
| 6834 | |||
| 6835 | void | ||
| 6836 | add_timer_wait_descriptor (int fd) | ||
| 6837 | { | ||
| 6838 | FD_SET (fd, &non_keyboard_wait_mask); | ||
| 6839 | fd_callback_info[fd].func = timerfd_callback; | ||
| 6840 | fd_callback_info[fd].data = NULL; | ||
| 6841 | fd_callback_info[fd].condition |= FOR_READ; | ||
| 6842 | if (fd > max_input_desc) | ||
| 6843 | max_input_desc = fd; | ||
| 6844 | } | ||
| 6845 | |||
| 6846 | #endif /* HAVE_TIMERFD */ | ||
| 6847 | |||
| 6830 | /* Add DESC to the set of keyboard input descriptors. */ | 6848 | /* Add DESC to the set of keyboard input descriptors. */ |
| 6831 | 6849 | ||
| 6832 | void | 6850 | void |