summaryrefslogtreecommitdiffstats
path: root/libstdc++-v3
diff options
context:
space:
mode:
authorredi <redi@138bc75d-0d04-0410-961f-82ee72b054a4>2013-11-20 20:59:19 +0000
committerredi <redi@138bc75d-0d04-0410-961f-82ee72b054a4>2013-11-20 20:59:19 +0000
commite95391f67ab448fda23c6ec5f29d473992ac45ec (patch)
tree52b3906db49c694dccf669aa2f545f7476b715f0 /libstdc++-v3
parent7619e6123badd33990e4d1ed7dd19a4c25a2c88e (diff)
downloadppe42-gcc-e95391f67ab448fda23c6ec5f29d473992ac45ec.tar.gz
ppe42-gcc-e95391f67ab448fda23c6ec5f29d473992ac45ec.zip
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@205144 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libstdc++-v3')
-rw-r--r--libstdc++-v3/ChangeLog24
-rw-r--r--libstdc++-v3/doc/xml/manual/status_cxx2011.xml10
-rw-r--r--libstdc++-v3/include/std/future84
-rw-r--r--libstdc++-v3/src/c++11/compatibility-thread-c++0x.cc37
-rw-r--r--libstdc++-v3/src/c++11/future.cc2
-rw-r--r--libstdc++-v3/testsuite/30_threads/async/async.cc21
-rw-r--r--libstdc++-v3/testsuite/30_threads/async/sync.cc24
7 files changed, 160 insertions, 42 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index e989a0d1471..c1e20c2c8e4 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 <dje.gcc@gmail.com>
* 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 3c4ec69dcad..bda8a79a30d 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.
<entry>Missing set_*_at_thread_exit</entry>
</row>
<row>
- <?dbhtml bgcolor="#B0B0B0" ?>
<entry>30.6.6</entry>
<entry>Class template <code>future</code></entry>
- <entry>Partial</entry>
- <entry>Timed waiting functions do not return future_status::deferred</entry>
+ <entry>Y</entry>
+ <entry/>
</row>
<row>
- <?dbhtml bgcolor="#B0B0B0" ?>
<entry>30.6.7</entry>
<entry>Class template <code>shared_future</code></entry>
- <entry>Partial</entry>
- <entry>Timed waiting functions do not return future_status::deferred</entry>
+ <entry>Y</entry>
+ <entry/>
</row>
<row>
<entry>30.6.8</entry>
diff --git a/libstdc++-v3/include/std/future b/libstdc++-v3/include/std/future
index 6d6b32b1f4d..b37578600d9 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<mutex> __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<mutex> __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<mutex> __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<bool>(_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<typename _BoundFn, typename = typename _BoundFn::result_type>
class _Deferred_state;
- class _Async_state_common;
-
template<typename _BoundFn, typename = typename _BoundFn::result_type>
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<typename _Res>
@@ -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<bool>(_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<typename _BoundFn, typename _Res>
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 ecc4ca4b558..bec7a2b6a64 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 @@
// <http://www.gnu.org/licenses/>.
#include <bits/c++config.h>
-#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
// <future> 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<thread>&&);
template _Bind_simple_helper<void (thread::*)(), reference_wrapper<thread>>::__type __bind_simple(void (thread::*&&)(), reference_wrapper<thread>&&);
+#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 906ded5476f..e253ac3cee9 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 f2ce205b20d..1f94494d0a3 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<mutex> l(m);
+ future<void> 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<mutex> l(m);
future<void> 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 e9b112ddf57..3e9cd34cd55 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<int> 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()
OpenPOWER on IntegriCloud