diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index d38c32b234e..6649f46fe04 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1570,10 +1570,18 @@ JavaThread* java_lang_Thread::thread(oop java_thread) { return reinterpret_cast(java_thread->address_field(_eetop_offset)); } +JavaThread* java_lang_Thread::thread_acquire(oop java_thread) { + return reinterpret_cast(java_thread->address_field_acquire(_eetop_offset)); +} + void java_lang_Thread::set_thread(oop java_thread, JavaThread* thread) { java_thread->address_field_put(_eetop_offset, (address)thread); } +void java_lang_Thread::release_set_thread(oop java_thread, JavaThread* thread) { + java_thread->release_address_field_put(_eetop_offset, (address)thread); +} + JvmtiThreadState* java_lang_Thread::jvmti_thread_state(oop java_thread) { return (JvmtiThreadState*)java_thread->address_field(_jvmti_thread_state_offset); } diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index 484d9ebfee1..84ce35ba767 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -366,8 +366,10 @@ class java_lang_Thread : AllStatic { // Returns the JavaThread associated with the thread obj static JavaThread* thread(oop java_thread); + static JavaThread* thread_acquire(oop java_thread); // Set JavaThread for instance static void set_thread(oop java_thread, JavaThread* thread); + static void release_set_thread(oop java_thread, JavaThread* thread); // FieldHolder static oop holder(oop java_thread); // Interrupted status diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 2e3ad138768..b469c1a6790 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -743,8 +743,7 @@ static void ensure_join(JavaThread* thread) { // Clear the native thread instance - this makes isAlive return false and allows the join() // to complete once we've done the notify_all below. Needs a release() to obey Java Memory Model // requirements. - OrderAccess::release(); - java_lang_Thread::set_thread(threadObj(), nullptr); + java_lang_Thread::release_set_thread(threadObj(), nullptr); lock.notify_all(thread); // Ignore pending exception, since we are exiting anyway thread->clear_pending_exception(); @@ -1668,7 +1667,6 @@ void JavaThread::prepare(jobject jni_thread, ThreadPriority prio) { assert(InstanceKlass::cast(thread_oop->klass())->is_linked(), "must be initialized"); set_threadOopHandles(thread_oop()); - java_lang_Thread::set_thread(thread_oop(), this); if (prio == NoPriority) { prio = java_lang_Thread::priority(thread_oop()); @@ -1684,6 +1682,11 @@ void JavaThread::prepare(jobject jni_thread, ThreadPriority prio) { // added to the Threads list for if a GC happens, then the java_thread oop // will not be visited by GC. Threads::add(this); + // Publish the JavaThread* in java.lang.Thread after the JavaThread* is + // on a ThreadsList. We don't want to wait for the release when the + // Theads_lock is dropped somewhere in the caller since the JavaThread* + // is already visible to JVM/TI via the ThreadsList. + java_lang_Thread::release_set_thread(thread_oop(), this); } oop JavaThread::current_park_blocker() { @@ -2121,9 +2124,6 @@ void JavaThread::start_internal_daemon(JavaThread* current, JavaThread* target, MutexLocker mu(current, Threads_lock); // Initialize the fields of the thread_oop first. - - java_lang_Thread::set_thread(thread_oop(), target); // isAlive == true now - if (prio != NoPriority) { java_lang_Thread::set_priority(thread_oop(), prio); // Note: we don't call os::set_priority here. Possibly we should, @@ -2136,6 +2136,11 @@ void JavaThread::start_internal_daemon(JavaThread* current, JavaThread* target, target->set_threadOopHandles(thread_oop()); Threads::add(target); // target is now visible for safepoint/handshake + // Publish the JavaThread* in java.lang.Thread after the JavaThread* is + // on a ThreadsList. We don't want to wait for the release when the + // Theads_lock is dropped when the 'mu' destructor is run since the + // JavaThread* is already visible to JVM/TI via the ThreadsList. + java_lang_Thread::release_set_thread(thread_oop(), target); // isAlive == true now Thread::start(target); } diff --git a/src/hotspot/share/runtime/threadSMR.cpp b/src/hotspot/share/runtime/threadSMR.cpp index b543039653b..20e0ad8b857 100644 --- a/src/hotspot/share/runtime/threadSMR.cpp +++ b/src/hotspot/share/runtime/threadSMR.cpp @@ -815,10 +815,11 @@ bool ThreadsListHandle::cv_internal_thread_to_JavaThread(jobject jthread, *thread_oop_p = thread_oop; } - JavaThread *java_thread = java_lang_Thread::thread(thread_oop); + JavaThread *java_thread = java_lang_Thread::thread_acquire(thread_oop); if (java_thread == nullptr) { - // The java.lang.Thread does not contain a JavaThread * so it has - // not yet run or it has died. + // The java.lang.Thread does not contain a JavaThread* so it has not + // run enough to be put on a ThreadsList or it has exited enough to + // make it past ensure_join() where the JavaThread* is cleared. return false; } // Looks like a live JavaThread at this point.