mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-08-20 07:38:54 +02:00
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:
17
configure.ac
17
configure.ac
@@ -2235,23 +2235,14 @@ AS_IF([ test x"$have_threads" = xposix], [
|
|||||||
AC_DEFINE(HAVE_PTHREAD_CONDATTR_SETCLOCK,1,
|
AC_DEFINE(HAVE_PTHREAD_CONDATTR_SETCLOCK,1,
|
||||||
[Have function pthread_condattr_setclock])],
|
[Have function pthread_condattr_setclock])],
|
||||||
[AC_MSG_RESULT(no)])
|
[AC_MSG_RESULT(no)])
|
||||||
AC_MSG_CHECKING(for pthread_cond_timedwait_monotonic)
|
AC_MSG_CHECKING(for pthread_cond_timedwait_relative_np)
|
||||||
AC_LINK_IFELSE(
|
AC_LINK_IFELSE(
|
||||||
[AC_LANG_PROGRAM(
|
[AC_LANG_PROGRAM(
|
||||||
[#include <pthread.h>],
|
[#include <pthread.h>],
|
||||||
[pthread_cond_timedwait_monotonic(NULL, NULL, NULL)])],
|
[pthread_cond_timedwait_relative_np(NULL, NULL, NULL)])],
|
||||||
[AC_MSG_RESULT(yes)
|
[AC_MSG_RESULT(yes)
|
||||||
AC_DEFINE(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC,1,
|
AC_DEFINE(HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP,1,
|
||||||
[Have function pthread_cond_timedwait_monotonic])],
|
[Have function pthread_cond_timedwait_relative_np])],
|
||||||
[AC_MSG_RESULT(no)])
|
|
||||||
AC_MSG_CHECKING(for pthread_cond_timedwait_monotonic_np)
|
|
||||||
AC_LINK_IFELSE(
|
|
||||||
[AC_LANG_PROGRAM(
|
|
||||||
[#include <pthread.h>],
|
|
||||||
[pthread_cond_timedwait_monotonic_np(NULL, NULL, NULL)])],
|
|
||||||
[AC_MSG_RESULT(yes)
|
|
||||||
AC_DEFINE(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP,1,
|
|
||||||
[Have function pthread_cond_timedwait_monotonic_np])],
|
|
||||||
[AC_MSG_RESULT(no)])
|
[AC_MSG_RESULT(no)])
|
||||||
CPPFLAGS="$glib_save_CPPFLAGS"
|
CPPFLAGS="$glib_save_CPPFLAGS"
|
||||||
])
|
])
|
||||||
|
@@ -45,6 +45,7 @@
|
|||||||
#include "gslice.h"
|
#include "gslice.h"
|
||||||
#include "gmessages.h"
|
#include "gmessages.h"
|
||||||
#include "gstrfuncs.h"
|
#include "gstrfuncs.h"
|
||||||
|
#include "gmain.h"
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -853,19 +854,41 @@ g_cond_wait_until (GCond *cond,
|
|||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
gint status;
|
gint status;
|
||||||
|
|
||||||
ts.tv_sec = end_time / 1000000;
|
#ifdef HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP
|
||||||
ts.tv_nsec = (end_time % 1000000) * 1000;
|
/* 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 (end_time <= now)
|
||||||
if ((status = pthread_cond_timedwait_monotonic (g_cond_get_impl (cond), g_mutex_get_impl (mutex), &ts)) == 0)
|
return FALSE;
|
||||||
return TRUE;
|
|
||||||
#elif defined(HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC_NP)
|
relative = end_time - now;
|
||||||
if ((status = pthread_cond_timedwait_monotonic_np (g_cond_get_impl (cond), g_mutex_get_impl (mutex), &ts)) == 0)
|
|
||||||
return TRUE;
|
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
|
#else
|
||||||
/* Pray that the cond is actually using the monotonic clock */
|
#error Cannot support GCond on your platform.
|
||||||
if ((status = pthread_cond_timedwait (g_cond_get_impl (cond), g_mutex_get_impl (mutex), &ts)) == 0)
|
|
||||||
return TRUE;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if G_UNLIKELY (status != ETIMEDOUT)
|
if G_UNLIKELY (status != ETIMEDOUT)
|
||||||
|
Reference in New Issue
Block a user