Index: include/thread =================================================================== --- include/thread +++ include/thread @@ -99,6 +99,7 @@ #include #endif #include <__threading_support> +#include <__debug> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -159,8 +160,7 @@ 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 @@ -191,21 +191,12 @@ } template -typename __thread_specific_ptr<_Tp>::pointer -__thread_specific_ptr<_Tp>::release() -{ - pointer __p = get(); - __libcpp_tl_set(__key_, nullptr); - return __p; -} - -template 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 @@ { // _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::value, 2>::type _Index; __thread_execute(*__p, _Index()); return nullptr; @@ -392,7 +383,7 @@ 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; } Index: src/condition_variable.cpp =================================================================== --- src/condition_variable.cpp +++ src/condition_variable.cpp @@ -79,6 +79,12 @@ void notify_all_at_thread_exit(condition_variable& cond, unique_lock 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()); } Index: test/std/thread/thread.condition/PR30202_notify_from_pthread_created_thread.pass.cpp =================================================================== --- /dev/null +++ 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 + +// + +// void +// notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); + +// Test that this function works with threads that were not created by +// std::thread. See http://llvm.org/PR30202. + + +#include +#include +#include +#include +#include +#include + +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 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 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 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(); + } +}