mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-01-11 14:25:31 +08:00
re PR libstdc++/49204 ([C++0x] remaining issues in <future>)
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
This commit is contained in:
parent
a2d0d374f6
commit
f2f08be7ea
@ -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.
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -40,8 +40,6 @@ struct work {
|
||||
|
||||
void test01()
|
||||
{
|
||||
bool test __attribute__((unused)) = true;
|
||||
|
||||
mutex m;
|
||||
condition_variable cv;
|
||||
unique_lock<mutex> l(m);
|
||||
@ -50,8 +48,29 @@ void test01()
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user