diff options
author | Howard Hinnant <hhinnant@apple.com> | 2010-09-03 21:46:37 +0000 |
---|---|---|
committer | Howard Hinnant <hhinnant@apple.com> | 2010-09-03 21:46:37 +0000 |
commit | b77c0c03bb5f48c7ff98aa0d8dd5c648e8a1a651 (patch) | |
tree | 51b1ae1903851f02fc0104ff07339673c7e83f73 | |
parent | 005155e236afd14f9cc1342a213f050287e9bb26 (diff) | |
download | bcm5719-llvm-b77c0c03bb5f48c7ff98aa0d8dd5c648e8a1a651.tar.gz bcm5719-llvm-b77c0c03bb5f48c7ff98aa0d8dd5c648e8a1a651.zip |
[futures.atomic_future] and notify_all_at_thread_exit. This completes the header <future> and all of Chapter 30 (for C++0x enabled compilers).
llvm-svn: 113017
17 files changed, 1010 insertions, 3 deletions
diff --git a/libcxx/include/condition_variable b/libcxx/include/condition_variable index 3e766b6cd9c..aacae0a19ee 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<mutex> lk); + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP_CONDITION_VARIABLE diff --git a/libcxx/include/future b/libcxx/include/future index 4189d88165e..a1f976f2925 100644 --- a/libcxx/include/future +++ b/libcxx/include/future @@ -439,7 +439,7 @@ template <class R, class Alloc> struct uses_allocator<packaged_task<R>, Alloc>; #include <memory> #include <chrono> #include <exception> -#include <__mutex_base> +#include <mutex> #include <thread> #pragma GCC system_header @@ -2066,6 +2066,8 @@ async(_F&& __f, _Args&&... __args) #endif // _LIBCPP_HAS_NO_VARIADICS +// shared_future + template <class _R> class shared_future { @@ -2244,6 +2246,200 @@ swap(shared_future<_R>& __x, shared_future<_R>& __y) __x.swap(__y); } +// atomic_future + +template <class _R> +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 <class _Rep, class _Period> + future_status + wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const + {return __state_->wait_for(__rel_time);} + template <class _Clock, class _Duration> + future_status + wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const + {return __state_->wait_until(__abs_time);} +}; + +template <class _R> +atomic_future<_R>::~atomic_future() +{ + if (__state_) + __state_->__release_shared(); +} + +template <class _R> +atomic_future<_R>& +atomic_future<_R>::operator=(const atomic_future& __rhs) +{ + if (this != &__rhs) + { + unique_lock<mutex> __this(__mut_, defer_lock); + unique_lock<mutex> __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 <class _R> +void +atomic_future<_R>::swap(atomic_future& __rhs) +{ + if (this != &__rhs) + { + unique_lock<mutex> __this(__mut_, defer_lock); + unique_lock<mutex> __that(__rhs.__mut_, defer_lock); + _STD::lock(__this, __that); + _STD::swap(__state_, __rhs.__state_); + } +} + +template <class _R> +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 <class _Rep, class _Period> + future_status + wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const + {return __state_->wait_for(__rel_time);} + template <class _Clock, class _Duration> + future_status + wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const + {return __state_->wait_until(__abs_time);} +}; + +template <class _R> +atomic_future<_R&>::~atomic_future() +{ + if (__state_) + __state_->__release_shared(); +} + +template <class _R> +atomic_future<_R&>& +atomic_future<_R&>::operator=(const atomic_future& __rhs) +{ + if (this != &__rhs) + { + unique_lock<mutex> __this(__mut_, defer_lock); + unique_lock<mutex> __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 <class _R> +void +atomic_future<_R&>::swap(atomic_future& __rhs) +{ + if (this != &__rhs) + { + unique_lock<mutex> __this(__mut_, defer_lock); + unique_lock<mutex> __that(__rhs.__mut_, defer_lock); + _STD::lock(__this, __that); + _STD::swap(__state_, __rhs.__state_); + } +} + +template <> +class atomic_future<void> +{ + __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<void>&& __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 <class _Rep, class _Period> + future_status + wait_for(const chrono::duration<_Rep, _Period>& __rel_time) const + {return __state_->wait_for(__rel_time);} + template <class _Clock, class _Duration> + future_status + wait_until(const chrono::time_point<_Clock, _Duration>& __abs_time) const + {return __state_->wait_until(__abs_time);} +}; + +template <class _R> +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 123c472c85b..c380fe6ec1e 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 7373ec3ce5d..3bafa8c8cb8 100644 --- a/libcxx/src/condition_variable.cpp +++ b/libcxx/src/condition_variable.cpp @@ -61,4 +61,10 @@ condition_variable::__do_timed_wait(unique_lock<mutex>& lk, __throw_system_error(ec, "condition_variable timed_wait failed"); } +void +notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> 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 924a6846869..ca3080382ee 100644 --- a/libcxx/src/future.cpp +++ b/libcxx/src/future.cpp @@ -257,4 +257,39 @@ shared_future<void>::operator=(const shared_future& __rhs) return *this; } +atomic_future<void>::~atomic_future() +{ + if (__state_) + __state_->__release_shared(); +} + +atomic_future<void>& +atomic_future<void>::operator=(const atomic_future& __rhs) +{ + if (this != &__rhs) + { + unique_lock<mutex> __this(__mut_, defer_lock); + unique_lock<mutex> __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<void>::swap(atomic_future& __rhs) +{ + if (this != &__rhs) + { + unique_lock<mutex> __this(__mut_, defer_lock); + unique_lock<mutex> __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 f8407067270..3d388e9f030 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<pair<condition_variable*, mutex*> > _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<condition_variable*, mutex*>(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 00000000000..bd17f88d0d3 --- /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. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class atomic_future<R> + +// atomic_future& operator=(const atomic_future& rhs); + +#include <future> +#include <cassert> + +int main() +{ +#ifdef _LIBCPP_MOVE + { + typedef int T; + std::promise<T> p; + std::atomic_future<T> f0 = p.get_future(); + std::atomic_future<T> f; + f = f0; + assert(f0.valid()); + assert(f.valid()); + } + { + typedef int T; + std::atomic_future<T> f0; + std::atomic_future<T> f; + f = f0; + assert(!f0.valid()); + assert(!f.valid()); + } + { + typedef int& T; + std::promise<T> p; + std::atomic_future<T> f0 = p.get_future(); + std::atomic_future<T> f; + f = f0; + assert(f0.valid()); + assert(f.valid()); + } + { + typedef int& T; + std::atomic_future<T> f0; + std::atomic_future<T> f; + f = f0; + assert(!f0.valid()); + assert(!f.valid()); + } + { + typedef void T; + std::promise<T> p; + std::atomic_future<T> f0 = p.get_future(); + std::atomic_future<T> f; + f = f0; + assert(f0.valid()); + assert(f.valid()); + } + { + typedef void T; + std::atomic_future<T> f0; + std::atomic_future<T> 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 00000000000..a4338129819 --- /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. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class atomic_future<R> + +// atomic_future(const atomic_future& rhs); + +#include <future> +#include <cassert> + +int main() +{ + { + typedef int T; + std::promise<T> p; + std::atomic_future<T> f0 = p.get_future(); + std::atomic_future<T> f = f0; + assert(f0.valid()); + assert(f.valid()); + } + { + typedef int T; + std::atomic_future<T> f0; + std::atomic_future<T> f = f0; + assert(!f0.valid()); + assert(!f.valid()); + } + { + typedef int& T; + std::promise<T> p; + std::atomic_future<T> f0 = p.get_future(); + std::atomic_future<T> f = f0; + assert(f0.valid()); + assert(f.valid()); + } + { + typedef int& T; + std::atomic_future<T> f0; + std::atomic_future<T> f = std::move(f0); + assert(!f0.valid()); + assert(!f.valid()); + } + { + typedef void T; + std::promise<T> p; + std::atomic_future<T> f0 = p.get_future(); + std::atomic_future<T> f = f0; + assert(f0.valid()); + assert(f.valid()); + } + { + typedef void T; + std::atomic_future<T> f0; + std::atomic_future<T> 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 00000000000..db0e4237ef2 --- /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. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class atomic_future<R> + +// atomic_future(future<R>&& rhs); + +#include <future> +#include <cassert> + +int main() +{ + { + typedef int T; + std::promise<T> p; + std::future<T> f0 = p.get_future(); + std::atomic_future<T> f = std::move(f0); + assert(!f0.valid()); + assert(f.valid()); + } + { + typedef int T; + std::future<T> f0; + std::atomic_future<T> f = std::move(f0); + assert(!f0.valid()); + assert(!f.valid()); + } + { + typedef int& T; + std::promise<T> p; + std::future<T> f0 = p.get_future(); + std::atomic_future<T> f = std::move(f0); + assert(!f0.valid()); + assert(f.valid()); + } + { + typedef int& T; + std::future<T> f0; + std::atomic_future<T> f = std::move(f0); + assert(!f0.valid()); + assert(!f.valid()); + } + { + typedef void T; + std::promise<T> p; + std::future<T> f0 = p.get_future(); + std::atomic_future<T> f = std::move(f0); + assert(!f0.valid()); + assert(f.valid()); + } + { + typedef void T; + std::future<T> f0; + std::atomic_future<T> 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 00000000000..98d55044ae6 --- /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. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class atomic_future<R> + +// atomic_future(); + +#include <future> +#include <cassert> + +int main() +{ + { + std::atomic_future<int> f; + assert(!f.valid()); + } + { + std::atomic_future<int&> f; + assert(!f.valid()); + } + { + std::atomic_future<void> 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 00000000000..a71b5230937 --- /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. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class atomic_future<R> + +// ~atomic_future(); + +#include <future> +#include <cassert> + +#include "../test_allocator.h" + +int main() +{ + assert(test_alloc_base::count == 0); + { + typedef int T; + std::atomic_future<T> f; + { + std::promise<T> p(std::allocator_arg, test_allocator<T>()); + 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<T> f; + { + std::promise<T> p(std::allocator_arg, test_allocator<int>()); + 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<T> f; + { + std::promise<T> p(std::allocator_arg, test_allocator<T>()); + 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 00000000000..db0ad955f7f --- /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. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class atomic_future<R> + +// const R& atomic_future::get(); +// R& atomic_future<R&>::get(); +// void atomic_future<void>::get(); + +#include <future> +#include <cassert> + +void func1(std::promise<int>& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + p.set_value(3); +} + +void func2(std::promise<int>& 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<int&>& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + j = 5; + p.set_value(j); +} + +void func4(std::promise<int&>& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + p.set_exception(std::make_exception_ptr(3.5)); +} + +void func5(std::promise<void>& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + p.set_value(); +} + +void func6(std::promise<void>& 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<T> p; + std::atomic_future<T> f = p.get_future(); + std::thread(func1, std::move(p)).detach(); + assert(f.valid()); + assert(f.get() == 3); + assert(f.valid()); + } + { + std::promise<T> p; + std::atomic_future<T> 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<T> p; + std::atomic_future<T> f = p.get_future(); + std::thread(func3, std::move(p)).detach(); + assert(f.valid()); + assert(f.get() == 5); + assert(f.valid()); + } + { + std::promise<T> p; + std::atomic_future<T> 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<T> p; + std::atomic_future<T> f = p.get_future(); + std::thread(func5, std::move(p)).detach(); + assert(f.valid()); + f.get(); + assert(f.valid()); + } + { + std::promise<T> p; + std::atomic_future<T> 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 00000000000..b8810d26900 --- /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. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class atomic_future<R> + +// void wait() const; + +#include <future> +#include <cassert> + +void func1(std::promise<int>& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + p.set_value(3); +} + +int j = 0; + +void func3(std::promise<int&>& p) +{ + std::this_thread::sleep_for(std::chrono::milliseconds(500)); + j = 5; + p.set_value(j); +} + +void func5(std::promise<void>& 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<double, std::milli> ms; + { + typedef int T; + std::promise<T> p; + std::atomic_future<T> 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<T> p; + std::atomic_future<T> 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<T> p; + std::atomic_future<T> 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 00000000000..0a544ef9cc8 --- /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. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class atomic_future<R> + +// template <class Rep, class Period> +// future_status +// wait_for(const chrono::duration<Rep, Period>& rel_time) const; + +#include <future> +#include <cassert> + +typedef std::chrono::milliseconds ms; + +void func1(std::promise<int>& p) +{ + std::this_thread::sleep_for(ms(500)); + p.set_value(3); +} + +int j = 0; + +void func3(std::promise<int&>& p) +{ + std::this_thread::sleep_for(ms(500)); + j = 5; + p.set_value(j); +} + +void func5(std::promise<void>& 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<T> p; + std::atomic_future<T> 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<T> p; + std::atomic_future<T> 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<T> p; + std::atomic_future<T> 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 00000000000..e1270411fee --- /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. +// +//===----------------------------------------------------------------------===// + +// <future> + +// class atomic_future<R> + +// template <class Clock, class Duration> +// future_status +// wait_until(const chrono::time_point<Clock, Duration>& abs_time) const; + +#include <future> +#include <cassert> + +typedef std::chrono::milliseconds ms; + +void func1(std::promise<int>& p) +{ + std::this_thread::sleep_for(ms(500)); + p.set_value(3); +} + +int j = 0; + +void func3(std::promise<int&>& p) +{ + std::this_thread::sleep_for(ms(500)); + j = 5; + p.set_value(j); +} + +void func5(std::promise<void>& 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<T> p; + std::atomic_future<T> 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<T> p; + std::atomic_future<T> 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<T> p; + std::atomic_future<T> 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 6cc9067effc..6584a7712c2 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<mutex> lk); #include <condition_variable> +#include <mutex> +#include <thread> +#include <chrono> #include <cassert> +std::condition_variable cv; +std::mutex mut; + +typedef std::chrono::milliseconds ms; +typedef std::chrono::high_resolution_clock Clock; + +void func() +{ + std::unique_lock<std::mutex> 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<std::mutex> 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 a0e347db3e8..ac071d0ae88 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; |