Commit ae24bb35 authored by Colin Walters's avatar Colin Walters

Bug 18121 - Use a monotonic clock for pthread timeouts

Patch based on one from Keith Mok <ek9852@gmail.com>, some
followup work from Janne Karhunen <Janne.Karhunen@gmail.com>.

We don't want condition variable timeouts to be affected by the system clock.
Use the POSIX CLOCK_MONOTONIC if available.
parent f4e15893
......@@ -696,8 +696,31 @@ if $dbus_use_libxml; then
fi
# Thread lib detection
AC_CHECK_FUNC(pthread_cond_timedwait,,[AC_CHECK_LIB(pthread,pthread_cond_timedwait,
AC_CHECK_FUNC(pthread_cond_timedwait,[AC_CHECK_LIB(pthread,pthread_cond_timedwait,
[THREAD_LIBS="-lpthread"])])
save_libs="$LIBS"
LIBS="$LIBS $THREAD_LIBS"
AC_CHECK_FUNC(pthread_condattr_setclock,have_pthread_condattr_setclock=true,have_pthread_condattr_setclock=false)
if test x$have_pthread_condattr_setclock = xtrue; then
AC_SEARCH_LIBS([clock_getres],[rt],[THREAD_LIBS="$THREAD_LIBS -lrt"])
AC_MSG_CHECKING([for CLOCK_MONOTONIC])
AC_TRY_COMPILE([#include <time.h>
#include <pthread.h>
], [
struct timespec monotonic_timer;
pthread_condattr_t attr;
pthread_condattr_init (&attr);
pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);
clock_getres (CLOCK_MONOTONIC,&monotonic_timer);
], have_clock_monotonic=true, have_clock_monotonic=false)
if test x$have_clock_monotonic = xtrue; then
AC_MSG_RESULT([found])
AC_DEFINE(HAVE_MONOTONIC_CLOCK, 1, [Define if we have CLOCK_MONOTONIC])
else
AC_MSG_RESULT([not found])
fi
fi
LIBS="$save_libs"
# SELinux detection
if test x$enable_selinux = xno ; then
......
......@@ -33,6 +33,15 @@
#include <errno.h>
#endif
#include <config.h>
/* Whether we have a "monotonic" clock; i.e. a clock not affected by
* changes in system time.
* This is initialized once in check_monotonic_clock below.
* https://bugs.freedesktop.org/show_bug.cgi?id=18121
*/
static dbus_bool_t have_monotonic_clock = 0;
typedef struct {
pthread_mutex_t lock; /**< lock protecting count field */
volatile int count; /**< count of how many times lock holder has recursively locked */
......@@ -184,13 +193,21 @@ static DBusCondVar *
_dbus_pthread_condvar_new (void)
{
DBusCondVarPThread *pcond;
pthread_condattr_t attr;
int result;
pcond = dbus_new (DBusCondVarPThread, 1);
if (pcond == NULL)
return NULL;
result = pthread_cond_init (&pcond->cond, NULL);
pthread_condattr_init (&attr);
#ifdef HAVE_MONOTONIC_CLOCK
if (have_monotonic_clock)
pthread_condattr_setclock (&attr, CLOCK_MONOTONIC);
#endif
result = pthread_cond_init (&pcond->cond, &attr);
pthread_condattr_destroy (&attr);
if (result == EAGAIN || result == ENOMEM)
{
......@@ -248,7 +265,18 @@ _dbus_pthread_condvar_wait_timeout (DBusCondVar *cond,
_dbus_assert (pmutex->count > 0);
_dbus_assert (pthread_equal (pmutex->holder, pthread_self ()));
#ifdef HAVE_MONOTONIC_CLOCK
if (have_monotonic_clock)
{
struct timespec monotonic_timer;
clock_gettime (CLOCK_MONOTONIC,&monotonic_timer);
time_now.tv_sec = monotonic_timer.tv_sec;
time_now.tv_usec = monotonic_timer.tv_nsec / 1000;
}
else
/* This else falls through to gettimeofday */
#endif
gettimeofday (&time_now, NULL);
end_time.tv_sec = time_now.tv_sec + timeout_milliseconds / 1000;
......@@ -317,8 +345,19 @@ static const DBusThreadFunctions pthread_functions =
_dbus_pthread_mutex_unlock
};
static void
check_monotonic_clock (void)
{
#ifdef HAVE_MONOTONIC_CLOCK
struct timespec dummy;
if (clock_getres (CLOCK_MONOTONIC, &dummy) == 0)
have_monotonic_clock = TRUE;
#endif
}
dbus_bool_t
_dbus_threads_init_platform_specific (void)
{
check_monotonic_clock ();
return dbus_threads_init (&pthread_functions);
}
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