diff options
-rw-r--r-- | libcxx/include/thread | 23 | ||||
-rw-r--r-- | libcxx/src/condition_variable.cpp | 6 | ||||
-rw-r--r-- | libcxx/test/std/thread/thread.condition/PR30202_notify_from_pthread_created_thread.pass.cpp | 75 |
3 files changed, 88 insertions, 16 deletions
diff --git a/libcxx/include/thread b/libcxx/include/thread index 022021c5add..21cc7610fd0 100644 --- a/libcxx/include/thread +++ b/libcxx/include/thread @@ -99,6 +99,7 @@ void sleep_for(const chrono::duration<Rep, Period>& rel_time); #include <tuple> #endif #include <__threading_support> +#include <__debug> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -159,8 +160,7 @@ public: pointer operator*() const {return *get();} _LIBCPP_INLINE_VISIBILITY pointer operator->() const {return get();} - pointer release(); - void reset(pointer __p = nullptr); + void set_pointer(pointer __p); }; template <class _Tp> @@ -191,21 +191,12 @@ __thread_specific_ptr<_Tp>::~__thread_specific_ptr() } template <class _Tp> -typename __thread_specific_ptr<_Tp>::pointer -__thread_specific_ptr<_Tp>::release() -{ - pointer __p = get(); - __libcpp_tl_set(__key_, nullptr); - return __p; -} - -template <class _Tp> void -__thread_specific_ptr<_Tp>::reset(pointer __p) +__thread_specific_ptr<_Tp>::set_pointer(pointer __p) { - pointer __p_old = get(); + _LIBCPP_ASSERT(get() == nullptr, + "Attempting to overwrite thread local data"); __libcpp_tl_set(__key_, __p); - delete __p_old; } class _LIBCPP_TYPE_VIS thread; @@ -351,7 +342,7 @@ void* __thread_proxy(void* __vp) { // _Fp = std::tuple< unique_ptr<__thread_struct>, Functor, Args...> std::unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp)); - __thread_local_data().reset(_VSTD::get<0>(*__p).release()); + __thread_local_data().set_pointer(_VSTD::get<0>(*__p).release()); typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 2>::type _Index; __thread_execute(*__p, _Index()); return nullptr; @@ -392,7 +383,7 @@ template <class _Fp> void* __thread_proxy_cxx03(void* __vp) { std::unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp)); - __thread_local_data().reset(__p->__tsp_.release()); + __thread_local_data().set_pointer(__p->__tsp_.release()); (__p->__fn_)(); return nullptr; } diff --git a/libcxx/src/condition_variable.cpp b/libcxx/src/condition_variable.cpp index bfb4bf3925f..25e66038eec 100644 --- a/libcxx/src/condition_variable.cpp +++ b/libcxx/src/condition_variable.cpp @@ -79,6 +79,12 @@ condition_variable::__do_timed_wait(unique_lock<mutex>& lk, void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk) { + auto& tl_ptr = __thread_local_data(); + // If this thread was not created using std::thread then it will not have + // previously allocated. + if (tl_ptr.get() == nullptr) { + tl_ptr.set_pointer(new __thread_struct); + } __thread_local_data()->notify_all_at_thread_exit(&cond, lk.release()); } diff --git a/libcxx/test/std/thread/thread.condition/PR30202_notify_from_pthread_created_thread.pass.cpp b/libcxx/test/std/thread/thread.condition/PR30202_notify_from_pthread_created_thread.pass.cpp new file mode 100644 index 00000000000..d60e4291886 --- /dev/null +++ b/libcxx/test/std/thread/thread.condition/PR30202_notify_from_pthread_created_thread.pass.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// UNSUPPORTED: libcpp-has-no-threads + +// notify_all_at_thread_exit(...) requires move semantics to transfer the +// unique_lock. +// UNSUPPORTED: c++98, c++03 + +// <condition_variable> + +// void +// notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk); + +// Test that this function works with threads that were not created by +// std::thread. See http://llvm.org/PR30202. + + +#include <condition_variable> +#include <mutex> +#include <thread> +#include <chrono> +#include <cassert> +#include <pthread.h> + +std::condition_variable cv; +std::mutex mut; +bool exited = false; + +typedef std::chrono::milliseconds ms; +typedef std::chrono::high_resolution_clock Clock; + +void* func(void*) +{ + std::unique_lock<std::mutex> lk(mut); + std::notify_all_at_thread_exit(cv, std::move(lk)); + std::this_thread::sleep_for(ms(300)); + exited = true; + return nullptr; +} + +int main() +{ + { + std::unique_lock<std::mutex> lk(mut); + pthread_t id; + int res = pthread_create(&id, 0, &func, nullptr); + assert(res == 0); + Clock::time_point t0 = Clock::now(); + assert(exited == false); + cv.wait(lk); + Clock::time_point t1 = Clock::now(); + assert(exited); + assert(t1-t0 > ms(250)); + pthread_join(id, 0); + } + exited = false; + { + std::unique_lock<std::mutex> lk(mut); + std::thread t(&func, nullptr); + Clock::time_point t0 = Clock::now(); + assert(exited == false); + cv.wait(lk); + Clock::time_point t1 = Clock::now(); + assert(exited); + assert(t1-t0 > ms(250)); + t.join(); + } +} |