diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index bdf354b4fa8..92e526776db 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,24 @@ +2008-09-23 Chris Fairles + + * include/std/chrono: If _GLIBCXX_USE_MONOTONIC_CLOCK is defined, don't + typedef monotonic_clock to system_clock and instead declare new class. + * src/chrono.cc: Conditionally define monotonic_clock::now(). + * include/std/condition_variable (wait_until): Throw exception if + __gthread_cond_timedwait returns with error other than timed_out. Use + system_clock as known clock type (__clock_t) and add overloads for known + and unknown clocks. In the unknown case, sync to the known clock. + Implement overload taking a predicate. + (wait_for): Implement overload taking a predicate. + * config/abi/pre/gnu.ver: Add exports for monotonic_clock. + * testsuite/30_threads/condition_variable_any/cons/assign_neg.cc: Modify + line numbers. + * testsuite/30_threads/condition_variable_any/cons/copy_neg.cc: + Likewise. + * testsuite/30_threads/condition_variable/cons/assign_neg.cc: Likewise. + * testsuite/30_threads/condition_variable/cons/copy_neg.cc: Likewise. + * testsuite/30_threads/condition_variable/member/1.cc: New. + * testsuite/30_threads/condition_variable/member/2.cc: Likewise. + 2008-09-23 Paolo Carlini PR libstdc++/37624 diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver index df69c87c377..56fa9be3e6e 100644 --- a/libstdc++-v3/config/abi/pre/gnu.ver +++ b/libstdc++-v3/config/abi/pre/gnu.ver @@ -952,6 +952,8 @@ GLIBCXX_3.4.11 { # chrono _ZNSt6chrono12system_clock12is_monotonicE; _ZNSt6chrono12system_clock3nowEv; + _ZNSt6chrono15monotonic_clock12is_monotonicE; + _ZNSt6chrono15monotonic_clock3nowEv; # string/wstring initializer_list overloads _ZNSs6appendESt16initializer_listIcE; diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono index d20c7f45cd9..76dc93ce674 100644 --- a/libstdc++-v3/include/std/chrono +++ b/libstdc++-v3/include/std/chrono @@ -578,8 +578,7 @@ namespace std /// system_clock struct system_clock { -#if defined(_GLIBCXX_USE_CLOCK_MONOTONIC) || \ - defined(_GLIBCXX_USE_CLOCK_REALTIME) +#ifdef _GLIBCXX_USE_CLOCK_REALTIME typedef chrono::nanoseconds duration; #elif defined(_GLIBCXX_USE_GETTIMEOFDAY) typedef chrono::microseconds duration; @@ -591,11 +590,7 @@ namespace std typedef duration::period period; typedef chrono::time_point time_point; -#ifdef _GLIBCXX_USE_CLOCK_MONOTONIC - static const bool is_monotonic = true; -#else static const bool is_monotonic = false; -#endif static time_point now(); @@ -625,8 +620,24 @@ namespace std */ }; +#ifdef _GLIBCXX_USE_CLOCK_MONOTONIC + struct monotonic_clock + { + typedef chrono::nanoseconds duration; + typedef duration::rep rep; + typedef duration::period period; + typedef chrono::time_point time_point; + + static const bool is_monotonic = true; + + static time_point + now(); + }; +#else + typedef system_clock monotonic_clock; +#endif + typedef system_clock high_resolution_clock; - typedef system_clock monotonic_clock; } } diff --git a/libstdc++-v3/include/std/condition_variable b/libstdc++-v3/include/std/condition_variable index f2035d6de73..8325ff1aa95 100644 --- a/libstdc++-v3/include/std/condition_variable +++ b/libstdc++-v3/include/std/condition_variable @@ -50,6 +50,8 @@ namespace std /// condition_variable class condition_variable { + typedef chrono::system_clock __clock_t; + public: typedef __gthread_cond_t* native_handle_type; @@ -76,44 +78,51 @@ namespace std wait(__lock); } - template + template bool - wait_until(unique_lock& __lock, + wait_until(unique_lock& __lock, + const chrono::time_point<__clock_t, _Duration>& __atime) + { return __wait_until_impl(__lock, __atime); } + + template + bool + wait_until(unique_lock& __lock, const chrono::time_point<_Clock, _Duration>& __atime) { - chrono::time_point<_Clock, chrono::seconds> __s = - chrono::time_point_cast(__atime); + // DR 887 - Sync unknown clock to known clock. + typename _Clock::time_point __c_entry = _Clock::now(); + __clock_t::time_point __s_entry = __clock_t::now(); + chrono::nanoseconds __delta = __atime - __c_entry; + __clock_t::time_point __s_atime = __s_entry + __delta; - chrono::nanoseconds __ns = - chrono::duration_cast(__atime - __s); - - __gthread_time_t __ts = { - static_cast(__s.time_since_epoch().count()), - static_cast(__ns.count()) - }; - - __gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(), &__ts); - - return __clock_t::now() < __atime; + return __wait_until_impl(__lock, __s_atime); } template bool wait_until(unique_lock& __lock, const chrono::time_point<_Clock, _Duration>& __atime, - _Predicate __p); + _Predicate __p) + { + while(!__p()) + if(!wait_until(__lock, __atime)) + return __p(); + + return true; + } template bool wait_for(unique_lock& __lock, const chrono::duration<_Rep, _Period>& __rtime) - { return __wait_for_impl(__rtime); } + { return wait_until(__lock, __clock_t::now() + __rtime); } template bool wait_for(unique_lock& __lock, const chrono::duration<_Rep, _Period>& __rtime, - _Predicate __p); + _Predicate __p) + { return wait_until(__lock, __clock_t::now() + __rtime, std::move(__p)); } native_handle_type native_handle() @@ -123,35 +132,28 @@ namespace std __gthread_cond_t _M_cond; mutex _M_internal_mutex; -#ifdef _GLIBCXX_USE_CLOCK_MONOTONIC - typedef chrono::monotonic_clock __clock_t; -#else - typedef chrono::high_resolution_clock __clock_t; -#endif - - template - typename enable_if< - ratio_less_equal<__clock_t::period, _Period>::value, bool>::type - __wait_for_impl(unique_lock& __lock, - const chrono::duration<_Rep, _Period>& __rtime) - { - __clock_t::time_point __atime = __clock_t::now() - + chrono::duration_cast<__clock_t::duration>(__rtime); + template + bool + __wait_until_impl(unique_lock& __lock, + const chrono::time_point<_Clock, _Duration>& __atime) + { + chrono::time_point<__clock_t, chrono::seconds> __s = + chrono::time_point_cast(__atime); - return wait_until(__lock, __atime); + chrono::nanoseconds __ns = + chrono::duration_cast(__atime - __s); + + __gthread_time_t __ts = + { + static_cast(__s.time_since_epoch().count()), + static_cast(__ns.count()) + }; + + __gthread_cond_timedwait(&_M_cond, __lock.mutex()->native_handle(), + &__ts); + + return _Clock::now() < __atime; } - - template - typename enable_if< - !ratio_less_equal<__clock_t::period, _Period>::value, bool>::type - __wait_for_impl(unique_lock& __lock, - const chrono::duration<_Rep, _Period>& __rtime) - { - __clock_t::time_point __atime = __clock_t::now() - + ++chrono::duration_cast<__clock_t::duration>(__rtime); - - return wait_until(__lock, __atime); - } }; /// condition_variable_any diff --git a/libstdc++-v3/src/chrono.cc b/libstdc++-v3/src/chrono.cc index 88fb4c180e9..c44d793cb23 100644 --- a/libstdc++-v3/src/chrono.cc +++ b/libstdc++-v3/src/chrono.cc @@ -47,29 +47,37 @@ namespace std system_clock::time_point system_clock::now() { -#ifdef _GLIBCXX_USE_CLOCK_MONOTONIC - timespec tp; - // -EINVAL, -EFAULT - clock_gettime(CLOCK_MONOTONIC, &tp); - return time_point(duration(chrono::seconds(tp.tv_sec) - + chrono::nanoseconds(tp.tv_nsec))); -#elif defined(_GLIBCXX_USE_CLOCK_REALTIME) - timespec tp; - // -EINVAL, -EFAULT - clock_gettime(CLOCK_REALTIME, &tp); - return time_point(duration(chrono::seconds(tp.tv_sec) - + chrono::nanoseconds(tp.tv_nsec))); +#ifdef _GLIBCXX_USE_CLOCK_REALTIME + timespec tp; + // -EINVAL, -EFAULT + clock_gettime(CLOCK_REALTIME, &tp); + return time_point(duration(chrono::seconds(tp.tv_sec) + + chrono::nanoseconds(tp.tv_nsec))); #elif defined(_GLIBCXX_USE_GETTIMEOFDAY) - timeval tv; - // EINVAL, EFAULT - gettimeofday(&tv, NULL); - return time_point(duration(chrono::seconds(tv.tv_sec) - + chrono::microseconds(tv.tv_usec))); + timeval tv; + // EINVAL, EFAULT + gettimeofday(&tv, NULL); + return time_point(duration(chrono::seconds(tv.tv_sec) + + chrono::microseconds(tv.tv_usec))); #else - std::time_t __sec = std::time(0); - return system_clock::from_time_t(__sec); + std::time_t __sec = std::time(0); + return system_clock::from_time_t(__sec); #endif } + +#ifdef _GLIBCXX_USE_CLOCK_MONOTONIC + const bool monotonic_clock::is_monotonic; + + monotonic_clock::time_point + monotonic_clock::now() + { + timespec tp; + // -EINVAL, -EFAULT + clock_gettime(CLOCK_MONOTONIC, &tp); + return time_point(duration(chrono::seconds(tp.tv_sec) + + chrono::nanoseconds(tp.tv_nsec))); + } +#endif } } diff --git a/libstdc++-v3/src/condition_variable.cc b/libstdc++-v3/src/condition_variable.cc index f1ae33a9bab..cdad0512e73 100644 --- a/libstdc++-v3/src/condition_variable.cc +++ b/libstdc++-v3/src/condition_variable.cc @@ -1,4 +1,4 @@ -// mutex -*- C++ -*- +// condition_variable -*- C++ -*- // Copyright (C) 2008 Free Software Foundation, Inc. // diff --git a/libstdc++-v3/testsuite/30_threads/condition_variable/cons/assign_neg.cc b/libstdc++-v3/testsuite/30_threads/condition_variable/cons/assign_neg.cc index 331a8146ca8..601bd82eedf 100644 --- a/libstdc++-v3/testsuite/30_threads/condition_variable/cons/assign_neg.cc +++ b/libstdc++-v3/testsuite/30_threads/condition_variable/cons/assign_neg.cc @@ -41,4 +41,4 @@ void test01() } // { dg-error "used here" "" { target *-*-* } 40 } -// { dg-error "deleted function" "" { target *-*-* } 60 } +// { dg-error "deleted function" "" { target *-*-* } 62 } diff --git a/libstdc++-v3/testsuite/30_threads/condition_variable/cons/copy_neg.cc b/libstdc++-v3/testsuite/30_threads/condition_variable/cons/copy_neg.cc index 329279f8926..b617c8af4ce 100644 --- a/libstdc++-v3/testsuite/30_threads/condition_variable/cons/copy_neg.cc +++ b/libstdc++-v3/testsuite/30_threads/condition_variable/cons/copy_neg.cc @@ -40,4 +40,4 @@ void test01() } // { dg-error "used here" "" { target *-*-* } 39 } -// { dg-error "deleted function" "" { target *-*-* } 59 } +// { dg-error "deleted function" "" { target *-*-* } 61 } diff --git a/libstdc++-v3/testsuite/30_threads/condition_variable/member/1.cc b/libstdc++-v3/testsuite/30_threads/condition_variable/member/1.cc new file mode 100644 index 00000000000..a4fd9bcb3db --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/condition_variable/member/1.cc @@ -0,0 +1,67 @@ +// { dg-do run { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-solaris* *-*-cygwin *-*-darwin* alpha*-*-osf* mips-sgi-irix6* } } +// { dg-options " -std=gnu++0x -pthread" { target *-*-freebsd* *-*-netbsd* *-*-linux* alpha*-*-osf* mips-sgi-irix6* } } +// { dg-options " -std=gnu++0x -pthreads" { target *-*-solaris* } } +// { dg-options " -std=gnu++0x " { target *-*-cygwin *-*-darwin* } } +// { dg-require-cstdint "" } +// { dg-require-gthreads "" } + +// Copyright (C) 2008 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +// USA. + +// As a special exception, you may use this file as part of a free software +// library without restriction. Specifically, if other files instantiate +// templates or use macros or inline functions from this file, or you compile +// this file and link it with other files to produce an executable, this +// file does not by itself cause the resulting executable to be covered by +// the GNU General Public License. This exception does not however +// invalidate any other reasons why the executable file might be covered by +// the GNU General Public License. + +#include +#include +#include +#include + +int main() +{ + bool test __attribute__((unused)) = true; + + try + { + std::chrono::microseconds ms(500); + std::condition_variable c1; + std::mutex m; + std::unique_lock l(m); + + auto then = std::chrono::system_clock::now(); + bool result = c1.wait_for(l, ms); + VERIFY( !result ); + VERIFY( (std::chrono::system_clock::now() - then) >= ms ); + VERIFY( l.owns_lock() ); + } + catch (const std::system_error& e) + { + VERIFY( false ); + } + catch (...) + { + VERIFY( false ); + } + + return 0; +} diff --git a/libstdc++-v3/testsuite/30_threads/condition_variable/member/2.cc b/libstdc++-v3/testsuite/30_threads/condition_variable/member/2.cc new file mode 100644 index 00000000000..25b3f2437d3 --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/condition_variable/member/2.cc @@ -0,0 +1,67 @@ +// { dg-do run { target *-*-freebsd* *-*-netbsd* *-*-linux* *-*-solaris* *-*-cygwin *-*-darwin* alpha*-*-osf* mips-sgi-irix6* } } +// { dg-options " -std=gnu++0x -pthread" { target *-*-freebsd* *-*-netbsd* *-*-linux* alpha*-*-osf* mips-sgi-irix6* } } +// { dg-options " -std=gnu++0x -pthreads" { target *-*-solaris* } } +// { dg-options " -std=gnu++0x " { target *-*-cygwin *-*-darwin* } } +// { dg-require-cstdint "" } +// { dg-require-gthreads "" } + +// Copyright (C) 2008 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 2, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING. If not, write to the Free +// Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, +// USA. + +// As a special exception, you may use this file as part of a free software +// library without restriction. Specifically, if other files instantiate +// templates or use macros or inline functions from this file, or you compile +// this file and link it with other files to produce an executable, this +// file does not by itself cause the resulting executable to be covered by +// the GNU General Public License. This exception does not however +// invalidate any other reasons why the executable file might be covered by +// the GNU General Public License. + +#include +#include +#include +#include + +int main() +{ + bool test __attribute__((unused)) = true; + + try + { + std::chrono::microseconds ms(500); + std::condition_variable c1; + std::mutex m; + std::unique_lock l(m); + + auto then = std::chrono::monotonic_clock::now(); + bool result = c1.wait_until(l, then + ms); + VERIFY( !result ); + VERIFY( (std::chrono::monotonic_clock::now() - then) >= ms ); + VERIFY( l.owns_lock() ); + } + catch (const std::system_error& e) + { + VERIFY( false ); + } + catch (...) + { + VERIFY( false ); + } + + return 0; +} diff --git a/libstdc++-v3/testsuite/30_threads/condition_variable_any/cons/assign_neg.cc b/libstdc++-v3/testsuite/30_threads/condition_variable_any/cons/assign_neg.cc index 7cdd252a59a..7399ed6f961 100644 --- a/libstdc++-v3/testsuite/30_threads/condition_variable_any/cons/assign_neg.cc +++ b/libstdc++-v3/testsuite/30_threads/condition_variable_any/cons/assign_neg.cc @@ -41,4 +41,4 @@ void test01() } // { dg-error "used here" "" { target *-*-* } 40 } -// { dg-error "deleted function" "" { target *-*-* } 168 } +// { dg-error "deleted function" "" { target *-*-* } 170 } diff --git a/libstdc++-v3/testsuite/30_threads/condition_variable_any/cons/copy_neg.cc b/libstdc++-v3/testsuite/30_threads/condition_variable_any/cons/copy_neg.cc index d71e955800d..86c81a2b914 100644 --- a/libstdc++-v3/testsuite/30_threads/condition_variable_any/cons/copy_neg.cc +++ b/libstdc++-v3/testsuite/30_threads/condition_variable_any/cons/copy_neg.cc @@ -40,4 +40,4 @@ void test01() } // { dg-error "used here" "" { target *-*-* } 39 } -// { dg-error "deleted function" "" { target *-*-* } 167 } +// { dg-error "deleted function" "" { target *-*-* } 169 }