diff options
| author | Paul Eggert | 2014-07-31 13:17:01 -0700 |
|---|---|---|
| committer | Paul Eggert | 2014-07-31 13:17:01 -0700 |
| commit | 5c6476b48a2d00bef6ada92fa210ac7cd1bc9a77 (patch) | |
| tree | 6f92d25b9731476c9aceab154149f8cf87def1e2 | |
| parent | f3655f35ccd5a56c158a5db399c5f168b2e928d0 (diff) | |
| download | emacs-5c6476b48a2d00bef6ada92fa210ac7cd1bc9a77.tar.gz emacs-5c6476b48a2d00bef6ada92fa210ac7cd1bc9a77.zip | |
Simplify timerfd configuration and fix some minor glitches.
* configure.ac (HAVE_TIMERFD): Define only if TFD_CLOEXEC works,
since the code leaked file descriptors to children when !TFD_CLOEXEC.
(HAVE_TIMERFD_CLOEXEC): Remove; no longer used.
* m4/clock_time.m4 (gl_CLOCK_TIME): Don't check for clock_getres.
This reverts the previous change to this file, so it matches
gnulib again.
* src/atimer.c (TIMERFD_CREATE_FLAGS): Remove; we now assume TFD_CLOEXEC.
(alarm_timer, alarm_timer_ok, set_alarm, init_atimer):
Fall back on timer_create if timerfd_create fails at runtime.
(resolution) [HAVE_CLOCK_GETRES]: Remove; we now rely on the
kernel primitives to do resolution. All uses removed.
(timerfd) [!HAVE_TIMERFD]: Define to be -1, for convenience.
(turn_on_atimers): Clear timer_create-based timers too,
for consistency.
| -rw-r--r-- | ChangeLog | 10 | ||||
| -rw-r--r-- | configure.ac | 33 | ||||
| -rw-r--r-- | m4/clock_time.m4 | 2 | ||||
| -rw-r--r-- | src/ChangeLog | 10 | ||||
| -rw-r--r-- | src/atimer.c | 124 |
5 files changed, 87 insertions, 92 deletions
| @@ -1,3 +1,13 @@ | |||
| 1 | 2014-07-31 Paul Eggert <eggert@cs.ucla.edu> | ||
| 2 | |||
| 3 | Simplify timerfd configuration and fix some minor glitches. | ||
| 4 | * configure.ac (HAVE_TIMERFD): Define only if TFD_CLOEXEC works, | ||
| 5 | since the code leaked file descriptors to children when !TFD_CLOEXEC. | ||
| 6 | (HAVE_TIMERFD_CLOEXEC): Remove; no longer used. | ||
| 7 | * m4/clock_time.m4 (gl_CLOCK_TIME): Don't check for clock_getres. | ||
| 8 | This reverts the previous change to this file, so it matches | ||
| 9 | gnulib again. | ||
| 10 | |||
| 1 | 2014-07-28 Dmitry Antipov <dmantipov@yandex.ru> | 11 | 2014-07-28 Dmitry Antipov <dmantipov@yandex.ru> |
| 2 | 12 | ||
| 3 | * configure.ac (toplevel): Check whether GNU/Linux-specific | 13 | * configure.ac (toplevel): Check whether GNU/Linux-specific |
diff --git a/configure.ac b/configure.ac index 89440446ee5..4f3fde56af2 100644 --- a/configure.ac +++ b/configure.ac | |||
| @@ -1539,7 +1539,7 @@ if test "$ac_cv_header_sys_sysinfo_h" = yes; then | |||
| 1539 | AC_DEFINE(LINUX_SYSINFO_UNIT, 1, | 1539 | AC_DEFINE(LINUX_SYSINFO_UNIT, 1, |
| 1540 | [Define to 1 if Linux sysinfo sizes are in multiples of mem_unit bytes.])) | 1540 | [Define to 1 if Linux sysinfo sizes are in multiples of mem_unit bytes.])) |
| 1541 | fi | 1541 | fi |
| 1542 | fi | 1542 | fi |
| 1543 | 1543 | ||
| 1544 | dnl On Solaris 8 there's a compilation warning for term.h because | 1544 | dnl On Solaris 8 there's a compilation warning for term.h because |
| 1545 | dnl it doesn't define `bool'. | 1545 | dnl it doesn't define `bool'. |
| @@ -3711,25 +3711,18 @@ AC_SUBST(LIBS_TERMCAP) | |||
| 3711 | AC_SUBST(TERMCAP_OBJ) | 3711 | AC_SUBST(TERMCAP_OBJ) |
| 3712 | 3712 | ||
| 3713 | # GNU/Linux-specific timer functions. | 3713 | # GNU/Linux-specific timer functions. |
| 3714 | if test $opsys = gnu-linux; then | 3714 | AC_CACHE_CHECK([for timerfd interface], [emacs_cv_have_timerfd], |
| 3715 | AC_MSG_CHECKING([whether Linux timerfd functions are supported]) | 3715 | [AC_COMPILE_IFELSE( |
| 3716 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/timerfd.h>]], | 3716 | [AC_LANG_PROGRAM([[#include <sys/timerfd.h> |
| 3717 | [[timerfd_create (CLOCK_REALTIME, 0); | 3717 | ]], |
| 3718 | timerfd_settime (0, 0, NULL, NULL)]])], | 3718 | [[timerfd_create (CLOCK_REALTIME, TFD_CLOEXEC); |
| 3719 | emacs_cv_linux_timerfd=yes, emacs_cv_linux_timerfd=no) | 3719 | timerfd_settime (0, TFD_TIMER_ABSTIME, 0, 0);]])], |
| 3720 | AC_MSG_RESULT([$emacs_cv_linux_timerfd]) | 3720 | [emacs_cv_have_timerfd=yes], |
| 3721 | if test $emacs_cv_linux_timerfd = yes; then | 3721 | [emacs_cv_have_timerfd=no])]) |
| 3722 | AC_DEFINE(HAVE_TIMERFD, 1, [Define to 1 if Linux timerfd functions are supported.]) | 3722 | if test "$emacs_cv_have_timerfd" = yes; then |
| 3723 | AC_MSG_CHECKING([whether TFD_CLOEXEC is defined]) | 3723 | AC_DEFINE([HAVE_TIMERFD], 1, |
| 3724 | AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/timerfd.h>]], | 3724 | [Define to 1 if timerfd functions are supported as in GNU/Linux.]) |
| 3725 | [[timerfd_create (CLOCK_REALTIME, TFD_CLOEXEC)]])], | 3725 | fi |
| 3726 | emacs_cv_tfd_cloexec=yes, emacs_cv_tfd_cloexec=no) | ||
| 3727 | AC_MSG_RESULT([$emacs_cv_tfd_cloexec]) | ||
| 3728 | if test $emacs_cv_tfd_cloexec = yes; then | ||
| 3729 | AC_DEFINE(HAVE_TIMERFD_CLOEXEC, 1, [Define to 1 if TFD_CLOEXEC is defined.]) | ||
| 3730 | fi | ||
| 3731 | fi | ||
| 3732 | fi | ||
| 3733 | 3726 | ||
| 3734 | # Do we have res_init, for detecting changes in /etc/resolv.conf? | 3727 | # Do we have res_init, for detecting changes in /etc/resolv.conf? |
| 3735 | # On Darwin, res_init appears not to be useful: see bug#562 and | 3728 | # On Darwin, res_init appears not to be useful: see bug#562 and |
diff --git a/m4/clock_time.m4 b/m4/clock_time.m4 index 8513c6d781a..6c4a637dc62 100644 --- a/m4/clock_time.m4 +++ b/m4/clock_time.m4 | |||
| @@ -26,6 +26,6 @@ AC_DEFUN([gl_CLOCK_TIME], | |||
| 26 | AC_SEARCH_LIBS([clock_gettime], [rt posix4], | 26 | AC_SEARCH_LIBS([clock_gettime], [rt posix4], |
| 27 | [test "$ac_cv_search_clock_gettime" = "none required" || | 27 | [test "$ac_cv_search_clock_gettime" = "none required" || |
| 28 | LIB_CLOCK_GETTIME=$ac_cv_search_clock_gettime]) | 28 | LIB_CLOCK_GETTIME=$ac_cv_search_clock_gettime]) |
| 29 | AC_CHECK_FUNCS([clock_getres clock_gettime clock_settime]) | 29 | AC_CHECK_FUNCS([clock_gettime clock_settime]) |
| 30 | LIBS=$gl_saved_libs | 30 | LIBS=$gl_saved_libs |
| 31 | ]) | 31 | ]) |
diff --git a/src/ChangeLog b/src/ChangeLog index 985e3b33e06..f3ab7f9b990 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,5 +1,15 @@ | |||
| 1 | 2014-07-31 Paul Eggert <eggert@cs.ucla.edu> | 1 | 2014-07-31 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 2 | ||
| 3 | Simplify timerfd configuration and fix some minor glitches. | ||
| 4 | * atimer.c (TIMERFD_CREATE_FLAGS): Remove; we now assume TFD_CLOEXEC. | ||
| 5 | (alarm_timer, alarm_timer_ok, set_alarm, init_atimer): | ||
| 6 | Fall back on timer_create if timerfd_create fails at runtime. | ||
| 7 | (resolution) [HAVE_CLOCK_GETRES]: Remove; we now rely on the | ||
| 8 | kernel primitives to do resolution. All uses removed. | ||
| 9 | (timerfd) [!HAVE_TIMERFD]: Define to be -1, for convenience. | ||
| 10 | (turn_on_atimers): Clear timer_create-based timers too, | ||
| 11 | for consistency. | ||
| 12 | |||
| 3 | * frame.c (x_set_frame_parameters): Don't use uninitialized locals. | 13 | * frame.c (x_set_frame_parameters): Don't use uninitialized locals. |
| 4 | Without this change, the code can access the local variable 'width' | 14 | Without this change, the code can access the local variable 'width' |
| 5 | even when it has not been initialized, and likewise for 'height'; | 15 | even when it has not been initialized, and likewise for 'height'; |
diff --git a/src/atimer.c b/src/atimer.c index c03ac96c6da..daac32f19b4 100644 --- a/src/atimer.c +++ b/src/atimer.c | |||
| @@ -27,13 +27,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 27 | #include <unistd.h> | 27 | #include <unistd.h> |
| 28 | 28 | ||
| 29 | #ifdef HAVE_TIMERFD | 29 | #ifdef HAVE_TIMERFD |
| 30 | #include <sys/timerfd.h> | 30 | # include <sys/timerfd.h> |
| 31 | #ifdef HAVE_TIMERFD_CLOEXEC | 31 | #endif |
| 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 | 32 | ||
| 38 | /* Free-list of atimer structures. */ | 33 | /* Free-list of atimer structures. */ |
| 39 | 34 | ||
| @@ -49,23 +44,18 @@ static struct atimer *stopped_atimers; | |||
| 49 | 44 | ||
| 50 | static struct atimer *atimers; | 45 | static struct atimer *atimers; |
| 51 | 46 | ||
| 52 | #if defined (HAVE_TIMERFD) | 47 | #ifdef HAVE_ITIMERSPEC |
| 53 | /* File descriptor returned by timerfd_create. GNU/Linux-specific. */ | 48 | /* The alarm timer and whether it was properly initialized, if |
| 54 | static int timerfd; | 49 | POSIX timers are available. */ |
| 55 | #elif defined (HAVE_ITIMERSPEC) | ||
| 56 | /* The alarm timer used if POSIX timers are available. */ | ||
| 57 | static timer_t alarm_timer; | 50 | static timer_t alarm_timer; |
| 58 | #endif | 51 | static bool alarm_timer_ok; |
| 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 | 52 | ||
| 66 | #ifdef HAVE_CLOCK_GETRES | 53 | # ifdef HAVE_TIMERFD |
| 67 | /* Resolution of CLOCK_REALTIME clock. */ | 54 | /* File descriptor for timer, or -1 if it could not be created. */ |
| 68 | static struct timespec resolution; | 55 | static int timerfd; |
| 56 | # else | ||
| 57 | enum { timerfd = -1 }; | ||
| 58 | # endif | ||
| 69 | #endif | 59 | #endif |
| 70 | 60 | ||
| 71 | /* Block/unblock SIGALRM. */ | 61 | /* Block/unblock SIGALRM. */ |
| @@ -92,20 +82,20 @@ static void schedule_atimer (struct atimer *); | |||
| 92 | static struct atimer *append_atimer_lists (struct atimer *, | 82 | static struct atimer *append_atimer_lists (struct atimer *, |
| 93 | struct atimer *); | 83 | struct atimer *); |
| 94 | 84 | ||
| 95 | /* Start a new atimer of type TYPE. TIME specifies when the timer is | 85 | /* Start a new atimer of type TYPE. TIMESTAMP specifies when the timer is |
| 96 | ripe. FN is the function to call when the timer fires. | 86 | ripe. FN is the function to call when the timer fires. |
| 97 | CLIENT_DATA is stored in the client_data member of the atimer | 87 | CLIENT_DATA is stored in the client_data member of the atimer |
| 98 | structure returned and so made available to FN when it is called. | 88 | structure returned and so made available to FN when it is called. |
| 99 | 89 | ||
| 100 | If TYPE is ATIMER_ABSOLUTE, TIME is the absolute time at which the | 90 | If TYPE is ATIMER_ABSOLUTE, TIMESTAMP is the absolute time at which the |
| 101 | timer fires. | 91 | timer fires. |
| 102 | 92 | ||
| 103 | If TYPE is ATIMER_RELATIVE, the timer is ripe TIME s/us in the | 93 | If TYPE is ATIMER_RELATIVE, the timer is ripe TIMESTAMP seconds in the |
| 104 | future. | 94 | future. |
| 105 | 95 | ||
| 106 | In both cases, the timer is automatically freed after it has fired. | 96 | In both cases, the timer is automatically freed after it has fired. |
| 107 | 97 | ||
| 108 | If TYPE is ATIMER_CONTINUOUS, the timer fires every TIME s/us. | 98 | If TYPE is ATIMER_CONTINUOUS, the timer fires every TIMESTAMP seconds. |
| 109 | 99 | ||
| 110 | Value is a pointer to the atimer started. It can be used in calls | 100 | Value is a pointer to the atimer started. It can be used in calls |
| 111 | to cancel_atimer; don't free it yourself. */ | 101 | to cancel_atimer; don't free it yourself. */ |
| @@ -117,16 +107,10 @@ start_atimer (enum atimer_type type, struct timespec timestamp, | |||
| 117 | struct atimer *t; | 107 | struct atimer *t; |
| 118 | sigset_t oldset; | 108 | sigset_t oldset; |
| 119 | 109 | ||
| 120 | #if !defined (HAVE_SETITIMER) | 110 | /* Round TIMESTAMP up to the next full second if we don't have itimers. */ |
| 121 | /* Round TIME up to the next full second if we don't have itimers. */ | 111 | #ifndef HAVE_SETITIMER |
| 122 | if (timestamp.tv_nsec != 0 && timestamp.tv_sec < TYPE_MAXIMUM (time_t)) | 112 | if (timestamp.tv_nsec != 0 && timestamp.tv_sec < TYPE_MAXIMUM (time_t)) |
| 123 | timestamp = make_timespec (timestamp.tv_sec + 1, 0); | 113 | 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; | ||
| 130 | #endif /* not HAVE_SETITIMER */ | 114 | #endif /* not HAVE_SETITIMER */ |
| 131 | 115 | ||
| 132 | /* Get an atimer structure from the free-list, or allocate | 116 | /* Get an atimer structure from the free-list, or allocate |
| @@ -311,25 +295,24 @@ set_alarm (void) | |||
| 311 | #endif | 295 | #endif |
| 312 | struct timespec now, interval; | 296 | struct timespec now, interval; |
| 313 | 297 | ||
| 314 | #if defined (HAVE_TIMERFD) || defined (HAVE_ITIMERSPEC) | 298 | #ifdef HAVE_ITIMERSPEC |
| 315 | if (special_timer_available) | 299 | if (0 <= timerfd || alarm_timer_ok) |
| 316 | { | 300 | { |
| 317 | struct itimerspec ispec; | 301 | struct itimerspec ispec; |
| 318 | ispec.it_value = atimers->expiration; | 302 | ispec.it_value = atimers->expiration; |
| 319 | ispec.it_interval.tv_sec = ispec.it_interval.tv_nsec = 0; | 303 | ispec.it_interval.tv_sec = ispec.it_interval.tv_nsec = 0; |
| 320 | #if defined (HAVE_TIMERFD) | 304 | # ifdef HAVE_TIMERFD |
| 321 | if (special_timer_available == 1) | 305 | if (timerfd_settime (timerfd, TFD_TIMER_ABSTIME, &ispec, 0) == 0) |
| 322 | { | 306 | { |
| 323 | add_timer_wait_descriptor (timerfd); | 307 | add_timer_wait_descriptor (timerfd); |
| 324 | special_timer_available++; | 308 | return; |
| 325 | } | 309 | } |
| 326 | if (timerfd_settime (timerfd, TFD_TIMER_ABSTIME, &ispec, 0) == 0) | 310 | # endif |
| 327 | #elif defined (HAVE_ITIMERSPEC) | 311 | if (alarm_timer_ok |
| 328 | if (timer_settime (alarm_timer, TIMER_ABSTIME, &ispec, 0) == 0) | 312 | && timer_settime (alarm_timer, TIMER_ABSTIME, &ispec, 0) == 0) |
| 329 | #endif | ||
| 330 | return; | 313 | return; |
| 331 | } | 314 | } |
| 332 | #endif /* HAVE_TIMERFD || HAVE_ITIMERSPEC */ | 315 | #endif |
| 333 | 316 | ||
| 334 | /* Determine interval till the next timer is ripe. | 317 | /* Determine interval till the next timer is ripe. |
| 335 | Don't set the interval to 0; this disables the timer. */ | 318 | Don't set the interval to 0; this disables the timer. */ |
| @@ -453,15 +436,15 @@ turn_on_atimers (bool on) | |||
| 453 | set_alarm (); | 436 | set_alarm (); |
| 454 | else | 437 | else |
| 455 | { | 438 | { |
| 456 | #ifdef HAVE_TIMERFD | 439 | #ifdef HAVE_ITIMERSPEC |
| 457 | if (special_timer_available > 1) | 440 | struct itimerspec ispec; |
| 458 | { | 441 | memset (&ispec, 0, sizeof ispec); |
| 459 | struct itimerspec ispec; | 442 | if (alarm_timer_ok) |
| 460 | memset (&ispec, 0, sizeof (ispec)); | 443 | timer_settime (alarm_timer, TIMER_ABSTIME, &ispec, 0); |
| 461 | /* Writing zero expiration time should disarm it. */ | 444 | # ifdef HAVE_TIMERFD |
| 462 | timerfd_settime (timerfd, TFD_TIMER_ABSTIME, &ispec, 0); | 445 | timerfd_settime (timerfd, TFD_TIMER_ABSTIME, &ispec, 0); |
| 463 | } | 446 | # endif |
| 464 | #endif /* HAVE_TIMERFD */ | 447 | #endif |
| 465 | alarm (0); | 448 | alarm (0); |
| 466 | } | 449 | } |
| 467 | } | 450 | } |
| @@ -494,14 +477,14 @@ debug_timer_callback (struct atimer *t) | |||
| 494 | r->intime = 0; | 477 | r->intime = 0; |
| 495 | else if (result >= 0) | 478 | else if (result >= 0) |
| 496 | { | 479 | { |
| 497 | #ifdef HAVE_SETITIMER | 480 | #ifdef HAVE_SETITIMER |
| 498 | struct timespec delta = timespec_sub (now, r->expected); | 481 | struct timespec delta = timespec_sub (now, r->expected); |
| 499 | /* Too late if later than expected + 0.01s. FIXME: | 482 | /* Too late if later than expected + 0.01s. FIXME: |
| 500 | this should depend from system clock resolution. */ | 483 | this should depend from system clock resolution. */ |
| 501 | if (timespec_cmp (delta, make_timespec (0, 10000000)) > 0) | 484 | if (timespec_cmp (delta, make_timespec (0, 10000000)) > 0) |
| 502 | r->intime = 0; | 485 | r->intime = 0; |
| 503 | else | 486 | else |
| 504 | #endif /* HAVE_SETITIMER */ | 487 | #endif /* HAVE_SETITIMER */ |
| 505 | r->intime = 1; | 488 | r->intime = 1; |
| 506 | } | 489 | } |
| 507 | } | 490 | } |
| @@ -543,21 +526,20 @@ Return t if all self-tests are passed, nil otherwise. */) | |||
| 543 | void | 526 | void |
| 544 | init_atimer (void) | 527 | init_atimer (void) |
| 545 | { | 528 | { |
| 546 | #if defined (HAVE_TIMERFD) | 529 | #ifdef HAVE_ITIMERSPEC |
| 547 | timerfd = timerfd_create (CLOCK_REALTIME, TIMERFD_CREATE_FLAGS); | 530 | # ifdef HAVE_TIMERFD |
| 548 | special_timer_available = !!(timerfd != -1); | 531 | timerfd = timerfd_create (CLOCK_REALTIME, TFD_CLOEXEC); |
| 549 | #elif defined (HAVE_ITIMERSPEC) | 532 | # endif |
| 550 | struct sigevent sigev; | 533 | if (timerfd < 0) |
| 551 | sigev.sigev_notify = SIGEV_SIGNAL; | 534 | { |
| 552 | sigev.sigev_signo = SIGALRM; | 535 | struct sigevent sigev; |
| 553 | sigev.sigev_value.sival_ptr = &alarm_timer; | 536 | sigev.sigev_notify = SIGEV_SIGNAL; |
| 554 | special_timer_available | 537 | sigev.sigev_signo = SIGALRM; |
| 555 | = timer_create (CLOCK_REALTIME, &sigev, &alarm_timer) == 0; | 538 | sigev.sigev_value.sival_ptr = &alarm_timer; |
| 556 | #endif /* HAVE_TIMERFD */ | 539 | alarm_timer_ok |
| 557 | #ifdef HAVE_CLOCK_GETRES | 540 | = timer_create (CLOCK_REALTIME, &sigev, &alarm_timer) == 0; |
| 558 | if (clock_getres (CLOCK_REALTIME, &resolution)) | 541 | } |
| 559 | resolution = invalid_timespec (); | 542 | #endif |
| 560 | #endif | ||
| 561 | free_atimers = stopped_atimers = atimers = NULL; | 543 | free_atimers = stopped_atimers = atimers = NULL; |
| 562 | 544 | ||
| 563 | /* pending_signals is initialized in init_keyboard. */ | 545 | /* pending_signals is initialized in init_keyboard. */ |
| @@ -567,5 +549,5 @@ init_atimer (void) | |||
| 567 | 549 | ||
| 568 | #ifdef ENABLE_CHECKING | 550 | #ifdef ENABLE_CHECKING |
| 569 | defsubr (&Sdebug_timer_check); | 551 | defsubr (&Sdebug_timer_check); |
| 570 | #endif | 552 | #endif |
| 571 | } | 553 | } |