aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDmitry Antipov2014-07-28 10:28:15 +0400
committerDmitry Antipov2014-07-28 10:28:15 +0400
commit768b24eb0e880c0b39e36fd089905cdca572a758 (patch)
tree75899b103fedc549e5d17294d39bfcb4ed0a9bc9 /src
parent7daa4ff121ad8da6e609b959d5c95796e5d3a9eb (diff)
downloademacs-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/ChangeLog20
-rw-r--r--src/atimer.c155
-rw-r--r--src/atimer.h3
-rw-r--r--src/lisp.h3
-rw-r--r--src/process.c18
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 @@
12014-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
12014-07-28 Paul Eggert <eggert@cs.ucla.edu> 212014-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
31static struct atimer *free_atimers; 40static struct atimer *free_atimers;
@@ -40,11 +49,23 @@ static struct atimer *stopped_atimers;
40 49
41static struct atimer *atimers; 50static 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 54static int timerfd;
55#elif defined (HAVE_ITIMERSPEC)
56/* The alarm timer used if POSIX timers are available. */
46static timer_t alarm_timer; 57static timer_t alarm_timer;
47static 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. */
63static int special_timer_available;
64#endif
65
66#ifdef HAVE_CLOCK_GETRES
67/* Resolution of CLOCK_REALTIME clock. */
68static 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
413void
414timerfd_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
454struct 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
464static void
465debug_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
488DEFUN ("debug-timer-check", Fdebug_timer_check, Sdebug_timer_check, 0, 0, 0,
489 doc: /* Run internal self-tests to check timers subsystem.
490Return 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
405void 522void
406init_atimer (void) 523init_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);
77void turn_on_atimers (bool); 77void turn_on_atimers (bool);
78void stop_other_atimers (struct atimer *); 78void stop_other_atimers (struct atimer *);
79void run_all_atimers (void); 79void run_all_atimers (void);
80#ifdef HAVE_TIMERFD
81void 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
4190extern void add_timer_wait_descriptor (int);
4191#endif
4189extern void add_keyboard_wait_descriptor (int); 4192extern void add_keyboard_wait_descriptor (int);
4190extern void delete_keyboard_wait_descriptor (int); 4193extern 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
6835void
6836add_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
6832void 6850void