Message ID | 813a2918734ae172846d52f7d33f3dac34aabf9a.1563209229.git-series.mac@mcrowe.com |
---|---|
State | New |
Headers | show |
Series | PR libstdc++/41861 Add full steady_clock support to condition_variable | expand |
On 15/07/19 17:47 +0100, Mike Crowe wrote: >The pthread_cond_clockwait function was recently added[1] to glibc, and is >due to be released in glibc 2.30. If this function is available in the C >library it can be used it to fix >https://gcc.gnu.org/bugzilla/show_bug.cgi?id=41861 by supporting >std::chrono::steady_clock properly with std::condition_variable. > >This means that code using std::condition_variable::wait_for or >std::condition_variable::wait_until with std::chrono::steady_clock is no >longer subject to timing out early or potentially waiting for much longer >if the system clock is warped at an inopportune moment. > >If pthread_cond_clockwait is available then std::chrono::steady_clock is >deemed to be the "best" clock available which means that it is used for the >relative wait_for calls and absolute wait_until calls using user-defined >clocks. Calls explicitly using std::chrono::system_clock continue to use >CLOCK_REALTIME via __gthread_cond_timedwait. > >If pthread_cond_clockwait is not available then std::chrono::system_clock >is deemed to be the "best" clock available which means that the previous >suboptimal behaviour remains. > >[1] https://sourceware.org/git/?p=glibc.git;a=commit;h=afe4de7d283ebd88157126c5494ce1796194c16e > >libstdc++-v3/ > > * include/std/condition_variable: Add include of <bits/c++config.h> > to make _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT available. > (condition_variable): Split __clock_t into __system_clock_t, which > is always system_clock and __best_clock_t, which is the clock that > we wish to convert arbitrary other clocks to. If we know that > pthread_cond_clockwait is available then it is best to convert > clocks to steady_clock, otherwise it's best to use > system_clock. (wait_until): If pthread_cond_clockwait is available, > provide a steady_clock overload. Convert previous __clock_t > overload to use __system_clock_t. Convert generic overload to > convert passed clock to __best_clock_t. (wait_until_impl): Add > steady_clock overload that calls pthread_cond_clockwait. Convert > previous __clock_t overload to use > __system_clock_t. (condition_variable_any): Use steady_clock for > __clock_t if pthread_cond_clockwait is available. > > * acinclude.m4: Detect the availability of POSIX-proposed > pthread_cond_clockwait function. > * configure: Likewise. > * configure.ac: Likewise. > * config.h.in: Add _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT define to > indicate presence of pthread_cond_clockwait function. Thanks, Mike! This patch is much simpler than the previous versions. Thanks for perservering with POSIX and glibc to get the necessary functionality into libc. I've attached a slightly-modified patch, which changes the names of the clock typedefs in std::condition_variable. The names "steady_clock" and "system_clock" are already reserved names, so we can just use those (instead of the uglier __steady_clock_t forms). And we can just keep the original __clock_t name to mean the best clock. Does that look OK to you too? I've confirmed that with glibc 2.30 the new function is detected, and the testsuite passes. I'm running the tests with an older glibc as well. I noticed that the new tests you added in [PATCH 1/2] pass on current trunk, even without [PATCH 2/2], is that expected?
On Wednesday 04 September 2019 at 14:39:35 +0100, Jonathan Wakely wrote: > On 15/07/19 17:47 +0100, Mike Crowe wrote: > > The pthread_cond_clockwait function was recently added[1] to glibc, and is > > due to be released in glibc 2.30. If this function is available in the C > > library it can be used it to fix > > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=41861 by supporting > > std::chrono::steady_clock properly with std::condition_variable. > > > > This means that code using std::condition_variable::wait_for or > > std::condition_variable::wait_until with std::chrono::steady_clock is no > > longer subject to timing out early or potentially waiting for much longer > > if the system clock is warped at an inopportune moment. > > > > If pthread_cond_clockwait is available then std::chrono::steady_clock is > > deemed to be the "best" clock available which means that it is used for the > > relative wait_for calls and absolute wait_until calls using user-defined > > clocks. Calls explicitly using std::chrono::system_clock continue to use > > CLOCK_REALTIME via __gthread_cond_timedwait. > > > > If pthread_cond_clockwait is not available then std::chrono::system_clock > > is deemed to be the "best" clock available which means that the previous > > suboptimal behaviour remains. > > > > [1] https://sourceware.org/git/?p=glibc.git;a=commit;h=afe4de7d283ebd88157126c5494ce1796194c16e > > > > libstdc++-v3/ > > > > * include/std/condition_variable: Add include of <bits/c++config.h> > > to make _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT available. > > (condition_variable): Split __clock_t into __system_clock_t, which > > is always system_clock and __best_clock_t, which is the clock that > > we wish to convert arbitrary other clocks to. If we know that > > pthread_cond_clockwait is available then it is best to convert > > clocks to steady_clock, otherwise it's best to use > > system_clock. (wait_until): If pthread_cond_clockwait is available, > > provide a steady_clock overload. Convert previous __clock_t > > overload to use __system_clock_t. Convert generic overload to > > convert passed clock to __best_clock_t. (wait_until_impl): Add > > steady_clock overload that calls pthread_cond_clockwait. Convert > > previous __clock_t overload to use > > __system_clock_t. (condition_variable_any): Use steady_clock for > > __clock_t if pthread_cond_clockwait is available. > > > > * acinclude.m4: Detect the availability of POSIX-proposed > > pthread_cond_clockwait function. > > * configure: Likewise. > > * configure.ac: Likewise. > > * config.h.in: Add _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT define to > > indicate presence of pthread_cond_clockwait function. > > Thanks, Mike! > > This patch is much simpler than the previous versions. Thanks for > perservering with POSIX and glibc to get the necessary functionality > into libc. > > I've attached a slightly-modified patch, which changes the names of > the clock typedefs in std::condition_variable. The names > "steady_clock" and "system_clock" are already reserved names, so we > can just use those (instead of the uglier __steady_clock_t forms). And > we can just keep the original __clock_t name to mean the best clock. > Does that look OK to you too? You're far more expert on that stuff than I am, but it looks fine to me. However, you've also removed the <bits/c++config.h> include. Was that intentional? > I've confirmed that with glibc 2.30 the new function is detected, and > the testsuite passes. I'm running the tests with an older glibc as > well. I found that it was necessary to run the test under strace to prove that the correct variant of futex is called too, because... > I noticed that the new tests you added in [PATCH 1/2] pass on current > trunk, even without [PATCH 2/2], is that expected? Unfortunately, yes. CLOCK_MONOTONIC and CLOCK_REALTIME will tick at the same rate, so unless someone warps CLOCK_REALTIME during the test we can't tell the difference between the old implementation of translating steady_clock to system_clock and the new implementation that uses steady_clock directly. :( I added the tests in the hope of finding other mistakes in the new implementation rather than to reproduce the original problem. Maybe I should add comments to the test to make that clear along the lines of those found in testsuite/27_io/objects/char/3_xin.cc ? Thanks for looking at this. Mike.
On 04/09/19 15:49 +0100, Mike Crowe wrote: >On Wednesday 04 September 2019 at 14:39:35 +0100, Jonathan Wakely wrote: >> On 15/07/19 17:47 +0100, Mike Crowe wrote: >> > The pthread_cond_clockwait function was recently added[1] to glibc, and is >> > due to be released in glibc 2.30. If this function is available in the C >> > library it can be used it to fix >> > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=41861 by supporting >> > std::chrono::steady_clock properly with std::condition_variable. >> > >> > This means that code using std::condition_variable::wait_for or >> > std::condition_variable::wait_until with std::chrono::steady_clock is no >> > longer subject to timing out early or potentially waiting for much longer >> > if the system clock is warped at an inopportune moment. >> > >> > If pthread_cond_clockwait is available then std::chrono::steady_clock is >> > deemed to be the "best" clock available which means that it is used for the >> > relative wait_for calls and absolute wait_until calls using user-defined >> > clocks. Calls explicitly using std::chrono::system_clock continue to use >> > CLOCK_REALTIME via __gthread_cond_timedwait. >> > >> > If pthread_cond_clockwait is not available then std::chrono::system_clock >> > is deemed to be the "best" clock available which means that the previous >> > suboptimal behaviour remains. >> > >> > [1] https://sourceware.org/git/?p=glibc.git;a=commit;h=afe4de7d283ebd88157126c5494ce1796194c16e >> > >> > libstdc++-v3/ >> > >> > * include/std/condition_variable: Add include of <bits/c++config.h> >> > to make _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT available. >> > (condition_variable): Split __clock_t into __system_clock_t, which >> > is always system_clock and __best_clock_t, which is the clock that >> > we wish to convert arbitrary other clocks to. If we know that >> > pthread_cond_clockwait is available then it is best to convert >> > clocks to steady_clock, otherwise it's best to use >> > system_clock. (wait_until): If pthread_cond_clockwait is available, >> > provide a steady_clock overload. Convert previous __clock_t >> > overload to use __system_clock_t. Convert generic overload to >> > convert passed clock to __best_clock_t. (wait_until_impl): Add >> > steady_clock overload that calls pthread_cond_clockwait. Convert >> > previous __clock_t overload to use >> > __system_clock_t. (condition_variable_any): Use steady_clock for >> > __clock_t if pthread_cond_clockwait is available. >> > >> > * acinclude.m4: Detect the availability of POSIX-proposed >> > pthread_cond_clockwait function. >> > * configure: Likewise. >> > * configure.ac: Likewise. >> > * config.h.in: Add _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT define to >> > indicate presence of pthread_cond_clockwait function. >> >> Thanks, Mike! >> >> This patch is much simpler than the previous versions. Thanks for >> perservering with POSIX and glibc to get the necessary functionality >> into libc. >> >> I've attached a slightly-modified patch, which changes the names of >> the clock typedefs in std::condition_variable. The names >> "steady_clock" and "system_clock" are already reserved names, so we >> can just use those (instead of the uglier __steady_clock_t forms). And >> we can just keep the original __clock_t name to mean the best clock. >> Does that look OK to you too? > >You're far more expert on that stuff than I am, but it looks fine to me. > >However, you've also removed the <bits/c++config.h> include. Was that >intentional? Yes, it's already included via <type_traits> (and probably several other routes). Every header should already be including that. If they didn't, the macros like _GLIBCXX_HAS_GTHREADS, _GLIBCXX_VISIBILITY, and _GLIBCXX_BEGIN_NAMESPACE_VERSION would produce errors. >> I've confirmed that with glibc 2.30 the new function is detected, and >> the testsuite passes. I'm running the tests with an older glibc as >> well. > >I found that it was necessary to run the test under strace to prove that >the correct variant of futex is called too, because... > >> I noticed that the new tests you added in [PATCH 1/2] pass on current >> trunk, even without [PATCH 2/2], is that expected? > >Unfortunately, yes. CLOCK_MONOTONIC and CLOCK_REALTIME will tick at the >same rate, so unless someone warps CLOCK_REALTIME during the test we can't >tell the difference between the old implementation of translating >steady_clock to system_clock and the new implementation that uses >steady_clock directly. :( I added the tests in the hope of finding other >mistakes in the new implementation rather than to reproduce the original >problem. OK, that was what I figured was the case. Thanks for confirming. >Maybe I should add comments to the test to make that clear along the lines >of those found in testsuite/27_io/objects/char/3_xin.cc ? More comments are usually useful, otherwise I'll just ask the same question again and again :-) All my testing passed, so I'll get this committed today. Thanks again for perservering to finally get this fixed!
On 04/09/19 18:21 +0100, Mike Crowe wrote: >On Wednesday 04 September 2019 at 17:57:45 +0100, Mike Crowe wrote: >> On Wednesday 04 September 2019 at 17:14:30 +0100, Jonathan Wakely wrote: >> > On 04/09/19 15:49 +0100, Mike Crowe wrote: >> > > On Wednesday 04 September 2019 at 14:39:35 +0100, Jonathan Wakely wrote: >> > > > I noticed that the new tests you added in [PATCH 1/2] pass on current >> > > > trunk, even without [PATCH 2/2], is that expected? >> > > >> > > Unfortunately, yes. CLOCK_MONOTONIC and CLOCK_REALTIME will tick at the >> > > same rate, so unless someone warps CLOCK_REALTIME during the test we can't >> > > tell the difference between the old implementation of translating >> > > steady_clock to system_clock and the new implementation that uses >> > > steady_clock directly. :( I added the tests in the hope of finding other >> > > mistakes in the new implementation rather than to reproduce the original >> > > problem. >> > >> > OK, that was what I figured was the case. Thanks for confirming. >> > >> > > Maybe I should add comments to the test to make that clear along the lines >> > > of those found in testsuite/27_io/objects/char/3_xin.cc ? >> > >> > More comments are usually useful, otherwise I'll just ask the same >> > question again and again :-) >> >> How about something like: >> >> --8<-- >> It's not possible for this test to automatically ensure that the >> system_clock test cases result in a wait on CLOCK_REALTIME and steady_clock >> test cases result in a wait on CLOCK_MONOTONIC. It's recommended to run the >> test under strace(1) and check whether the expected futex calls are made by >> glibc. >> -->8-- >> >> Unfortunately I'm unable to determine how I actually managed to run the >> test under strace. Perhaps I just compiled a similar test myself rather >> than using dejagnu. :( > >Ah, I did it. Here's a new comment: > >--8<-- >It's not possible for this test to automatically ensure that the >system_clock test cases result in a wait on CLOCK_REALTIME and steady_clock >test cases result in a wait on CLOCK_MONOTONIC. It's recommended to run the >test under strace(1) and check whether the expected futex calls are made by >glibc. The easiest way to do this is to copy and paste the line used to >build the test from the output of: > > make -j8 check-target-libstdc++-v3 RUNTESTFLAGS="conformance.exp=30_threads/condition_variable/members/* -v -v" > >to compile the test with only the tests for one clock enabled and then run it as: > > strace ./2.exe > >You should see calls to: > > futex(..., FUTEX_WAIT_BITSET_PRIVATE|FUTEX_CLOCK_REALTIME, ...) > >with large values of tv_sec when using system_clock and calls to: > > futex(..., FUTEX_WAIT_BITSET_PRIVATE, ...) > >with values of tv_sec based on the system uptime when using steady_clock. >-->8-- Great. I've committed the patch I sent earlier (with the renamed typedefs) and the attached one for the tests (using an abridged form of the comment above, linking to the copy of your mail in the list archives for the full instructions). Thanks!
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index a52a704..597000b 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,30 @@ 2019-07-15 Mike Crowe <mac@mcrowe.com> + * include/std/condition_variable: Add include of <bits/c++config.h> + to make _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT available. + (condition_variable): Split __clock_t into __system_clock_t, which + is always system_clock and __best_clock_t, which is the clock that + we wish to convert arbitrary other clocks to. If we know that + pthread_cond_clockwait is available then it is best to convert + clocks to steady_clock, otherwise it's best to use + system_clock. (wait_until): If pthread_cond_clockwait is available, + provide a steady_clock overload. Convert previous __clock_t + overload to use __system_clock_t. Convert generic overload to + convert passed clock to __best_clock_t. (wait_until_impl): Add + steady_clock overload that calls pthread_cond_clockwait. Convert + previous __clock_t overload to use + __system_clock_t. (condition_variable_any): Use steady_clock for + __clock_t if pthread_cond_clockwait is available. + + * acinclude.m4: Detect the availability of POSIX-proposed + pthread_cond_clockwait function. + * configure: Likewise. + * configure.ac: Likewise. + * config.h.in: Add _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT define to + indicate presence of pthread_cond_clockwait function. + +2019-07-15 Mike Crowe <mac@mcrowe.com> + * testsuite/30_threads/condition_variable/members/2.cc (test01): Parameterise so that test can be run against an arbitrary clock. (main): Test using std::chrono::steady_clock and a user-defined diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4 index 24145fd..35979e7 100644 --- a/libstdc++-v3/acinclude.m4 +++ b/libstdc++-v3/acinclude.m4 @@ -4194,6 +4194,37 @@ AC_DEFUN([GLIBCXX_CHECK_PTHREADS_NUM_PROCESSORS_NP], [ ]) dnl +dnl Check whether pthread_cond_clockwait is available in <pthread.h> for std::condition_variable to use, +dnl and define _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT. +dnl +AC_DEFUN([GLIBCXX_CHECK_PTHREAD_COND_CLOCKWAIT], [ + + AC_LANG_SAVE + AC_LANG_CPLUSPLUS + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + ac_save_LIBS="$LIBS" + LIBS="$LIBS -lpthread" + + AC_MSG_CHECKING([for pthread_cond_clockwait]) + AC_CACHE_VAL(glibcxx_cv_PTHREAD_COND_CLOCKWAIT, [ + GCC_TRY_COMPILE_OR_LINK( + [#include <pthread.h>], + [pthread_mutex_t mutex; pthread_cond_t cond; struct timespec ts; int n = pthread_cond_clockwait(&cond, &mutex, 0, &ts);], + [glibcxx_cv_PTHREAD_COND_CLOCKWAIT=yes], + [glibcxx_cv_PTHREAD_COND_CLOCKWAIT=no]) + ]) + if test $glibcxx_cv_PTHREAD_COND_CLOCKWAIT = yes; then + AC_DEFINE(_GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT, 1, [Define if pthread_cond_clockwait is available in <pthread.h>.]) + fi + AC_MSG_RESULT($glibcxx_cv_PTHREAD_COND_CLOCKWAIT) + + CXXFLAGS="$ac_save_CXXFLAGS" + LIBS="$ac_save_LIBS" + AC_LANG_RESTORE +]) + +dnl dnl Check whether sysctl is available in <pthread.h>, and define _GLIBCXX_USE_SYSCTL_HW_NCPU. dnl AC_DEFUN([GLIBCXX_CHECK_SYSCTL_HW_NCPU], [ diff --git a/libstdc++-v3/config.h.in b/libstdc++-v3/config.h.in index 99286e6..3d13402 100644 --- a/libstdc++-v3/config.h.in +++ b/libstdc++-v3/config.h.in @@ -991,6 +991,9 @@ /* Define if pthreads_num_processors_np is available in <pthread.h>. */ #undef _GLIBCXX_USE_PTHREADS_NUM_PROCESSORS_NP +/* Define if pthread_cond_clockwait is available in <pthread.h>. */ +#undef _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT + /* Define if POSIX read/write locks are available in <gthr.h>. */ #undef _GLIBCXX_USE_PTHREAD_RWLOCK_T diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure index ab46399..c0b98d8 100755 --- a/libstdc++-v3/configure +++ b/libstdc++-v3/configure @@ -21581,6 +21581,89 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu +# For pthread_cond_clockwait + + + + ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + ac_save_CXXFLAGS="$CXXFLAGS" + CXXFLAGS="$CXXFLAGS -fno-exceptions" + ac_save_LIBS="$LIBS" + LIBS="$LIBS -lpthread" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_cond_clockwait" >&5 +$as_echo_n "checking for pthread_cond_clockwait... " >&6; } + if test "${glibcxx_cv_PTHREAD_COND_CLOCKWAIT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + + if test x$gcc_no_link = xyes; then + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <pthread.h> +int +main () +{ +pthread_mutex_t mutex; pthread_cond_t cond; struct timespec ts; int n = pthread_cond_clockwait(&cond, &mutex, 0, &ts); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + glibcxx_cv_PTHREAD_COND_CLOCKWAIT=yes +else + glibcxx_cv_PTHREAD_COND_CLOCKWAIT=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + if test x$gcc_no_link = xyes; then + as_fn_error "Link tests are not allowed after GCC_NO_EXECUTABLES." "$LINENO" 5 +fi +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <pthread.h> +int +main () +{ +pthread_mutex_t mutex; pthread_cond_t cond; struct timespec ts; int n = pthread_cond_clockwait(&cond, &mutex, 0, &ts); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + glibcxx_cv_PTHREAD_COND_CLOCKWAIT=yes +else + glibcxx_cv_PTHREAD_COND_CLOCKWAIT=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi + +fi + + if test $glibcxx_cv_PTHREAD_COND_CLOCKWAIT = yes; then + +$as_echo "#define _GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT 1" >>confdefs.h + + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $glibcxx_cv_PTHREAD_COND_CLOCKWAIT" >&5 +$as_echo "$glibcxx_cv_PTHREAD_COND_CLOCKWAIT" >&6; } + + CXXFLAGS="$ac_save_CXXFLAGS" + LIBS="$ac_save_LIBS" + ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + ac_fn_c_check_header_mongrel "$LINENO" "locale.h" "ac_cv_header_locale_h" "$ac_includes_default" if test "x$ac_cv_header_locale_h" = xyes; then : diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac index 80d8202..ad4ae0c 100644 --- a/libstdc++-v3/configure.ac +++ b/libstdc++-v3/configure.ac @@ -220,6 +220,9 @@ GLIBCXX_ENABLE_LIBSTDCXX_TIME # Check for tmpnam which is obsolescent in POSIX.1-2008 GLIBCXX_CHECK_TMPNAM +# For pthread_cond_clockwait +GLIBCXX_CHECK_PTHREAD_COND_CLOCKWAIT + AC_LC_MESSAGES # For hardware_concurrency diff --git a/libstdc++-v3/include/std/condition_variable b/libstdc++-v3/include/std/condition_variable index a83996a..0e1bdf7 100644 --- a/libstdc++-v3/include/std/condition_variable +++ b/libstdc++-v3/include/std/condition_variable @@ -35,6 +35,7 @@ # include <bits/c++0x_warning.h> #else +#include <bits/c++config.h> #include <chrono> #include <bits/std_mutex.h> #include <bits/unique_lock.h> @@ -65,8 +66,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// condition_variable class condition_variable { - typedef chrono::system_clock __clock_t; typedef chrono::steady_clock __steady_clock_t; +#if defined(_GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT) + typedef chrono::steady_clock __best_clock_t; +#else + typedef chrono::system_clock __best_clock_t; +#endif + typedef chrono::system_clock __system_clock_t; typedef __gthread_cond_t __native_type; #ifdef __GTHREAD_COND_INIT @@ -101,10 +107,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION wait(__lock); } +#if defined(_GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT) + template<typename _Duration> + cv_status + wait_until(unique_lock<mutex>& __lock, + const chrono::time_point<__steady_clock_t, _Duration>& __atime) + { return __wait_until_impl(__lock, __atime); } +#endif + template<typename _Duration> cv_status wait_until(unique_lock<mutex>& __lock, - const chrono::time_point<__clock_t, _Duration>& __atime) + const chrono::time_point<__system_clock_t, _Duration>& __atime) { return __wait_until_impl(__lock, __atime); } template<typename _Clock, typename _Duration> @@ -112,9 +126,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION wait_until(unique_lock<mutex>& __lock, const chrono::time_point<_Clock, _Duration>& __atime) { - // DR 887 - Sync unknown clock to known clock. const typename _Clock::time_point __c_entry = _Clock::now(); - const __clock_t::time_point __s_entry = __clock_t::now(); + const __best_clock_t::time_point __s_entry = __best_clock_t::now(); const auto __delta = __atime - __c_entry; const auto __s_atime = __s_entry + __delta; @@ -171,10 +184,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { return &_M_cond; } private: +#if defined(_GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT) + template<typename _Dur> + cv_status + __wait_until_impl(unique_lock<mutex>& __lock, + const chrono::time_point<__steady_clock_t, _Dur>& __atime) + { + auto __s = chrono::time_point_cast<chrono::seconds>(__atime); + auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); + + __gthread_time_t __ts = + { + static_cast<std::time_t>(__s.time_since_epoch().count()), + static_cast<long>(__ns.count()) + }; + + pthread_cond_clockwait(&_M_cond, __lock.mutex()->native_handle(), + CLOCK_MONOTONIC, + &__ts); + + return (__steady_clock_t::now() < __atime + ? cv_status::no_timeout : cv_status::timeout); + } +#endif template<typename _Dur> cv_status __wait_until_impl(unique_lock<mutex>& __lock, - const chrono::time_point<__clock_t, _Dur>& __atime) + const chrono::time_point<__system_clock_t, _Dur>& __atime) { auto __s = chrono::time_point_cast<chrono::seconds>(__atime); auto __ns = chrono::duration_cast<chrono::nanoseconds>(__atime - __s); @@ -188,7 +224,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(), &__ts); - return (__clock_t::now() < __atime + return (__system_clock_t::now() < __atime ? cv_status::no_timeout : cv_status::timeout); } }; @@ -208,7 +244,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Like above, but mutex is not required to have try_lock. class condition_variable_any { +#if defined(_GLIBCXX_USE_PTHREAD_COND_CLOCKWAIT) + typedef chrono::steady_clock __clock_t; +#else typedef chrono::system_clock __clock_t; +#endif condition_variable _M_cond; shared_ptr<mutex> _M_mutex;