From b77c0c03bb5f48c7ff98aa0d8dd5c648e8a1a651 Mon Sep 17 00:00:00 2001 From: Howard Hinnant Date: Fri, 3 Sep 2010 21:46:37 +0000 Subject: [futures.atomic_future] and notify_all_at_thread_exit. This completes the header and all of Chapter 30 (for C++0x enabled compilers). llvm-svn: 113017 --- libcxx/include/condition_variable | 2 + libcxx/include/future | 198 ++++++++++++++++++++- libcxx/include/thread | 1 + libcxx/src/condition_variable.cpp | 6 + libcxx/src/future.cpp | 35 ++++ libcxx/src/thread.cpp | 22 +++ .../futures.atomic_future/copy_assign.pass.cpp | 74 ++++++++ .../futures.atomic_future/copy_ctor.pass.cpp | 66 +++++++ .../futures.atomic_future/ctor_future.pass.cpp | 66 +++++++ .../futures/futures.atomic_future/default.pass.cpp | 33 ++++ .../futures/futures.atomic_future/dtor.pass.cpp | 66 +++++++ .../futures/futures.atomic_future/get.pass.cpp | 143 +++++++++++++++ .../futures/futures.atomic_future/wait.pass.cpp | 86 +++++++++ .../futures.atomic_future/wait_for.pass.cpp | 95 ++++++++++ .../futures.atomic_future/wait_until.pass.cpp | 95 ++++++++++ .../notify_all_at_thread_exit.pass.cpp | 23 ++- .../wait_for_pred.pass.cpp | 2 +- 17 files changed, 1010 insertions(+), 3 deletions(-) create mode 100644 libcxx/test/thread/futures/futures.atomic_future/copy_assign.pass.cpp create mode 100644 libcxx/test/thread/futures/futures.atomic_future/copy_ctor.pass.cpp create mode 100644 libcxx/test/thread/futures/futures.atomic_future/ctor_future.pass.cpp create mode 100644 libcxx/test/thread/futures/futures.atomic_future/default.pass.cpp create mode 100644 libcxx/test/thread/futures/futures.atomic_future/dtor.pass.cpp create mode 100644 libcxx/test/thread/futures/futures.atomic_future/get.pass.cpp create mode 100644 libcxx/test/thread/futures/futures.atomic_future/wait.pass.cpp create mode 100644 libcxx/test/thread/futures/futures.atomic_future/wait_for.pass.cpp create mode 100644 libcxx/test/thread/futures/futures.atomic_future/wait_until.pass.cpp diff --git a/libcxx/include/condition_variable b/libcxx/include/condition_variable index 3e766b6..aacae0a19 100644 --- a/libcxx/include/condition_variable +++ b/libcxx/include/condition_variable @@ -246,6 +246,8 @@ condition_variable_any::wait_for(_Lock& __lock, _STD::move(__pred)); } +void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_CONDITION_VARIABLE diff --git a/libcxx/include/future b/libcxx/include/future index 4189d88..a1f976f2 100644 --- a/libcxx/include/future +++ b/libcxx/include/future @@ -439,7 +439,7 @@ template struct uses_allocator, Alloc>; #include #include #include -#include <__mutex_base> +#include #include #pragma GCC system_header @@ -2066,6 +2066,8 @@ async(_F&& __f, _Args&&... __args) #endif // _LIBCPP_HAS_NO_VARIADICS +// shared_future + template class shared_future { @@ -2244,6 +2246,200 @@ swap(shared_future<_R>& __x, shared_future<_R>& __y) __x.swap(__y); } +// atomic_future + +template +class atomic_future +{ + __assoc_state<_R>* __state_; + mutable mutex __mut_; + +public: + atomic_future() : __state_(nullptr) {} + atomic_future(const atomic_future& __rhs) : __state_(__rhs.__state_) + {if (__state_) __state_->__add_shared();} +#ifdef _LIBCPP_MOVE + atomic_future(future<_R>&& __f) : __state_(__f.__state_) + {__f.__state_ = nullptr;} +#endif // _LIBCPP_MOVE + ~atomic_future(); + atomic_future& operator=(const atomic_future& __rhs); + + // retrieving the value + const _R& get() const {return __state_->copy();} + + void swap(atomic_future& __rhs); + + // functions to check state + bool valid() const {return __state_ != nullptr;} + + void wait() const {__state_->wait();} + template + future_status + wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const + {return __state_->wait_for(__rel_time);} + template + future_status + wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const + {return __state_->wait_until(__abs_time);} +}; + +template +atomic_future<_R>::~atomic_future() +{ + if (__state_) + __state_->__release_shared(); +} + +template +atomic_future<_R>& +atomic_future<_R>::operator=(const atomic_future& __rhs) +{ + if (this != &__rhs) + { + unique_lock __this(__mut_, defer_lock); + unique_lock __that(__rhs.__mut_, defer_lock); + _STD::lock(__this, __that); + if (__rhs.__state_) + __rhs.__state_->__add_shared(); + if (__state_) + __state_->__release_shared(); + __state_ = __rhs.__state_; + } + return *this; +} + +template +void +atomic_future<_R>::swap(atomic_future& __rhs) +{ + if (this != &__rhs) + { + unique_lock __this(__mut_, defer_lock); + unique_lock __that(__rhs.__mut_, defer_lock); + _STD::lock(__this, __that); + _STD::swap(__state_, __rhs.__state_); + } +} + +template +class atomic_future<_R&> +{ + __assoc_state<_R&>* __state_; + mutable mutex __mut_; + +public: + atomic_future() : __state_(nullptr) {} + atomic_future(const atomic_future& __rhs) : __state_(__rhs.__state_) + {if (__state_) __state_->__add_shared();} +#ifdef _LIBCPP_MOVE + atomic_future(future<_R&>&& __f) : __state_(__f.__state_) + {__f.__state_ = nullptr;} +#endif // _LIBCPP_MOVE + ~atomic_future(); + atomic_future& operator=(const atomic_future& __rhs); + + // retrieving the value + _R& get() const {return __state_->copy();} + + void swap(atomic_future& __rhs); + + // functions to check state + bool valid() const {return __state_ != nullptr;} + + void wait() const {__state_->wait();} + template + future_status + wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const + {return __state_->wait_for(__rel_time);} + template + future_status + wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const + {return __state_->wait_until(__abs_time);} +}; + +template +atomic_future<_R&>::~atomic_future() +{ + if (__state_) + __state_->__release_shared(); +} + +template +atomic_future<_R&>& +atomic_future<_R&>::operator=(const atomic_future& __rhs) +{ + if (this != &__rhs) + { + unique_lock __this(__mut_, defer_lock); + unique_lock __that(__rhs.__mut_, defer_lock); + _STD::lock(__this, __that); + if (__rhs.__state_) + __rhs.__state_->__add_shared(); + if (__state_) + __state_->__release_shared(); + __state_ = __rhs.__state_; + } + return *this; +} + +template +void +atomic_future<_R&>::swap(atomic_future& __rhs) +{ + if (this != &__rhs) + { + unique_lock __this(__mut_, defer_lock); + unique_lock __that(__rhs.__mut_, defer_lock); + _STD::lock(__this, __that); + _STD::swap(__state_, __rhs.__state_); + } +} + +template <> +class atomic_future +{ + __assoc_sub_state* __state_; + mutable mutex __mut_; + +public: + atomic_future() : __state_(nullptr) {} + atomic_future(const atomic_future& __rhs) : __state_(__rhs.__state_) + {if (__state_) __state_->__add_shared();} +#ifdef _LIBCPP_MOVE + atomic_future(future&& __f) : __state_(__f.__state_) + {__f.__state_ = nullptr;} +#endif // _LIBCPP_MOVE + ~atomic_future(); + atomic_future& operator=(const atomic_future& __rhs); + + // retrieving the value + void get() const {__state_->copy();} + + void swap(atomic_future& __rhs); + + // functions to check state + bool valid() const {return __state_ != nullptr;} + + void wait() const {__state_->wait();} + template + future_status + wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const + {return __state_->wait_for(__rel_time);} + template + future_status + wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const + {return __state_->wait_until(__abs_time);} +}; + +template +inline _LIBCPP_INLINE_VISIBILITY +void +swap(atomic_future<_R>& __x, atomic_future<_R>& __y) +{ + __x.swap(__y); +} + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_FUTURE diff --git a/libcxx/include/thread b/libcxx/include/thread index 123c472..c380fe6 100644 --- a/libcxx/include/thread +++ b/libcxx/include/thread @@ -295,6 +295,7 @@ public: __thread_struct(); ~__thread_struct(); + void notify_all_at_thread_exit(condition_variable*, mutex*); void __make_ready_at_thread_exit(__assoc_sub_state*); }; diff --git a/libcxx/src/condition_variable.cpp b/libcxx/src/condition_variable.cpp index 7373ec3..3bafa8c 100644 --- a/libcxx/src/condition_variable.cpp +++ b/libcxx/src/condition_variable.cpp @@ -61,4 +61,10 @@ condition_variable::__do_timed_wait(unique_lock& lk, __throw_system_error(ec, "condition_variable timed_wait failed"); } +void +notify_all_at_thread_exit(condition_variable& cond, unique_lock lk) +{ + __thread_local_data->notify_all_at_thread_exit(&cond, lk.release()); +} + _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/src/future.cpp b/libcxx/src/future.cpp index 924a684..ca30803 100644 --- a/libcxx/src/future.cpp +++ b/libcxx/src/future.cpp @@ -257,4 +257,39 @@ shared_future::operator=(const shared_future& __rhs) return *this; } +atomic_future::~atomic_future() +{ + if (__state_) + __state_->__release_shared(); +} + +atomic_future& +atomic_future::operator=(const atomic_future& __rhs) +{ + if (this != &__rhs) + { + unique_lock __this(__mut_, defer_lock); + unique_lock __that(__rhs.__mut_, defer_lock); + _STD::lock(__this, __that); + if (__rhs.__state_) + __rhs.__state_->__add_shared(); + if (__state_) + __state_->__release_shared(); + __state_ = __rhs.__state_; + } + return *this; +} + +void +atomic_future::swap(atomic_future& __rhs) +{ + if (this != &__rhs) + { + unique_lock __this(__mut_, defer_lock); + unique_lock __that(__rhs.__mut_, defer_lock); + _STD::lock(__this, __that); + _STD::swap(__state_, __rhs.__state_); + } +} + _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/src/thread.cpp b/libcxx/src/thread.cpp index f840706..3d388e9 100644 --- a/libcxx/src/thread.cpp +++ b/libcxx/src/thread.cpp @@ -90,7 +90,10 @@ __thread_specific_ptr<__thread_struct> __thread_local_data; class __thread_struct_imp { typedef vector<__assoc_sub_state*> _AsyncStates; + typedef vector > _Notify; + _AsyncStates async_states_; + _Notify notify_; __thread_struct_imp(const __thread_struct_imp&); __thread_struct_imp& operator=(const __thread_struct_imp&); @@ -98,11 +101,18 @@ public: __thread_struct_imp() {} ~__thread_struct_imp(); + void notify_all_at_thread_exit(condition_variable* cv, mutex* m); void __make_ready_at_thread_exit(__assoc_sub_state* __s); }; __thread_struct_imp::~__thread_struct_imp() { + for (_Notify::iterator i = notify_.begin(), e = notify_.end(); + i != e; ++i) + { + i->second->unlock(); + i->first->notify_all(); + } for (_AsyncStates::iterator i = async_states_.begin(), e = async_states_.end(); i != e; ++i) { @@ -112,6 +122,12 @@ __thread_struct_imp::~__thread_struct_imp() } void +__thread_struct_imp::notify_all_at_thread_exit(condition_variable* cv, mutex* m) +{ + notify_.push_back(pair(cv, m)); +} + +void __thread_struct_imp::__make_ready_at_thread_exit(__assoc_sub_state* __s) { async_states_.push_back(__s); @@ -131,6 +147,12 @@ __thread_struct::~__thread_struct() } void +__thread_struct::notify_all_at_thread_exit(condition_variable* cv, mutex* m) +{ + __p_->notify_all_at_thread_exit(cv, m); +} + +void __thread_struct::__make_ready_at_thread_exit(__assoc_sub_state* __s) { __p_->__make_ready_at_thread_exit(__s); diff --git a/libcxx/test/thread/futures/futures.atomic_future/copy_assign.pass.cpp b/libcxx/test/thread/futures/futures.atomic_future/copy_assign.pass.cpp new file mode 100644 index 0000000..bd17f88 --- /dev/null +++ b/libcxx/test/thread/futures/futures.atomic_future/copy_assign.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class atomic_future + +// atomic_future& operator=(const atomic_future& rhs); + +#include +#include + +int main() +{ +#ifdef _LIBCPP_MOVE + { + typedef int T; + std::promise p; + std::atomic_future f0 = p.get_future(); + std::atomic_future f; + f = f0; + assert(f0.valid()); + assert(f.valid()); + } + { + typedef int T; + std::atomic_future f0; + std::atomic_future f; + f = f0; + assert(!f0.valid()); + assert(!f.valid()); + } + { + typedef int& T; + std::promise p; + std::atomic_future f0 = p.get_future(); + std::atomic_future f; + f = f0; + assert(f0.valid()); + assert(f.valid()); + } + { + typedef int& T; + std::atomic_future f0; + std::atomic_future f; + f = f0; + assert(!f0.valid()); + assert(!f.valid()); + } + { + typedef void T; + std::promise p; + std::atomic_future f0 = p.get_future(); + std::atomic_future f; + f = f0; + assert(f0.valid()); + assert(f.valid()); + } + { + typedef void T; + std::atomic_future f0; + std::atomic_future f; + f = f0; + assert(!f0.valid()); + assert(!f.valid()); + } +#endif // _LIBCPP_MOVE +} diff --git a/libcxx/test/thread/futures/futures.atomic_future/copy_ctor.pass.cpp b/libcxx/test/thread/futures/futures.atomic_future/copy_ctor.pass.cpp new file mode 100644 index 0000000..a433812 --- /dev/null +++ b/libcxx/test/thread/futures/futures.atomic_future/copy_ctor.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class atomic_future + +// atomic_future(const atomic_future& rhs); + +#include +#include + +int main() +{ + { + typedef int T; + std::promise p; + std::atomic_future f0 = p.get_future(); + std::atomic_future f = f0; + assert(f0.valid()); + assert(f.valid()); + } + { + typedef int T; + std::atomic_future f0; + std::atomic_future f = f0; + assert(!f0.valid()); + assert(!f.valid()); + } + { + typedef int& T; + std::promise p; + std::atomic_future f0 = p.get_future(); + std::atomic_future f = f0; + assert(f0.valid()); + assert(f.valid()); + } + { + typedef int& T; + std::atomic_future f0; + std::atomic_future f = std::move(f0); + assert(!f0.valid()); + assert(!f.valid()); + } + { + typedef void T; + std::promise p; + std::atomic_future f0 = p.get_future(); + std::atomic_future f = f0; + assert(f0.valid()); + assert(f.valid()); + } + { + typedef void T; + std::atomic_future f0; + std::atomic_future f = f0; + assert(!f0.valid()); + assert(!f.valid()); + } +} diff --git a/libcxx/test/thread/futures/futures.atomic_future/ctor_future.pass.cpp b/libcxx/test/thread/futures/futures.atomic_future/ctor_future.pass.cpp new file mode 100644 index 0000000..db0e423 --- /dev/null +++ b/libcxx/test/thread/futures/futures.atomic_future/ctor_future.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class atomic_future + +// atomic_future(future&& rhs); + +#include +#include + +int main() +{ + { + typedef int T; + std::promise p; + std::future f0 = p.get_future(); + std::atomic_future f = std::move(f0); + assert(!f0.valid()); + assert(f.valid()); + } + { + typedef int T; + std::future f0; + std::atomic_future f = std::move(f0); + assert(!f0.valid()); + assert(!f.valid()); + } + { + typedef int& T; + std::promise p; + std::future f0 = p.get_future(); + std::atomic_future f = std::move(f0); + assert(!f0.valid()); + assert(f.valid()); + } + { + typedef int& T; + std::future f0; + std::atomic_future f = std::move(f0); + assert(!f0.valid()); + assert(!f.valid()); + } + { + typedef void T; + std::promise p; + std::future f0 = p.get_future(); + std::atomic_future f = std::move(f0); + assert(!f0.valid()); + assert(f.valid()); + } + { + typedef void T; + std::future f0; + std::atomic_future f = std::move(f0); + assert(!f0.valid()); + assert(!f.valid()); + } +} diff --git a/libcxx/test/thread/futures/futures.atomic_future/default.pass.cpp b/libcxx/test/thread/futures/futures.atomic_future/default.pass.cpp new file mode 100644 index 0000000..98d5504 --- /dev/null +++ b/libcxx/test/thread/futures/futures.atomic_future/default.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class atomic_future + +// atomic_future(); + +#include +#include + +int main() +{ + { + std::atomic_future f; + assert(!f.valid()); + } + { + std::atomic_future f; + assert(!f.valid()); + } + { + std::atomic_future f; + assert(!f.valid()); + } +} diff --git a/libcxx/test/thread/futures/futures.atomic_future/dtor.pass.cpp b/libcxx/test/thread/futures/futures.atomic_future/dtor.pass.cpp new file mode 100644 index 0000000..a71b523 --- /dev/null +++ b/libcxx/test/thread/futures/futures.atomic_future/dtor.pass.cpp @@ -0,0 +1,66 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class atomic_future + +// ~atomic_future(); + +#include +#include + +#include "../test_allocator.h" + +int main() +{ + assert(test_alloc_base::count == 0); + { + typedef int T; + std::atomic_future f; + { + std::promise p(std::allocator_arg, test_allocator()); + assert(test_alloc_base::count == 1); + f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + } + assert(test_alloc_base::count == 1); + assert(f.valid()); + } + assert(test_alloc_base::count == 0); + { + typedef int& T; + std::atomic_future f; + { + std::promise p(std::allocator_arg, test_allocator()); + assert(test_alloc_base::count == 1); + f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + } + assert(test_alloc_base::count == 1); + assert(f.valid()); + } + assert(test_alloc_base::count == 0); + { + typedef void T; + std::atomic_future f; + { + std::promise p(std::allocator_arg, test_allocator()); + assert(test_alloc_base::count == 1); + f = p.get_future(); + assert(test_alloc_base::count == 1); + assert(f.valid()); + } + assert(test_alloc_base::count == 1); + assert(f.valid()); + } + assert(test_alloc_base::count == 0); +} diff --git a/libcxx/test/thread/futures/futures.atomic_future/get.pass.cpp b/libcxx/test/thread/futures/futures.atomic_future/get.pass.cpp new file mode 100644 index 0000000..db0ad95 --- /dev/null +++ b/libcxx/test/thread/futures/futures.atomic_future/get.pass.cpp @@ -0,0 +1,143 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class atomic_future + +// const R& atomic_future::get(); +// R& atomic_future::get(); +// void atomic_future::get(); + +#include +#include + +void func1(std::promise& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + p.set_value(3); +} + +void func2(std::promise& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + p.set_exception(std::make_exception_ptr(3)); +} + +int j = 0; + +void func3(std::promise& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + j = 5; + p.set_value(j); +} + +void func4(std::promise& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + p.set_exception(std::make_exception_ptr(3.5)); +} + +void func5(std::promise& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + p.set_value(); +} + +void func6(std::promise& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + p.set_exception(std::make_exception_ptr('c')); +} + +int main() +{ + { + typedef int T; + { + std::promise p; + std::atomic_future f = p.get_future(); + std::thread(func1, std::move(p)).detach(); + assert(f.valid()); + assert(f.get() == 3); + assert(f.valid()); + } + { + std::promise p; + std::atomic_future f = p.get_future(); + std::thread(func2, std::move(p)).detach(); + try + { + assert(f.valid()); + assert(f.get() == 3); + assert(false); + } + catch (int i) + { + assert(i == 3); + } + assert(f.valid()); + } + } + { + typedef int& T; + { + std::promise p; + std::atomic_future f = p.get_future(); + std::thread(func3, std::move(p)).detach(); + assert(f.valid()); + assert(f.get() == 5); + assert(f.valid()); + } + { + std::promise p; + std::atomic_future f = p.get_future(); + std::thread(func4, std::move(p)).detach(); + try + { + assert(f.valid()); + assert(f.get() == 3); + assert(false); + } + catch (double i) + { + assert(i == 3.5); + } + assert(f.valid()); + } + } + { + typedef void T; + { + std::promise p; + std::atomic_future f = p.get_future(); + std::thread(func5, std::move(p)).detach(); + assert(f.valid()); + f.get(); + assert(f.valid()); + } + { + std::promise p; + std::atomic_future f = p.get_future(); + std::thread(func6, std::move(p)).detach(); + try + { + assert(f.valid()); + f.get(); + assert(false); + } + catch (char i) + { + assert(i == 'c'); + } + assert(f.valid()); + } + } +} diff --git a/libcxx/test/thread/futures/futures.atomic_future/wait.pass.cpp b/libcxx/test/thread/futures/futures.atomic_future/wait.pass.cpp new file mode 100644 index 0000000..b8810d2 --- /dev/null +++ b/libcxx/test/thread/futures/futures.atomic_future/wait.pass.cpp @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class atomic_future + +// void wait() const; + +#include +#include + +void func1(std::promise& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + p.set_value(3); +} + +int j = 0; + +void func3(std::promise& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + j = 5; + p.set_value(j); +} + +void func5(std::promise& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + p.set_value(); +} + +int main() +{ + typedef std::chrono::high_resolution_clock Clock; + typedef std::chrono::duration ms; + { + typedef int T; + std::promise p; + std::atomic_future f = p.get_future(); + std::thread(func1, std::move(p)).detach(); + assert(f.valid()); + f.wait(); + assert(f.valid()); + Clock::time_point t0 = Clock::now(); + f.wait(); + Clock::time_point t1 = Clock::now(); + assert(f.valid()); + assert(t1-t0 < ms(5)); + } + { + typedef int& T; + std::promise p; + std::atomic_future f = p.get_future(); + std::thread(func3, std::move(p)).detach(); + assert(f.valid()); + f.wait(); + assert(f.valid()); + Clock::time_point t0 = Clock::now(); + f.wait(); + Clock::time_point t1 = Clock::now(); + assert(f.valid()); + assert(t1-t0 < ms(5)); + } + { + typedef void T; + std::promise p; + std::atomic_future f = p.get_future(); + std::thread(func5, std::move(p)).detach(); + assert(f.valid()); + f.wait(); + assert(f.valid()); + Clock::time_point t0 = Clock::now(); + f.wait(); + Clock::time_point t1 = Clock::now(); + assert(f.valid()); + assert(t1-t0 < ms(5)); + } +} diff --git a/libcxx/test/thread/futures/futures.atomic_future/wait_for.pass.cpp b/libcxx/test/thread/futures/futures.atomic_future/wait_for.pass.cpp new file mode 100644 index 0000000..0a544ef --- /dev/null +++ b/libcxx/test/thread/futures/futures.atomic_future/wait_for.pass.cpp @@ -0,0 +1,95 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class atomic_future + +// template +// future_status +// wait_for(const chrono::duration& rel_time) const; + +#include +#include + +typedef std::chrono::milliseconds ms; + +void func1(std::promise& p) +{ + std::this_thread::sleep_for(ms(500)); + p.set_value(3); +} + +int j = 0; + +void func3(std::promise& p) +{ + std::this_thread::sleep_for(ms(500)); + j = 5; + p.set_value(j); +} + +void func5(std::promise& p) +{ + std::this_thread::sleep_for(ms(500)); + p.set_value(); +} + +int main() +{ + typedef std::chrono::high_resolution_clock Clock; + { + typedef int T; + std::promise p; + std::atomic_future f = p.get_future(); + std::thread(func1, std::move(p)).detach(); + assert(f.valid()); + assert(f.wait_for(ms(300)) == std::future_status::timeout); + assert(f.valid()); + assert(f.wait_for(ms(300)) == std::future_status::ready); + assert(f.valid()); + Clock::time_point t0 = Clock::now(); + f.wait(); + Clock::time_point t1 = Clock::now(); + assert(f.valid()); + assert(t1-t0 < ms(5)); + } + { + typedef int& T; + std::promise p; + std::atomic_future f = p.get_future(); + std::thread(func3, std::move(p)).detach(); + assert(f.valid()); + assert(f.wait_for(ms(300)) == std::future_status::timeout); + assert(f.valid()); + assert(f.wait_for(ms(300)) == std::future_status::ready); + assert(f.valid()); + Clock::time_point t0 = Clock::now(); + f.wait(); + Clock::time_point t1 = Clock::now(); + assert(f.valid()); + assert(t1-t0 < ms(5)); + } + { + typedef void T; + std::promise p; + std::atomic_future f = p.get_future(); + std::thread(func5, std::move(p)).detach(); + assert(f.valid()); + assert(f.wait_for(ms(300)) == std::future_status::timeout); + assert(f.valid()); + assert(f.wait_for(ms(300)) == std::future_status::ready); + assert(f.valid()); + Clock::time_point t0 = Clock::now(); + f.wait(); + Clock::time_point t1 = Clock::now(); + assert(f.valid()); + assert(t1-t0 < ms(5)); + } +} diff --git a/libcxx/test/thread/futures/futures.atomic_future/wait_until.pass.cpp b/libcxx/test/thread/futures/futures.atomic_future/wait_until.pass.cpp new file mode 100644 index 0000000..e127041 --- /dev/null +++ b/libcxx/test/thread/futures/futures.atomic_future/wait_until.pass.cpp @@ -0,0 +1,95 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// class atomic_future + +// template +// future_status +// wait_until(const chrono::time_point& abs_time) const; + +#include +#include + +typedef std::chrono::milliseconds ms; + +void func1(std::promise& p) +{ + std::this_thread::sleep_for(ms(500)); + p.set_value(3); +} + +int j = 0; + +void func3(std::promise& p) +{ + std::this_thread::sleep_for(ms(500)); + j = 5; + p.set_value(j); +} + +void func5(std::promise& p) +{ + std::this_thread::sleep_for(ms(500)); + p.set_value(); +} + +int main() +{ + typedef std::chrono::high_resolution_clock Clock; + { + typedef int T; + std::promise p; + std::atomic_future f = p.get_future(); + std::thread(func1, std::move(p)).detach(); + assert(f.valid()); + assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::timeout); + assert(f.valid()); + assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::ready); + assert(f.valid()); + Clock::time_point t0 = Clock::now(); + f.wait(); + Clock::time_point t1 = Clock::now(); + assert(f.valid()); + assert(t1-t0 < ms(5)); + } + { + typedef int& T; + std::promise p; + std::atomic_future f = p.get_future(); + std::thread(func3, std::move(p)).detach(); + assert(f.valid()); + assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::timeout); + assert(f.valid()); + assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::ready); + assert(f.valid()); + Clock::time_point t0 = Clock::now(); + f.wait(); + Clock::time_point t1 = Clock::now(); + assert(f.valid()); + assert(t1-t0 < ms(5)); + } + { + typedef void T; + std::promise p; + std::atomic_future f = p.get_future(); + std::thread(func5, std::move(p)).detach(); + assert(f.valid()); + assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::timeout); + assert(f.valid()); + assert(f.wait_until(Clock::now() + ms(300)) == std::future_status::ready); + assert(f.valid()); + Clock::time_point t0 = Clock::now(); + f.wait(); + Clock::time_point t1 = Clock::now(); + assert(f.valid()); + assert(t1-t0 < ms(5)); + } +} diff --git a/libcxx/test/thread/thread.condition/notify_all_at_thread_exit.pass.cpp b/libcxx/test/thread/thread.condition/notify_all_at_thread_exit.pass.cpp index 6cc9067..6584a77 100644 --- a/libcxx/test/thread/thread.condition/notify_all_at_thread_exit.pass.cpp +++ b/libcxx/test/thread/thread.condition/notify_all_at_thread_exit.pass.cpp @@ -13,9 +13,30 @@ // notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); #include +#include +#include +#include #include +std::condition_variable cv; +std::mutex mut; + +typedef std::chrono::milliseconds ms; +typedef std::chrono::high_resolution_clock Clock; + +void func() +{ + std::unique_lock lk(mut); + std::notify_all_at_thread_exit(cv, std::move(lk)); + std::this_thread::sleep_for(ms(300)); +} + int main() { -#error notify_all_at_thread_exit not implemented + std::unique_lock lk(mut); + std::thread(func).detach(); + Clock::time_point t0 = Clock::now(); + cv.wait(lk); + Clock::time_point t1 = Clock::now(); + assert(t1-t0 > ms(250)); } diff --git a/libcxx/test/thread/thread.condition/thread.condition.condvarany/wait_for_pred.pass.cpp b/libcxx/test/thread/thread.condition/thread.condition.condvarany/wait_for_pred.pass.cpp index a0e347d..ac071d0 100644 --- a/libcxx/test/thread/thread.condition/thread.condition.condvarany/wait_for_pred.pass.cpp +++ b/libcxx/test/thread/thread.condition/thread.condition.condvarany/wait_for_pred.pass.cpp @@ -61,7 +61,7 @@ void f() } else { - assert(t1 - t0 - milliseconds(250) < milliseconds(2)); + assert(t1 - t0 - milliseconds(250) < milliseconds(5)); assert(test2 == 0); } ++runs; -- cgit v1.1