Fix g_cond_wait_until() vs. monotonic time

We've had a relatively rocky path with g_cond_wait_until() on systems
that either don't support pthread_condattr_setclock() or where
g_get_monotonic_time() is not based on CLOCK_MONOTONIC (ie: Android and
Mac OS).

Fortunately, both of these platforms seem to share
pthread_cond_timedwait_relative_np() which allows us to implement
g_cond_wait_until() without races.

With this patch, we now require that one of pthread_condattr_setclock()
or pthread_cond_timedwait_relative_np() exists.  A quick look around
suggests that this is true for all platforms that we care about.

This patch removes our use of pthread_cond_timedwait_monotonic() and
pthread_cond_timedwait_monotonic_np() which were Android-only APIs.

https://bugzilla.gnome.org/show_bug.cgi?id=673607
This commit is contained in:
Ryan Lortie
2014-02-18 18:50:18 -05:00
parent d614312546
commit 1de36e7755
2 changed files with 38 additions and 24 deletions

View File

@@ -45,6 +45,7 @@
#include "gslice.h"
#include "gmessages.h"
#include "gstrfuncs.h"
#include "gmain.h"
#include <stdlib.h>
#include <stdio.h>
@@ -853,19 +854,41 @@ g_cond_wait_until (GCond *cond,
struct timespec ts;
gint status;
ts.tv_sec = end_time / 1000000;
ts.tv_nsec = (end_time % 1000000) * 1000;
#ifdef HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
/* end_time is given relative to the monotonic clock as returned by
* g_get_monotonic_time().
*
* Since this pthreads wants the relative time, convert it back again.
*/
{
gint64 now = g_get_monotonic_time ();
gint64 relative;
#if defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC)
if ((status = pthread_cond_timedwait_monotonic (g_cond_get_impl (cond), g_mutex_get_impl (mutex), &ts)) == 0)
return TRUE;
#elif defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP)
if ((status = pthread_cond_timedwait_monotonic_np (g_cond_get_impl (cond), g_mutex_get_impl (mutex), &ts)) == 0)
return TRUE;
if (end_time <= now)
return FALSE;
relative = end_time - now;
ts.tv_sec = relative / 1000000;
ts.tv_nsec = (relative % 1000000) * 1000;
if ((status = pthread_cond_timedwait_relative_np (g_cond_get_impl (cond), g_mutex_get_impl (mutex), &ts)) == 0)
return TRUE;
}
#elif defined (HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined (CLOCK_MONOTONIC)
/* This is the exact check we used during init to set the clock to
* monotonic, so if we're in this branch, timedwait() will already be
* expecting a monotonic clock.
*/
{
ts.tv_sec = end_time / 1000000;
ts.tv_nsec = (end_time % 1000000) * 1000;
if ((status = pthread_cond_timedwait (g_cond_get_impl (cond), g_mutex_get_impl (mutex), &ts)) == 0)
return TRUE;
}
#else
/* Pray that the cond is actually using the monotonic clock */
if ((status = pthread_cond_timedwait (g_cond_get_impl (cond), g_mutex_get_impl (mutex), &ts)) == 0)
return TRUE;
#error Cannot support GCond on your platform.
#endif
if G_UNLIKELY (status != ETIMEDOUT)