summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libcxx/include/thread23
-rw-r--r--libcxx/src/condition_variable.cpp6
-rw-r--r--libcxx/test/std/thread/thread.condition/PR30202_notify_from_pthread_created_thread.pass.cpp75
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();
+ }
+}
OpenPOWER on IntegriCloud