From: Jonathan Wakely Date: Wed, 20 Nov 2013 20:59:19 +0000 (+0000) Subject: re PR libstdc++/49204 ([C++0x] remaining issues in ) X-Git-Tag: upstream/12.2.0~66393 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=f2f08be7ea13b75632f1ecdddbefb928b8fc0fe4;p=platform%2Fupstream%2Fgcc.git re PR libstdc++/49204 ([C++0x] remaining issues in ) PR libstdc++/49204 * include/std/future (__future_base::_State_base): Rename to __future_base::_State_baseV2. (__future_base::_State_baseV2::~_State_baseV2): Define as defaulted. (__future_base::_State_baseV2::_M_run_deferred): Rename to _M_complete_async. (__future_base::_State_baseV2::_M_has_deferred): Add new virtual. (__future_base::_State_baseV2::wait_for): Call _M_has_deferred() to test for a deferred function, or call _M_complete_async() to join an async thread that has made the shared state ready. (__future_base::_State_baseV2::wait_until): Likewise. (__future_base::_Async_state_common): Rename to _Async_state_commonV2. (__future_base::_Async_state_commonV2::_M_run_deferred): Rename to _M_complete_async. * src/c++11/compatibility-thread-c++0x.cc (__future_base::_State_base): Export old definition. (__future_base::_Async_state_common): Likewise. * src/c++11/future.cc (__future_base::_State_base::~_State_base): Remove. * doc/xml/manual/status_cxx2011.xml: Update status. * testsuite/30_threads/async/async.cc: Test future_status::timeout and future_status::ready. * testsuite/30_threads/async/sync.cc: Test future_status::deferred. From-SVN: r205144 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index e989a0d..c1e20c2 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -4,6 +4,30 @@ * include/ext/pointer.h (pointer_traits<>::rebind<>): Add template keyword in nested name. + PR libstdc++/49204 + * include/std/future (__future_base::_State_base): Rename to + __future_base::_State_baseV2. + (__future_base::_State_baseV2::~_State_baseV2): Define as defaulted. + (__future_base::_State_baseV2::_M_run_deferred): Rename to + _M_complete_async. + (__future_base::_State_baseV2::_M_has_deferred): Add new virtual. + (__future_base::_State_baseV2::wait_for): Call _M_has_deferred() to + test for a deferred function, or call _M_complete_async() to join an + async thread that has made the shared state ready. + (__future_base::_State_baseV2::wait_until): Likewise. + (__future_base::_Async_state_common): Rename to _Async_state_commonV2. + (__future_base::_Async_state_commonV2::_M_run_deferred): Rename to + _M_complete_async. + * src/c++11/compatibility-thread-c++0x.cc (__future_base::_State_base): + Export old definition. + (__future_base::_Async_state_common): Likewise. + * src/c++11/future.cc (__future_base::_State_base::~_State_base): + Remove. + * doc/xml/manual/status_cxx2011.xml: Update status. + * testsuite/30_threads/async/async.cc: Test future_status::timeout + and future_status::ready. + * testsuite/30_threads/async/sync.cc: Test future_status::deferred. + 2013-11-20 David Edelsohn * testsuite/17_intro/static.cc: Ignore AIX TOC reload warnings. diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2011.xml b/libstdc++-v3/doc/xml/manual/status_cxx2011.xml index 3c4ec69..bda8a79 100644 --- a/libstdc++-v3/doc/xml/manual/status_cxx2011.xml +++ b/libstdc++-v3/doc/xml/manual/status_cxx2011.xml @@ -2503,18 +2503,16 @@ particular release. Missing set_*_at_thread_exit - 30.6.6 Class template future - Partial - Timed waiting functions do not return future_status::deferred + Y + - 30.6.7 Class template shared_future - Partial - Timed waiting functions do not return future_status::deferred + Y + 30.6.8 diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future index 6d6b32b..b375786 100644 --- a/libstdc++-v3/include/std/future +++ b/libstdc++-v3/include/std/future @@ -298,7 +298,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// Base class for state between a promise and one or more /// associated futures. - class _State_base + class _State_baseV2 { typedef _Ptr<_Result_base> _Ptr_type; @@ -309,15 +309,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION once_flag _M_once; public: - _State_base() noexcept : _M_result(), _M_retrieved(ATOMIC_FLAG_INIT) { } - _State_base(const _State_base&) = delete; - _State_base& operator=(const _State_base&) = delete; - virtual ~_State_base(); + _State_baseV2() noexcept : _M_result(), _M_retrieved(ATOMIC_FLAG_INIT) + { } + _State_baseV2(const _State_baseV2&) = delete; + _State_baseV2& operator=(const _State_baseV2&) = delete; + virtual ~_State_baseV2() = default; _Result_base& wait() { - _M_run_deferred(); + _M_complete_async(); unique_lock __lock(_M_mutex); _M_cond.wait(__lock, [&] { return _M_ready(); }); return *_M_result; @@ -328,8 +329,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION wait_for(const chrono::duration<_Rep, _Period>& __rel) { unique_lock __lock(_M_mutex); - if (_M_cond.wait_for(__lock, __rel, [&] { return _M_ready(); })) + if (_M_ready()) return future_status::ready; + if (_M_has_deferred()) + return future_status::deferred; + if (_M_cond.wait_for(__lock, __rel, [&] { return _M_ready(); })) + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2100. timed waiting functions must also join + _M_complete_async(); + return future_status::ready; + } return future_status::timeout; } @@ -338,8 +348,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION wait_until(const chrono::time_point<_Clock, _Duration>& __abs) { unique_lock __lock(_M_mutex); - if (_M_cond.wait_until(__lock, __abs, [&] { return _M_ready(); })) + if (_M_ready()) return future_status::ready; + if (_M_has_deferred()) + return future_status::deferred; + if (_M_cond.wait_until(__lock, __abs, [&] { return _M_ready(); })) + { + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 2100. timed waiting functions must also join + _M_complete_async(); + return future_status::ready; + } return future_status::timeout; } @@ -349,7 +368,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool __set = __ignore_failure; // all calls to this function are serialized, // side-effects of invoking __res only happen once - call_once(_M_once, &_State_base::_M_do_set, this, ref(__res), + call_once(_M_once, &_State_baseV2::_M_do_set, this, ref(__res), ref(__set)); if (!__set) __throw_future_error(int(future_errc::promise_already_satisfied)); @@ -393,7 +412,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION typename promise<_Res>::_Ptr_type operator()() { - _State_base::_S_check(_M_promise->_M_future); + _State_baseV2::_S_check(_M_promise->_M_future); _M_promise->_M_storage->_M_set(_M_arg); return std::move(_M_promise->_M_storage); } @@ -407,7 +426,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { typename promise<_Res>::_Ptr_type operator()() { - _State_base::_S_check(_M_promise->_M_future); + _State_baseV2::_S_check(_M_promise->_M_future); _M_promise->_M_storage->_M_set(std::move(_M_arg)); return std::move(_M_promise->_M_storage); } @@ -423,7 +442,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { typename promise<_Res>::_Ptr_type operator()() { - _State_base::_S_check(_M_promise->_M_future); + _State_baseV2::_S_check(_M_promise->_M_future); _M_promise->_M_storage->_M_error = _M_ex; return std::move(_M_promise->_M_storage); } @@ -472,15 +491,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bool _M_ready() const noexcept { return static_cast(_M_result); } - // Misnamed: waits for completion of async function. - virtual void _M_run_deferred() { } + // Wait for completion of async function. + virtual void _M_complete_async() { } + + // Return true if state contains a deferred function. + virtual bool _M_has_deferred() const { return false; } }; +#ifdef _GLIBCXX_ASYNC_ABI_COMPAT + class _State_base; + class _Async_state_common; +#else + using _State_base = _State_baseV2; + class _Async_state_commonV2; +#endif + template class _Deferred_state; - class _Async_state_common; - template class _Async_state_impl; @@ -538,6 +566,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void _M_destroy() { delete this; } }; +#ifndef _GLIBCXX_ASYNC_ABI_COMPAT /// Common implementation for future and shared_future. template @@ -1439,26 +1468,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _Ptr_type _M_result; _BoundFn _M_fn; + // Run the deferred function. virtual void - _M_run_deferred() + _M_complete_async() { // safe to call multiple times so ignore failure _M_set_result(_S_task_setter(_M_result, _M_fn), true); } + + virtual bool + _M_has_deferred() const { return static_cast(_M_result); } }; - class __future_base::_Async_state_common : public __future_base::_State_base + class __future_base::_Async_state_commonV2 + : public __future_base::_State_base { protected: -#ifdef _GLIBCXX_ASYNC_ABI_COMPAT - ~_Async_state_common(); -#else - ~_Async_state_common() = default; -#endif + ~_Async_state_commonV2() = default; - // Allow non-timed waiting functions to block until the thread completes, - // as if joined. - virtual void _M_run_deferred() { _M_join(); } + // Make waiting functions block until the thread completes, as if joined. + virtual void _M_complete_async() { _M_join(); } void _M_join() { std::call_once(_M_once, &thread::join, ref(_M_thread)); } @@ -1468,7 +1497,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template class __future_base::_Async_state_impl final - : public __future_base::_Async_state_common + : public __future_base::_Async_state_commonV2 { public: explicit @@ -1536,6 +1565,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION std::forward<_Args>(__args)...); } +#endif // _GLIBCXX_ASYNC_ABI_COMPAT #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 // && ATOMIC_INT_LOCK_FREE diff --git a/libstdc++-v3/src/c++11/compatibility-thread-c++0x.cc b/libstdc++-v3/src/c++11/compatibility-thread-c++0x.cc index ecc4ca4..bec7a2b 100644 --- a/libstdc++-v3/src/c++11/compatibility-thread-c++0x.cc +++ b/libstdc++-v3/src/c++11/compatibility-thread-c++0x.cc @@ -23,7 +23,7 @@ // . #include -#if defined(_GLIBCXX_HAVE_TLS) && defined(_GLIBCXX_SHARED) +#if defined(_GLIBCXX_SHARED) #define _GLIBCXX_ASYNC_ABI_COMPAT #endif @@ -78,20 +78,49 @@ _GLIBCXX_ASM_SYMVER(_ZN9__gnu_cxx11try_to_lockE, _ZSt11try_to_lock, GLIBCXX_3.4. // XXX GLIBCXX_ABI Deprecated -// gcc-4.7.0 +// gcc-4.7.0, gcc-4.9.0 // export changes #if defined(_GLIBCXX_HAS_GTHREADS) && defined(_GLIBCXX_USE_C99_STDINT_TR1) \ && (ATOMIC_INT_LOCK_FREE > 1) -#if defined(_GLIBCXX_HAVE_TLS) && defined(_GLIBCXX_SHARED) +#if defined(_GLIBCXX_SHARED) namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION + // Replaced by _State_baseV2 in gcc-4.9.0 + class __future_base::_State_base + { + typedef _Ptr<_Result_base> _Ptr_type; + + _Ptr_type _M_result; + mutex _M_mutex; + condition_variable _M_cond; + atomic_flag _M_retrieved; + once_flag _M_once; + public: + virtual ~_State_base(); + virtual void _M_run_deferred() { } + }; + __future_base::_State_base::~_State_base() { } + + // Replaced by _Async_state_commonV2 in gcc-4.9.0 + class __future_base::_Async_state_common : public __future_base::_State_base + { + protected: + ~_Async_state_common(); + virtual void _M_run_deferred() { _M_join(); } + void _M_join() { std::call_once(_M_once, &thread::join, ref(_M_thread)); } + thread _M_thread; + once_flag _M_once; + }; +#if defined(_GLIBCXX_HAVE_TLS) + // Replaced with inline definition in gcc-4.8.0 __future_base::_Async_state_common::~_Async_state_common() { _M_join(); } // Explicit instantiation due to -fno-implicit-instantiation. template void call_once(once_flag&, void (thread::*&&)(), reference_wrapper&&); template _Bind_simple_helper>::__type __bind_simple(void (thread::*&&)(), reference_wrapper&&); +#endif // _GLIBCXX_HAVE_TLS _GLIBCXX_END_NAMESPACE_VERSION } // namespace std -#endif +#endif // _GLIBCXX_SHARED #endif // _GLIBCXX_HAS_GTHREADS && _GLIBCXX_USE_C99_STDINT_TR1 diff --git a/libstdc++-v3/src/c++11/future.cc b/libstdc++-v3/src/c++11/future.cc index 906ded5..e253ac3 100644 --- a/libstdc++-v3/src/c++11/future.cc +++ b/libstdc++-v3/src/c++11/future.cc @@ -82,8 +82,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __future_base::_Result_base::_Result_base() = default; __future_base::_Result_base::~_Result_base() = default; - - __future_base::_State_base::~_State_base() = default; #endif _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/testsuite/30_threads/async/async.cc b/libstdc++-v3/testsuite/30_threads/async/async.cc index f2ce205..1f94494 100644 --- a/libstdc++-v3/testsuite/30_threads/async/async.cc +++ b/libstdc++-v3/testsuite/30_threads/async/async.cc @@ -40,18 +40,37 @@ struct work { void test01() { + mutex m; + condition_variable cv; + unique_lock l(m); + future f1 = async(launch::async, work(), ref(m), ref(cv)); + cv.wait(l); + f1.get(); +} + +void test02() +{ bool test __attribute__((unused)) = true; mutex m; condition_variable cv; unique_lock l(m); future f1 = async(launch::async, work(), ref(m), ref(cv)); + std::future_status status; + status = f1.wait_for(std::chrono::milliseconds(1)); + VERIFY( status == std::future_status::timeout ); + status = f1.wait_until(std::chrono::system_clock::now()); + VERIFY( status == std::future_status::timeout ); cv.wait(l); - f1.get(); + status = f1.wait_for(std::chrono::milliseconds(0)); + VERIFY( status == std::future_status::ready ); + status = f1.wait_until(std::chrono::system_clock::now()); + VERIFY( status == std::future_status::ready ); } int main() { test01(); + test02(); return 0; } diff --git a/libstdc++-v3/testsuite/30_threads/async/sync.cc b/libstdc++-v3/testsuite/30_threads/async/sync.cc index e9b112d..3e9cd34 100644 --- a/libstdc++-v3/testsuite/30_threads/async/sync.cc +++ b/libstdc++-v3/testsuite/30_threads/async/sync.cc @@ -39,12 +39,32 @@ void test01() using namespace std; int a = 1; - int b = 10; - int c = 100; + int b = 1; + int c = 1; future f1 = async(launch::deferred, sum(), a, ref(b), cref(c)); + a = 0; + b = 10; + c = 100; + + const std::chrono::seconds delay(10); + const auto then = std::chrono::system_clock::now() + delay; VERIFY( f1.valid() ); + // timed waiting functions should return 'deferred' immediately + VERIFY( f1.wait_until(then) == std::future_status::deferred ); + VERIFY( f1.wait_for(delay) == std::future_status::deferred ); + VERIFY( std::chrono::system_clock::now() < then ); + + f1.wait(); + + VERIFY( f1.valid() ); + // timed waiting functions should return 'ready' immediately + VERIFY( f1.wait_until(then) == std::future_status::ready ); + VERIFY( f1.wait_for(delay) == std::future_status::ready ); + VERIFY( std::chrono::system_clock::now() < then ); + VERIFY( f1.get() == 111 ); + VERIFY( !f1.valid() ); } int main()