From 9a23f721c7bcbfdb2fcf5b2bd145d6967e000dc4 Mon Sep 17 00:00:00 2001 From: Patricio Chilano Mateo Date: Tue, 6 May 2025 22:08:51 +0000 Subject: [PATCH] 8316682: serviceability/jvmti/vthread/SelfSuspendDisablerTest timed out Reviewed-by: lmesnik, pchilanomate --- src/hotspot/share/prims/jvmtiEnv.cpp | 8 + src/hotspot/share/prims/jvmtiEnvBase.cpp | 137 ++++++++---------- src/hotspot/share/prims/jvmtiImpl.cpp | 2 +- src/hotspot/share/prims/jvmtiThreadState.cpp | 40 +++-- src/hotspot/share/prims/jvmtiThreadState.hpp | 4 +- src/hotspot/share/runtime/handshake.cpp | 40 +++-- src/hotspot/share/runtime/handshake.hpp | 8 +- src/hotspot/share/runtime/javaThread.cpp | 8 +- src/hotspot/share/runtime/javaThread.hpp | 10 +- .../share/runtime/javaThread.inline.hpp | 8 +- src/hotspot/share/runtime/mutexLocker.cpp | 2 + src/hotspot/share/runtime/mutexLocker.hpp | 1 + test/hotspot/jtreg/ProblemList.txt | 1 - 13 files changed, 147 insertions(+), 122 deletions(-) diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index b2af12b08a6..6a1f451bb74 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -988,6 +988,10 @@ JvmtiEnv::SuspendThreadList(jint request_count, const jthread* request_list, jvm self_tobj = Handle(current, thread_oop); continue; // self suspend after all other suspends } + if (java_lang_VirtualThread::is_instance(thread_oop)) { + oop carrier_thread = java_lang_VirtualThread::carrier_thread(thread_oop); + java_thread = carrier_thread == nullptr ? nullptr : java_lang_Thread::thread(carrier_thread); + } results[i] = suspend_thread(thread_oop, java_thread, /* single_suspend */ true); } } @@ -1114,6 +1118,10 @@ JvmtiEnv::ResumeThreadList(jint request_count, const jthread* request_list, jvmt continue; } } + if (java_lang_VirtualThread::is_instance(thread_oop)) { + oop carrier_thread = java_lang_VirtualThread::carrier_thread(thread_oop); + java_thread = carrier_thread == nullptr ? nullptr : java_lang_Thread::thread(carrier_thread); + } results[i] = resume_thread(thread_oop, java_thread, /* single_resume */ true); } // per-thread resume results returned via results parameter diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 9e0929e69cf..3b6602f2420 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -1398,8 +1398,7 @@ JvmtiEnvBase::is_vthread_suspended(oop vt_oop, JavaThread* jt) { bool suspended = false; if (java_lang_VirtualThread::is_instance(vt_oop)) { suspended = JvmtiVTSuspender::is_vthread_suspended(vt_oop); - } - if (vt_oop->is_a(vmClasses::BoundVirtualThread_klass())) { + } else if (vt_oop->is_a(vmClasses::BoundVirtualThread_klass())) { suspended = jt->is_suspended(); } return suspended; @@ -1757,57 +1756,46 @@ JvmtiEnvBase::suspend_thread(oop thread_oop, JavaThread* java_thread, bool singl Handle thread_h(current, thread_oop); bool is_virtual = java_lang_VirtualThread::is_instance(thread_h()); - if (is_virtual) { - if (single_suspend) { - if (JvmtiVTSuspender::is_vthread_suspended(thread_h())) { - return JVMTI_ERROR_THREAD_SUSPENDED; - } - JvmtiVTSuspender::register_vthread_suspend(thread_h()); - // Check if virtual thread is mounted and there is a java_thread. - // A non-null java_thread is always passed in the !single_suspend case. - oop carrier_thread = java_lang_VirtualThread::carrier_thread(thread_h()); - java_thread = carrier_thread == nullptr ? nullptr : java_lang_Thread::thread(carrier_thread); + // Unmounted vthread case. + + if (is_virtual && java_thread == nullptr) { + assert(single_suspend, "sanity check"); + if (JvmtiVTSuspender::is_vthread_suspended(thread_h())) { + return JVMTI_ERROR_THREAD_SUSPENDED; } - // The java_thread can be still blocked in VTMS transition after a previous JVMTI resume call. - // There is no need to suspend the java_thread in this case. After vthread unblocking, - // it will check for ext_suspend request and suspend itself if necessary. - if (java_thread == nullptr || java_thread->is_suspended()) { - // We are done if the virtual thread is unmounted or - // the java_thread is externally suspended. - return JVMTI_ERROR_NONE; - } - // The virtual thread is mounted: suspend the java_thread. + JvmtiVTSuspender::register_vthread_suspend(thread_h()); + return JVMTI_ERROR_NONE; } + + // Platform thread or mounted vthread cases. + + assert(java_thread != nullptr, "sanity check"); + assert(!java_thread->is_in_VTMS_transition(), "sanity check"); + // Don't allow hidden thread suspend request. if (java_thread->is_hidden_from_external_view()) { return JVMTI_ERROR_NONE; } - bool is_thread_carrying = is_thread_carrying_vthread(java_thread, thread_h()); - - // A case of non-virtual thread. - if (!is_virtual) { - // Thread.suspend() is used in some tests. It sets jt->is_suspended() only. - if (java_thread->is_carrier_thread_suspended() || - (!is_thread_carrying && java_thread->is_suspended())) { - return JVMTI_ERROR_THREAD_SUSPENDED; - } - java_thread->set_carrier_thread_suspended(); - } - assert(!java_thread->is_in_VTMS_transition(), "sanity check"); - - assert(!single_suspend || (!is_virtual && java_thread->is_carrier_thread_suspended()) || - (is_virtual && JvmtiVTSuspender::is_vthread_suspended(thread_h())), - "sanity check"); // An attempt to handshake-suspend a thread carrying a virtual thread will result in // suspension of mounted virtual thread. So, we just mark it as suspended // and it will be actually suspended at virtual thread unmount transition. - if (!is_thread_carrying) { + bool is_thread_carrying = is_thread_carrying_vthread(java_thread, thread_h()); + if (is_thread_carrying) { + return java_thread->set_carrier_thread_suspended() ? JVMTI_ERROR_NONE : JVMTI_ERROR_THREAD_SUSPENDED; + } else { + // Platform thread (not carrying vthread) or mounted vthread cases. assert(thread_h() != nullptr, "sanity check"); assert(single_suspend || thread_h()->is_a(vmClasses::BaseVirtualThread_klass()), "SuspendAllVirtualThreads should never suspend non-virtual threads"); - // Case of mounted virtual or attached carrier thread. - if (!java_thread->java_suspend()) { + + // Ideally we would just need to check java_thread->is_suspended(), but we have to + // consider the case of trying to suspend a thread that was previously suspended while + // carrying a vthread but has already unmounted it. + if (java_thread->is_suspended() || (!is_virtual && java_thread->is_carrier_thread_suspended())) { + return JVMTI_ERROR_THREAD_SUSPENDED; + } + if (!java_thread->java_suspend(is_virtual && single_suspend)) { // Thread is already suspended or in process of exiting. if (java_thread->is_exiting()) { // The thread was in the process of exiting. @@ -1815,8 +1803,8 @@ JvmtiEnvBase::suspend_thread(oop thread_oop, JavaThread* java_thread, bool singl } return JVMTI_ERROR_THREAD_SUSPENDED; } + return JVMTI_ERROR_NONE; } - return JVMTI_ERROR_NONE; } // java_thread - protected by ThreadsListHandle @@ -1827,54 +1815,51 @@ JvmtiEnvBase::resume_thread(oop thread_oop, JavaThread* java_thread, bool single Handle thread_h(current, thread_oop); bool is_virtual = java_lang_VirtualThread::is_instance(thread_h()); - if (is_virtual) { - if (single_resume) { - if (!JvmtiVTSuspender::is_vthread_suspended(thread_h())) { - return JVMTI_ERROR_THREAD_NOT_SUSPENDED; - } - JvmtiVTSuspender::register_vthread_resume(thread_h()); - // Check if virtual thread is mounted and there is a java_thread. - // A non-null java_thread is always passed in the !single_resume case. - oop carrier_thread = java_lang_VirtualThread::carrier_thread(thread_h()); - java_thread = carrier_thread == nullptr ? nullptr : java_lang_Thread::thread(carrier_thread); + // Unmounted vthread case. + + if (is_virtual && java_thread == nullptr) { + assert(single_resume, "sanity check"); + if (!JvmtiVTSuspender::is_vthread_suspended(thread_h())) { + return JVMTI_ERROR_THREAD_NOT_SUSPENDED; } - // The java_thread can be still blocked in VTMS transition after a previous JVMTI suspend call. - // There is no need to resume the java_thread in this case. After vthread unblocking, - // it will check for is_vthread_suspended request and remain resumed if necessary. - if (java_thread == nullptr || !java_thread->is_suspended()) { - // We are done if the virtual thread is unmounted or - // the java_thread is not externally suspended. - return JVMTI_ERROR_NONE; - } - // The virtual thread is mounted and java_thread is supended: resume the java_thread. + JvmtiVTSuspender::register_vthread_resume(thread_h()); + return JVMTI_ERROR_NONE; } + + // Platform thread or mounted vthread cases. + + assert(java_thread != nullptr, "sanity check"); + assert(!java_thread->is_in_VTMS_transition(), "sanity check"); + // Don't allow hidden thread resume request. if (java_thread->is_hidden_from_external_view()) { return JVMTI_ERROR_NONE; } + bool is_thread_carrying = is_thread_carrying_vthread(java_thread, thread_h()); + if (is_thread_carrying) { + return java_thread->clear_carrier_thread_suspended() ? JVMTI_ERROR_NONE : JVMTI_ERROR_THREAD_NOT_SUSPENDED; + } else { + // Platform thread (not carrying vthread) or mounted vthread cases. - // A case of a non-virtual thread. - if (!is_virtual) { - if (!java_thread->is_carrier_thread_suspended() && - (is_thread_carrying || !java_thread->is_suspended())) { - return JVMTI_ERROR_THREAD_NOT_SUSPENDED; - } - java_thread->clear_carrier_thread_suspended(); - } - assert(!java_thread->is_in_VTMS_transition(), "sanity check"); - - if (!is_thread_carrying) { assert(thread_h() != nullptr, "sanity check"); assert(single_resume || thread_h()->is_a(vmClasses::BaseVirtualThread_klass()), "ResumeAllVirtualThreads should never resume non-virtual threads"); - if (java_thread->is_suspended()) { - if (!java_thread->java_resume()) { - return JVMTI_ERROR_THREAD_NOT_SUSPENDED; - } + + // Ideally we would not have to check this but we have to consider the case + // of trying to resume a thread that was previously suspended while carrying + // a vthread but has already unmounted it. + if (!is_virtual && java_thread->is_carrier_thread_suspended()) { + bool res = java_thread->clear_carrier_thread_suspended(); + assert(res, "resume operations running concurrently?"); + return JVMTI_ERROR_NONE; } + + if (!java_thread->java_resume(is_virtual && single_resume)) { + return JVMTI_ERROR_THREAD_NOT_SUSPENDED; + } + return JVMTI_ERROR_NONE; } - return JVMTI_ERROR_NONE; } ResourceTracker::ResourceTracker(JvmtiEnv* env) { diff --git a/src/hotspot/share/prims/jvmtiImpl.cpp b/src/hotspot/share/prims/jvmtiImpl.cpp index 9caea2de520..0059636099e 100644 --- a/src/hotspot/share/prims/jvmtiImpl.cpp +++ b/src/hotspot/share/prims/jvmtiImpl.cpp @@ -658,7 +658,7 @@ vframe *VM_GetOrSetLocal::get_vframe() { javaVFrame *VM_GetOrSetLocal::get_java_vframe() { vframe* vf = get_vframe(); - if (!(_self || _thread->is_carrier_thread_suspended())) { + if (!_self && !_thread->is_suspended() && !_thread->is_carrier_thread_suspended()) { _result = JVMTI_ERROR_THREAD_NOT_SUSPENDED; return nullptr; } diff --git a/src/hotspot/share/prims/jvmtiThreadState.cpp b/src/hotspot/share/prims/jvmtiThreadState.cpp index b4119825bd3..40d7800de79 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.cpp +++ b/src/hotspot/share/prims/jvmtiThreadState.cpp @@ -254,7 +254,10 @@ JvmtiVTMSTransitionDisabler::print_info() { // disable VTMS transitions for one virtual thread // disable VTMS transitions for all threads if thread is nullptr or a platform thread JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(jthread thread) - : _is_SR(false), _thread(thread) + : _is_SR(false), + _is_virtual(false), + _is_self(false), + _thread(thread) { if (!Continuations::enabled()) { return; // JvmtiVTMSTransitionDisabler is no-op without virtual threads @@ -262,21 +265,26 @@ JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(jthread thread) if (Thread::current_or_null() == nullptr) { return; // Detached thread, can be a call from Agent_OnLoad. } + JavaThread* current = JavaThread::current(); + oop thread_oop = JNIHandles::resolve_external_guard(thread); + _is_virtual = java_lang_VirtualThread::is_instance(thread_oop); + + if (thread == nullptr || + (!_is_virtual && thread_oop == current->threadObj()) || + (_is_virtual && thread_oop == current->vthread())) { + _is_self = true; + return; // no need for current thread to disable and enable transitions for itself + } if (!sync_protocol_enabled_permanently()) { JvmtiVTMSTransitionDisabler::inc_sync_protocol_enabled_count(); } - oop thread_oop = JNIHandles::resolve_external_guard(thread); // Target can be virtual or platform thread. // If target is a platform thread then we have to disable VTMS transitions for all threads. // It is by several reasons: // - carrier threads can mount virtual threads which may cause incorrect behavior // - there is no mechanism to disable transitions for a specific carrier thread yet - if (!java_lang_VirtualThread::is_instance(thread_oop)) { - _thread = nullptr; // target is a platform thread, switch to disabling VTMS transitions for all threads - } - - if (_thread != nullptr) { + if (_is_virtual) { VTMS_transition_disable_for_one(); // disable VTMS transitions for one virtual thread } else { VTMS_transition_disable_for_all(); // disable VTMS transitions for all virtual threads @@ -285,7 +293,10 @@ JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(jthread thread) // disable VTMS transitions for all virtual threads JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(bool is_SR) - : _is_SR(is_SR), _thread(nullptr) + : _is_SR(is_SR), + _is_virtual(false), + _is_self(false), + _thread(nullptr) { if (!Continuations::enabled()) { return; // JvmtiVTMSTransitionDisabler is no-op without virtual threads @@ -309,7 +320,10 @@ JvmtiVTMSTransitionDisabler::~JvmtiVTMSTransitionDisabler() { if (Thread::current_or_null() == nullptr) { return; // Detached thread, can be a call from Agent_OnLoad. } - if (_thread != nullptr) { + if (_is_self) { + return; // no need for current thread to disable and enable transitions for itself + } + if (_is_virtual) { VTMS_transition_enable_for_one(); // enable VTMS transitions for one virtual thread } else { VTMS_transition_enable_for_all(); // enable VTMS transitions for all virtual threads @@ -684,7 +698,7 @@ JvmtiVTSuspender::_not_suspended_list = new VirtualThreadList(); void JvmtiVTSuspender::register_all_vthreads_suspend() { - MonitorLocker ml(JvmtiVTMSTransition_lock); + MutexLocker ml(JvmtiVThreadSuspend_lock, Mutex::_no_safepoint_check_flag); _SR_mode = SR_all; _suspended_list->invalidate(); @@ -693,7 +707,7 @@ JvmtiVTSuspender::register_all_vthreads_suspend() { void JvmtiVTSuspender::register_all_vthreads_resume() { - MonitorLocker ml(JvmtiVTMSTransition_lock); + MutexLocker ml(JvmtiVThreadSuspend_lock, Mutex::_no_safepoint_check_flag); _SR_mode = SR_none; _suspended_list->invalidate(); @@ -703,7 +717,7 @@ JvmtiVTSuspender::register_all_vthreads_resume() { void JvmtiVTSuspender::register_vthread_suspend(oop vt) { int64_t id = java_lang_Thread::thread_id(vt); - MonitorLocker ml(JvmtiVTMSTransition_lock); + MutexLocker ml(JvmtiVThreadSuspend_lock, Mutex::_no_safepoint_check_flag); if (_SR_mode == SR_all) { assert(_not_suspended_list->contains(id), @@ -720,7 +734,7 @@ JvmtiVTSuspender::register_vthread_suspend(oop vt) { void JvmtiVTSuspender::register_vthread_resume(oop vt) { int64_t id = java_lang_Thread::thread_id(vt); - MonitorLocker ml(JvmtiVTMSTransition_lock); + MutexLocker ml(JvmtiVThreadSuspend_lock, Mutex::_no_safepoint_check_flag); if (_SR_mode == SR_all) { assert(!_not_suspended_list->contains(id), diff --git a/src/hotspot/share/prims/jvmtiThreadState.hpp b/src/hotspot/share/prims/jvmtiThreadState.hpp index c9362d5b8cb..53144607a3c 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.hpp +++ b/src/hotspot/share/prims/jvmtiThreadState.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -86,6 +86,8 @@ class JvmtiVTMSTransitionDisabler { static volatile bool _sync_protocol_enabled_permanently; // seen a suspender: JvmtiVTMSTransitionDisabler protocol is enabled permanently bool _is_SR; // is suspender or resumer + bool _is_virtual; // target thread is virtual + bool _is_self; // JvmtiVTMSTransitionDisabler is a no-op for current platform, carrier or virtual thread jthread _thread; // virtual thread to disable transitions for, no-op if it is a platform thread DEBUG_ONLY(static void print_info();) diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp index 26d3be7c36a..6bed5e9d546 100644 --- a/src/hotspot/share/runtime/handshake.cpp +++ b/src/hotspot/share/runtime/handshake.cpp @@ -28,6 +28,7 @@ #include "logging/log.hpp" #include "logging/logStream.hpp" #include "memory/resourceArea.hpp" +#include "prims/jvmtiThreadState.hpp" #include "runtime/atomic.hpp" #include "runtime/globals.hpp" #include "runtime/handshake.hpp" @@ -729,7 +730,7 @@ class ThreadSelfSuspensionHandshake : public AsyncHandshakeClosure { virtual bool is_suspend() { return true; } }; -bool HandshakeState::suspend_with_handshake() { +bool HandshakeState::suspend_with_handshake(bool register_vthread_SR) { assert(_handshakee->threadObj() != nullptr, "cannot suspend with a null threadObj"); if (_handshakee->is_exiting()) { log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " exiting", p2i(_handshakee)); @@ -744,7 +745,7 @@ bool HandshakeState::suspend_with_handshake() { // Target is going to wake up and leave suspension. // Let's just stop the thread from doing that. log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " re-suspended", p2i(_handshakee)); - set_suspended(true); + set_suspended(true, register_vthread_SR); return true; } } @@ -752,7 +753,7 @@ bool HandshakeState::suspend_with_handshake() { assert(!is_suspended(), "cannot be suspended without a suspend request"); // Thread is safe, so it must execute the request, thus we can count it as suspended // from this point. - set_suspended(true); + set_suspended(true, register_vthread_SR); set_async_suspend_handshake(true); log_trace(thread, suspend)("JavaThread:" INTPTR_FORMAT " suspended, arming ThreadSuspension", p2i(_handshakee)); ThreadSelfSuspensionHandshake* ts = new ThreadSelfSuspensionHandshake(); @@ -762,17 +763,19 @@ bool HandshakeState::suspend_with_handshake() { // This is the closure that synchronously honors the suspend request. class SuspendThreadHandshake : public HandshakeClosure { + bool _register_vthread_SR; bool _did_suspend; public: - SuspendThreadHandshake() : HandshakeClosure("SuspendThread"), _did_suspend(false) {} + SuspendThreadHandshake(bool register_vthread_SR) : HandshakeClosure("SuspendThread"), + _register_vthread_SR(register_vthread_SR), _did_suspend(false) {} void do_thread(Thread* thr) { JavaThread* target = JavaThread::cast(thr); - _did_suspend = target->handshake_state()->suspend_with_handshake(); + _did_suspend = target->handshake_state()->suspend_with_handshake(_register_vthread_SR); } bool did_suspend() { return _did_suspend; } }; -bool HandshakeState::suspend() { +bool HandshakeState::suspend(bool register_vthread_SR) { JVMTI_ONLY(assert(!_handshakee->is_in_VTMS_transition(), "no suspend allowed in VTMS transition");) JavaThread* self = JavaThread::current(); if (_handshakee == self) { @@ -780,31 +783,42 @@ bool HandshakeState::suspend() { // and just suspend directly ThreadBlockInVM tbivm(self); MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag); - set_suspended(true); + set_suspended(true, register_vthread_SR); do_self_suspend(); return true; } else { - SuspendThreadHandshake st; + SuspendThreadHandshake st(register_vthread_SR); Handshake::execute(&st, _handshakee); return st.did_suspend(); } } -bool HandshakeState::resume() { - if (!is_suspended()) { - return false; - } +bool HandshakeState::resume(bool register_vthread_SR) { MutexLocker ml(&_lock, Mutex::_no_safepoint_check_flag); if (!is_suspended()) { assert(!_handshakee->is_suspended(), "cannot be suspended without a suspend request"); return false; } // Resume the thread. - set_suspended(false); + set_suspended(false, register_vthread_SR); _lock.notify(); return true; } +void HandshakeState::set_suspended(bool is_suspend, bool register_vthread_SR) { +#if INCLUDE_JVMTI + if (register_vthread_SR) { + assert(_handshakee->is_vthread_mounted(), "sanity check"); + if (is_suspend) { + JvmtiVTSuspender::register_vthread_suspend(_handshakee->vthread()); + } else { + JvmtiVTSuspender::register_vthread_resume(_handshakee->vthread()); + } + } +#endif + Atomic::store(&_suspended, is_suspend); +} + void HandshakeState::handle_unsafe_access_error() { if (is_suspended()) { // A suspend handshake was added to the queue after the diff --git a/src/hotspot/share/runtime/handshake.hpp b/src/hotspot/share/runtime/handshake.hpp index f754b744de9..9e963003053 100644 --- a/src/hotspot/share/runtime/handshake.hpp +++ b/src/hotspot/share/runtime/handshake.hpp @@ -173,18 +173,18 @@ class HandshakeState { bool _async_suspend_handshake; // Called from the suspend handshake. - bool suspend_with_handshake(); + bool suspend_with_handshake(bool register_vthread_SR); // Called from the async handshake (the trap) // to stop a thread from continuing execution when suspended. void do_self_suspend(); bool is_suspended() { return Atomic::load(&_suspended); } - void set_suspended(bool to) { return Atomic::store(&_suspended, to); } + void set_suspended(bool to, bool register_vthread_SR); bool has_async_suspend_handshake() { return _async_suspend_handshake; } void set_async_suspend_handshake(bool to) { _async_suspend_handshake = to; } - bool suspend(); - bool resume(); + bool suspend(bool register_vthread_SR); + bool resume(bool register_vthread_SR); }; #endif // SHARE_RUNTIME_HANDSHAKE_HPP diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 8a6da52d762..9f5dd07c4dc 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -1193,7 +1193,7 @@ void JavaThread::set_is_VTMS_transition_disabler(bool val) { // - Target thread will not execute any new bytecode. // - Target thread will not enter any new monitors. // -bool JavaThread::java_suspend() { +bool JavaThread::java_suspend(bool register_vthread_SR) { #if INCLUDE_JVMTI // Suspending a JavaThread in VTMS transition or disabling VTMS transitions can cause deadlocks. assert(!is_in_VTMS_transition(), "no suspend allowed in VTMS transition"); @@ -1202,13 +1202,13 @@ bool JavaThread::java_suspend() { guarantee(Thread::is_JavaThread_protected(/* target */ this), "target JavaThread is not protected in calling context."); - return this->handshake_state()->suspend(); + return this->handshake_state()->suspend(register_vthread_SR); } -bool JavaThread::java_resume() { +bool JavaThread::java_resume(bool register_vthread_SR) { guarantee(Thread::is_JavaThread_protected_by_TLH(/* target */ this), "missing ThreadsListHandle in calling context."); - return this->handshake_state()->resume(); + return this->handshake_state()->resume(register_vthread_SR); } // Wait for another thread to perform object reallocation and relocking on behalf of diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 01da26a97e8..8c62319f8dc 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -698,8 +698,8 @@ private: // Suspend/resume support for JavaThread // higher-level suspension/resume logic called by the public APIs - bool java_suspend(); - bool java_resume(); + bool java_suspend(bool register_vthread_SR); + bool java_resume(bool register_vthread_SR); bool is_suspended() { return _handshake.is_suspended(); } // Check for async exception in addition to safepoint. @@ -710,11 +710,11 @@ private: void wait_for_object_deoptimization(); #if INCLUDE_JVMTI - inline void set_carrier_thread_suspended(); - inline void clear_carrier_thread_suspended(); + inline bool set_carrier_thread_suspended(); + inline bool clear_carrier_thread_suspended(); bool is_carrier_thread_suspended() const { - return _carrier_thread_suspended; + return Atomic::load(&_carrier_thread_suspended); } bool is_in_VTMS_transition() const { return _is_in_VTMS_transition; } diff --git a/src/hotspot/share/runtime/javaThread.inline.hpp b/src/hotspot/share/runtime/javaThread.inline.hpp index f434fc161bb..de492fda50b 100644 --- a/src/hotspot/share/runtime/javaThread.inline.hpp +++ b/src/hotspot/share/runtime/javaThread.inline.hpp @@ -71,11 +71,11 @@ inline void JavaThread::clear_obj_deopt_flag() { } #if INCLUDE_JVMTI -inline void JavaThread::set_carrier_thread_suspended() { - _carrier_thread_suspended = true; +inline bool JavaThread::set_carrier_thread_suspended() { + return Atomic::cmpxchg(&_carrier_thread_suspended, false, true) == false; } -inline void JavaThread::clear_carrier_thread_suspended() { - _carrier_thread_suspended = false; +inline bool JavaThread::clear_carrier_thread_suspended() { + return Atomic::cmpxchg(&_carrier_thread_suspended, true, false) == true; } #endif diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 8cb239636d2..74df0fa9188 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -50,6 +50,7 @@ Monitor* JNICritical_lock = nullptr; Mutex* JvmtiThreadState_lock = nullptr; Monitor* EscapeBarrier_lock = nullptr; Monitor* JvmtiVTMSTransition_lock = nullptr; +Mutex* JvmtiVThreadSuspend_lock = nullptr; Monitor* Heap_lock = nullptr; #if INCLUDE_PARALLELGC Mutex* PSOldGenExpand_lock = nullptr; @@ -260,6 +261,7 @@ void mutex_init() { MUTEX_DEFN(DirectivesStack_lock , PaddedMutex , nosafepoint); MUTEX_DEFN(JvmtiVTMSTransition_lock , PaddedMonitor, safepoint); // used for Virtual Thread Mount State transition management + MUTEX_DEFN(JvmtiVThreadSuspend_lock , PaddedMutex, nosafepoint-1); MUTEX_DEFN(EscapeBarrier_lock , PaddedMonitor, nosafepoint); // Used to synchronize object reallocation/relocking triggered by JVMTI MUTEX_DEFN(Management_lock , PaddedMutex , safepoint); // used for JVM management diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index c307f70ba80..b21a738c8ff 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -48,6 +48,7 @@ extern Monitor* JNICritical_lock; // a lock used while synchroniz extern Mutex* JvmtiThreadState_lock; // a lock on modification of JVMTI thread data extern Monitor* EscapeBarrier_lock; // a lock to sync reallocating and relocking objects because of JVMTI access extern Monitor* JvmtiVTMSTransition_lock; // a lock for Virtual Thread Mount State transition (VTMS transition) management +extern Mutex* JvmtiVThreadSuspend_lock; // a lock for virtual threads suspension extern Monitor* Heap_lock; // a lock on the heap #if INCLUDE_PARALLELGC extern Mutex* PSOldGenExpand_lock; // a lock on expanding the heap diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index c5b24475107..94c957f77b9 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -108,7 +108,6 @@ gc/shenandoah/TestEvilSyncBug.java#generational 8345501 generic-all # :hotspot_runtime runtime/jni/terminatedThread/TestTerminatedThread.java 8317789 aix-ppc64 -runtime/handshake/HandshakeSuspendExitTest.java 8294313 generic-all runtime/Monitor/SyncOnValueBasedClassTest.java 8340995 linux-s390x runtime/os/TestTracePageSizes.java#no-options 8267460 linux-aarch64 runtime/os/TestTracePageSizes.java#explicit-large-page-size 8267460 linux-aarch64