Commit 5c6476b4 authored by Paul Eggert's avatar Paul Eggert

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.
parent f3655f35
2014-07-31 Paul Eggert <eggert@cs.ucla.edu>
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.
2014-07-28 Dmitry Antipov <dmantipov@yandex.ru> 2014-07-28 Dmitry Antipov <dmantipov@yandex.ru>
* configure.ac (toplevel): Check whether GNU/Linux-specific * configure.ac (toplevel): Check whether GNU/Linux-specific
......
...@@ -1539,7 +1539,7 @@ if test "$ac_cv_header_sys_sysinfo_h" = yes; then ...@@ -1539,7 +1539,7 @@ if test "$ac_cv_header_sys_sysinfo_h" = yes; then
AC_DEFINE(LINUX_SYSINFO_UNIT, 1, AC_DEFINE(LINUX_SYSINFO_UNIT, 1,
[Define to 1 if Linux sysinfo sizes are in multiples of mem_unit bytes.])) [Define to 1 if Linux sysinfo sizes are in multiples of mem_unit bytes.]))
fi fi
fi fi
dnl On Solaris 8 there's a compilation warning for term.h because dnl On Solaris 8 there's a compilation warning for term.h because
dnl it doesn't define `bool'. dnl it doesn't define `bool'.
...@@ -3711,25 +3711,18 @@ AC_SUBST(LIBS_TERMCAP) ...@@ -3711,25 +3711,18 @@ AC_SUBST(LIBS_TERMCAP)
AC_SUBST(TERMCAP_OBJ) AC_SUBST(TERMCAP_OBJ)
# GNU/Linux-specific timer functions. # GNU/Linux-specific timer functions.
if test $opsys = gnu-linux; then AC_CACHE_CHECK([for timerfd interface], [emacs_cv_have_timerfd],
AC_MSG_CHECKING([whether Linux timerfd functions are supported]) [AC_COMPILE_IFELSE(
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/timerfd.h>]], [AC_LANG_PROGRAM([[#include <sys/timerfd.h>
[[timerfd_create (CLOCK_REALTIME, 0); ]],
timerfd_settime (0, 0, NULL, NULL)]])], [[timerfd_create (CLOCK_REALTIME, TFD_CLOEXEC);
emacs_cv_linux_timerfd=yes, emacs_cv_linux_timerfd=no) timerfd_settime (0, TFD_TIMER_ABSTIME, 0, 0);]])],
AC_MSG_RESULT([$emacs_cv_linux_timerfd]) [emacs_cv_have_timerfd=yes],
if test $emacs_cv_linux_timerfd = yes; then [emacs_cv_have_timerfd=no])])
AC_DEFINE(HAVE_TIMERFD, 1, [Define to 1 if Linux timerfd functions are supported.]) if test "$emacs_cv_have_timerfd" = yes; then
AC_MSG_CHECKING([whether TFD_CLOEXEC is defined]) AC_DEFINE([HAVE_TIMERFD], 1,
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <sys/timerfd.h>]], [Define to 1 if timerfd functions are supported as in GNU/Linux.])
[[timerfd_create (CLOCK_REALTIME, TFD_CLOEXEC)]])], fi
emacs_cv_tfd_cloexec=yes, emacs_cv_tfd_cloexec=no)
AC_MSG_RESULT([$emacs_cv_tfd_cloexec])
if test $emacs_cv_tfd_cloexec = yes; then
AC_DEFINE(HAVE_TIMERFD_CLOEXEC, 1, [Define to 1 if TFD_CLOEXEC is defined.])
fi
fi
fi
# Do we have res_init, for detecting changes in /etc/resolv.conf? # Do we have res_init, for detecting changes in /etc/resolv.conf?
# On Darwin, res_init appears not to be useful: see bug#562 and # On Darwin, res_init appears not to be useful: see bug#562 and
......
...@@ -26,6 +26,6 @@ AC_DEFUN([gl_CLOCK_TIME], ...@@ -26,6 +26,6 @@ AC_DEFUN([gl_CLOCK_TIME],
AC_SEARCH_LIBS([clock_gettime], [rt posix4], AC_SEARCH_LIBS([clock_gettime], [rt posix4],
[test "$ac_cv_search_clock_gettime" = "none required" || [test "$ac_cv_search_clock_gettime" = "none required" ||
LIB_CLOCK_GETTIME=$ac_cv_search_clock_gettime]) LIB_CLOCK_GETTIME=$ac_cv_search_clock_gettime])
AC_CHECK_FUNCS([clock_getres clock_gettime clock_settime]) AC_CHECK_FUNCS([clock_gettime clock_settime])
LIBS=$gl_saved_libs LIBS=$gl_saved_libs
]) ])
2014-07-31 Paul Eggert <eggert@cs.ucla.edu> 2014-07-31 Paul Eggert <eggert@cs.ucla.edu>
Simplify timerfd configuration and fix some minor glitches.
* 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.
* frame.c (x_set_frame_parameters): Don't use uninitialized locals. * frame.c (x_set_frame_parameters): Don't use uninitialized locals.
Without this change, the code can access the local variable 'width' Without this change, the code can access the local variable 'width'
even when it has not been initialized, and likewise for 'height'; even when it has not been initialized, and likewise for 'height';
......
...@@ -27,13 +27,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ ...@@ -27,13 +27,8 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
#include <unistd.h> #include <unistd.h>
#ifdef HAVE_TIMERFD #ifdef HAVE_TIMERFD
#include <sys/timerfd.h> # include <sys/timerfd.h>
#ifdef HAVE_TIMERFD_CLOEXEC #endif
#define TIMERFD_CREATE_FLAGS TFD_CLOEXEC
#else
#define TIMERFD_CREATE_FLAGS 0
#endif /* HAVE_TIMERFD_CLOEXEC */
#endif /* HAVE_TIMERFD */
/* Free-list of atimer structures. */ /* Free-list of atimer structures. */
...@@ -49,23 +44,18 @@ static struct atimer *stopped_atimers; ...@@ -49,23 +44,18 @@ static struct atimer *stopped_atimers;
static struct atimer *atimers; static struct atimer *atimers;
#if defined (HAVE_TIMERFD) #ifdef HAVE_ITIMERSPEC
/* File descriptor returned by timerfd_create. GNU/Linux-specific. */ /* The alarm timer and whether it was properly initialized, if
static int timerfd; POSIX timers are available. */
#elif defined (HAVE_ITIMERSPEC)
/* The alarm timer used if POSIX timers are available. */
static timer_t alarm_timer; static timer_t alarm_timer;
#endif static bool alarm_timer_ok;
#if defined (HAVE_TIMERFD) || defined (HAVE_ITIMERSPEC)
/* Non-zero if one of the above was successfully initialized. Do not
use bool due to special treatment if HAVE_TIMERFD, see below. */
static int special_timer_available;
#endif
#ifdef HAVE_CLOCK_GETRES # ifdef HAVE_TIMERFD
/* Resolution of CLOCK_REALTIME clock. */ /* File descriptor for timer, or -1 if it could not be created. */
static struct timespec resolution; static int timerfd;
# else
enum { timerfd = -1 };
# endif
#endif #endif
/* Block/unblock SIGALRM. */ /* Block/unblock SIGALRM. */
...@@ -92,20 +82,20 @@ static void schedule_atimer (struct atimer *); ...@@ -92,20 +82,20 @@ static void schedule_atimer (struct atimer *);
static struct atimer *append_atimer_lists (struct atimer *, static struct atimer *append_atimer_lists (struct atimer *,
struct atimer *); struct atimer *);
/* Start a new atimer of type TYPE. TIME specifies when the timer is /* Start a new atimer of type TYPE. TIMESTAMP specifies when the timer is
ripe. FN is the function to call when the timer fires. ripe. FN is the function to call when the timer fires.
CLIENT_DATA is stored in the client_data member of the atimer CLIENT_DATA is stored in the client_data member of the atimer
structure returned and so made available to FN when it is called. structure returned and so made available to FN when it is called.
If TYPE is ATIMER_ABSOLUTE, TIME is the absolute time at which the If TYPE is ATIMER_ABSOLUTE, TIMESTAMP is the absolute time at which the
timer fires. timer fires.
If TYPE is ATIMER_RELATIVE, the timer is ripe TIME s/us in the If TYPE is ATIMER_RELATIVE, the timer is ripe TIMESTAMP seconds in the
future. future.
In both cases, the timer is automatically freed after it has fired. In both cases, the timer is automatically freed after it has fired.
If TYPE is ATIMER_CONTINUOUS, the timer fires every TIME s/us. If TYPE is ATIMER_CONTINUOUS, the timer fires every TIMESTAMP seconds.
Value is a pointer to the atimer started. It can be used in calls Value is a pointer to the atimer started. It can be used in calls
to cancel_atimer; don't free it yourself. */ to cancel_atimer; don't free it yourself. */
...@@ -117,16 +107,10 @@ start_atimer (enum atimer_type type, struct timespec timestamp, ...@@ -117,16 +107,10 @@ start_atimer (enum atimer_type type, struct timespec timestamp,
struct atimer *t; struct atimer *t;
sigset_t oldset; sigset_t oldset;
#if !defined (HAVE_SETITIMER) /* Round TIMESTAMP up to the next full second if we don't have itimers. */
/* Round TIME up to the next full second if we don't have itimers. */ #ifndef HAVE_SETITIMER
if (timestamp.tv_nsec != 0 && timestamp.tv_sec < TYPE_MAXIMUM (time_t)) if (timestamp.tv_nsec != 0 && timestamp.tv_sec < TYPE_MAXIMUM (time_t))
timestamp = make_timespec (timestamp.tv_sec + 1, 0); timestamp = make_timespec (timestamp.tv_sec + 1, 0);
#elif defined (HAVE_CLOCK_GETRES)
/* Check that the system clock is precise enough. If
not, round TIME up to the system clock resolution. */
if (timespec_valid_p (resolution)
&& timespec_cmp (timestamp, resolution) < 0)
timestamp = resolution;
#endif /* not HAVE_SETITIMER */ #endif /* not HAVE_SETITIMER */
/* Get an atimer structure from the free-list, or allocate /* Get an atimer structure from the free-list, or allocate
...@@ -311,25 +295,24 @@ set_alarm (void) ...@@ -311,25 +295,24 @@ set_alarm (void)
#endif #endif
struct timespec now, interval; struct timespec now, interval;
#if defined (HAVE_TIMERFD) || defined (HAVE_ITIMERSPEC) #ifdef HAVE_ITIMERSPEC
if (special_timer_available) if (0 <= timerfd || alarm_timer_ok)
{ {
struct itimerspec ispec; struct itimerspec ispec;
ispec.it_value = atimers->expiration; ispec.it_value = atimers->expiration;
ispec.it_interval.tv_sec = ispec.it_interval.tv_nsec = 0; ispec.it_interval.tv_sec = ispec.it_interval.tv_nsec = 0;
#if defined (HAVE_TIMERFD) # ifdef HAVE_TIMERFD
if (special_timer_available == 1) if (timerfd_settime (timerfd, TFD_TIMER_ABSTIME, &ispec, 0) == 0)
{ {
add_timer_wait_descriptor (timerfd); add_timer_wait_descriptor (timerfd);
special_timer_available++; return;
} }
if (timerfd_settime (timerfd, TFD_TIMER_ABSTIME, &ispec, 0) == 0) # endif
#elif defined (HAVE_ITIMERSPEC) if (alarm_timer_ok
if (timer_settime (alarm_timer, TIMER_ABSTIME, &ispec, 0) == 0) && timer_settime (alarm_timer, TIMER_ABSTIME, &ispec, 0) == 0)
#endif
return; return;
} }
#endif /* HAVE_TIMERFD || HAVE_ITIMERSPEC */ #endif
/* Determine interval till the next timer is ripe. /* Determine interval till the next timer is ripe.
Don't set the interval to 0; this disables the timer. */ Don't set the interval to 0; this disables the timer. */
...@@ -453,15 +436,15 @@ turn_on_atimers (bool on) ...@@ -453,15 +436,15 @@ turn_on_atimers (bool on)
set_alarm (); set_alarm ();
else else
{ {
#ifdef HAVE_TIMERFD #ifdef HAVE_ITIMERSPEC
if (special_timer_available > 1) struct itimerspec ispec;
{ memset (&ispec, 0, sizeof ispec);
struct itimerspec ispec; if (alarm_timer_ok)
memset (&ispec, 0, sizeof (ispec)); timer_settime (alarm_timer, TIMER_ABSTIME, &ispec, 0);
/* Writing zero expiration time should disarm it. */ # ifdef HAVE_TIMERFD
timerfd_settime (timerfd, TFD_TIMER_ABSTIME, &ispec, 0); timerfd_settime (timerfd, TFD_TIMER_ABSTIME, &ispec, 0);
} # endif
#endif /* HAVE_TIMERFD */ #endif
alarm (0); alarm (0);
} }
} }
...@@ -494,14 +477,14 @@ debug_timer_callback (struct atimer *t) ...@@ -494,14 +477,14 @@ debug_timer_callback (struct atimer *t)
r->intime = 0; r->intime = 0;
else if (result >= 0) else if (result >= 0)
{ {
#ifdef HAVE_SETITIMER #ifdef HAVE_SETITIMER
struct timespec delta = timespec_sub (now, r->expected); struct timespec delta = timespec_sub (now, r->expected);
/* Too late if later than expected + 0.01s. FIXME: /* Too late if later than expected + 0.01s. FIXME:
this should depend from system clock resolution. */ this should depend from system clock resolution. */
if (timespec_cmp (delta, make_timespec (0, 10000000)) > 0) if (timespec_cmp (delta, make_timespec (0, 10000000)) > 0)
r->intime = 0; r->intime = 0;
else else
#endif /* HAVE_SETITIMER */ #endif /* HAVE_SETITIMER */
r->intime = 1; r->intime = 1;
} }
} }
...@@ -543,21 +526,20 @@ Return t if all self-tests are passed, nil otherwise. */) ...@@ -543,21 +526,20 @@ Return t if all self-tests are passed, nil otherwise. */)
void void
init_atimer (void) init_atimer (void)
{ {
#if defined (HAVE_TIMERFD) #ifdef HAVE_ITIMERSPEC
timerfd = timerfd_create (CLOCK_REALTIME, TIMERFD_CREATE_FLAGS); # ifdef HAVE_TIMERFD
special_timer_available = !!(timerfd != -1); timerfd = timerfd_create (CLOCK_REALTIME, TFD_CLOEXEC);
#elif defined (HAVE_ITIMERSPEC) # endif
struct sigevent sigev; if (timerfd < 0)
sigev.sigev_notify = SIGEV_SIGNAL; {
sigev.sigev_signo = SIGALRM; struct sigevent sigev;
sigev.sigev_value.sival_ptr = &alarm_timer; sigev.sigev_notify = SIGEV_SIGNAL;
special_timer_available sigev.sigev_signo = SIGALRM;
= timer_create (CLOCK_REALTIME, &sigev, &alarm_timer) == 0; sigev.sigev_value.sival_ptr = &alarm_timer;
#endif /* HAVE_TIMERFD */ alarm_timer_ok
#ifdef HAVE_CLOCK_GETRES = timer_create (CLOCK_REALTIME, &sigev, &alarm_timer) == 0;
if (clock_getres (CLOCK_REALTIME, &resolution)) }
resolution = invalid_timespec (); #endif
#endif
free_atimers = stopped_atimers = atimers = NULL; free_atimers = stopped_atimers = atimers = NULL;
/* pending_signals is initialized in init_keyboard. */ /* pending_signals is initialized in init_keyboard. */
...@@ -567,5 +549,5 @@ init_atimer (void) ...@@ -567,5 +549,5 @@ init_atimer (void)
#ifdef ENABLE_CHECKING #ifdef ENABLE_CHECKING
defsubr (&Sdebug_timer_check); defsubr (&Sdebug_timer_check);
#endif #endif
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment