aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHoward Hinnant <hhinnant@apple.com>2010-09-03 21:46:37 +0000
committerHoward Hinnant <hhinnant@apple.com>2010-09-03 21:46:37 +0000
commitb77c0c03bb5f48c7ff98aa0d8dd5c648e8a1a651 (patch)
tree51b1ae1903851f02fc0104ff07339673c7e83f73
parent005155e236afd14f9cc1342a213f050287e9bb26 (diff)
downloadllvm-b77c0c03bb5f48c7ff98aa0d8dd5c648e8a1a651.zip
llvm-b77c0c03bb5f48c7ff98aa0d8dd5c648e8a1a651.tar.gz
llvm-b77c0c03bb5f48c7ff98aa0d8dd5c648e8a1a651.tar.bz2
[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
-rw-r--r--libcxx/include/condition_variable2
-rw-r--r--libcxx/include/future198
-rw-r--r--libcxx/include/thread1
-rw-r--r--libcxx/src/condition_variable.cpp6
-rw-r--r--libcxx/src/future.cpp35
-rw-r--r--libcxx/src/thread.cpp22
-rw-r--r--libcxx/test/thread/futures/futures.atomic_future/copy_assign.pass.cpp74
-rw-r--r--libcxx/test/thread/futures/futures.atomic_future/copy_ctor.pass.cpp66
-rw-r--r--libcxx/test/thread/futures/futures.atomic_future/ctor_future.pass.cpp66
-rw-r--r--libcxx/test/thread/futures/futures.atomic_future/default.pass.cpp33
-rw-r--r--libcxx/test/thread/futures/futures.atomic_future/dtor.pass.cpp66
-rw-r--r--libcxx/test/thread/futures/futures.atomic_future/get.pass.cpp143
-rw-r--r--libcxx/test/thread/futures/futures.atomic_future/wait.pass.cpp86
-rw-r--r--libcxx/test/thread/futures/futures.atomic_future/wait_for.pass.cpp95
-rw-r--r--libcxx/test/thread/futures/futures.atomic_future/wait_until.pass.cpp95
-rw-r--r--libcxx/test/thread/thread.condition/notify_all_at_thread_exit.pass.cpp23
-rw-r--r--libcxx/test/thread/thread.condition/thread.condition.condvarany/wait_for_pred.pass.cpp2
17 files changed, 1010 insertions, 3 deletions
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<mutex> 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 <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 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<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 924a684..ca30803 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 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<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 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.
+//
+//===----------------------------------------------------------------------===//
+
+// <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 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.
+//
+//===----------------------------------------------------------------------===//
+
+// <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 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.
+//
+//===----------------------------------------------------------------------===//
+
+// <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 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.
+//
+//===----------------------------------------------------------------------===//
+
+// <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 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.
+//
+//===----------------------------------------------------------------------===//
+
+// <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 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.
+//
+//===----------------------------------------------------------------------===//
+
+// <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 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.
+//
+//===----------------------------------------------------------------------===//
+
+// <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 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.
+//
+//===----------------------------------------------------------------------===//
+
+// <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 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.
+//
+//===----------------------------------------------------------------------===//
+
+// <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 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<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 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;