diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index 2b4c432d200..c6fd8449aed 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -783,21 +783,22 @@ UNSAFE_ENTRY(void, Unsafe_Park(JNIEnv *env, jobject unsafe, jboolean isAbsolute, UNSAFE_ENTRY(void, Unsafe_Unpark(JNIEnv *env, jobject unsafe, jobject jthread)) { if (jthread != nullptr) { - ThreadsListHandle tlh; - JavaThread* thr = nullptr; - oop java_thread = nullptr; - (void) tlh.cv_internal_thread_to_JavaThread(jthread, &thr, &java_thread); - if (java_thread != nullptr) { - // This is a valid oop. - if (thr != nullptr) { - // The JavaThread is alive. - Parker* p = thr->parker(); - HOTSPOT_THREAD_UNPARK((uintptr_t) p); - p->unpark(); - } + oop thread_oop = JNIHandles::resolve_non_null(jthread); + // Get the JavaThread* stored in the java.lang.Thread object _before_ + // the embedded ThreadsListHandle is constructed so we know if the + // early life stage of the JavaThread* is protected. We use acquire + // here to ensure that if we see a non-nullptr value, then we also + // see the main ThreadsList updates from the JavaThread* being added. + FastThreadsListHandle ftlh(thread_oop, java_lang_Thread::thread_acquire(thread_oop)); + JavaThread* thr = ftlh.protected_java_thread(); + if (thr != nullptr) { + // The still live JavaThread* is protected by the FastThreadsListHandle + // so it is safe to access. + Parker* p = thr->parker(); + HOTSPOT_THREAD_UNPARK((uintptr_t) p); + p->unpark(); } - } // ThreadsListHandle is destroyed here. - + } // FastThreadsListHandle is destroyed here. } UNSAFE_END UNSAFE_ENTRY(jint, Unsafe_GetLoadAverage0(JNIEnv *env, jobject unsafe, jdoubleArray loadavg, jint nelem)) { diff --git a/src/hotspot/share/runtime/threadSMR.cpp b/src/hotspot/share/runtime/threadSMR.cpp index 20e0ad8b857..cffec545a66 100644 --- a/src/hotspot/share/runtime/threadSMR.cpp +++ b/src/hotspot/share/runtime/threadSMR.cpp @@ -839,6 +839,20 @@ bool ThreadsListHandle::cv_internal_thread_to_JavaThread(jobject jthread, return true; } +FastThreadsListHandle::FastThreadsListHandle(oop thread_oop, JavaThread* java_thread) : _protected_java_thread(nullptr) { + assert(thread_oop != nullptr, "must be"); + if (java_thread != nullptr) { + // We captured a non-nullptr JavaThread* before the _tlh was created + // so that covers the early life stage of the target JavaThread. + _protected_java_thread = java_lang_Thread::thread(thread_oop); + assert(_protected_java_thread == nullptr || _tlh.includes(_protected_java_thread), "must be"); + // If we captured a non-nullptr JavaThread* after the _tlh was created + // then that covers the end life stage of the target JavaThread and we + // we know that _tlh protects the JavaThread*. The underlying atomic + // load is sufficient (no acquire necessary here). + } +} + void ThreadsSMRSupport::add_thread(JavaThread *thread){ ThreadsList *new_list = ThreadsList::add_thread(get_java_thread_list(), thread); if (EnableThreadSMRStatistics) { diff --git a/src/hotspot/share/runtime/threadSMR.hpp b/src/hotspot/share/runtime/threadSMR.hpp index 0cb6da8da9c..e6b1a52e1a9 100644 --- a/src/hotspot/share/runtime/threadSMR.hpp +++ b/src/hotspot/share/runtime/threadSMR.hpp @@ -333,6 +333,29 @@ public: } }; +// This stack allocated FastThreadsListHandle implements the special case +// where we want to quickly determine if a JavaThread* is protected by the +// embedded ThreadsListHandle. +// +class FastThreadsListHandle : public StackObj { + JavaThread* _protected_java_thread; + ThreadsListHandle _tlh; + +public: + // The 'java_thread' parameter to the constructor must be provided + // by a java_lang_Thread::thread_acquire(thread_oop) call which gets + // us the JavaThread* stored in the java.lang.Thread object _before_ + // the embedded ThreadsListHandle is constructed. We use acquire there + // to ensure that if we see a non-nullptr value, then we also see the + // main ThreadsList updates from the JavaThread* being added. + // + FastThreadsListHandle(oop thread_oop, JavaThread* java_thread); + + JavaThread* protected_java_thread() { + return _protected_java_thread; + } +}; + // This stack allocated JavaThreadIterator is used to walk the // specified ThreadsList using the following style: //