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:
Jonathan Wakely 2013-11-20 20:59:19 +00:00 committed by Jonathan Wakely
parent a2d0d374f6
commit f2f08be7ea
7 changed files with 161 additions and 43 deletions

View File

@ -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.

View File

@ -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>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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()