From 13b1ebba276940ff83e53b8ec3659280b3574204 Mon Sep 17 00:00:00 2001 From: Serguei Spitsyn Date: Tue, 14 Feb 2023 01:28:42 +0000 Subject: [PATCH] 8298853: JvmtiVTMSTransitionDisabler should support disabling one virtual thread transitions Reviewed-by: pchilanomate, lmesnik --- src/hotspot/share/classfile/javaClasses.cpp | 27 ++++ src/hotspot/share/classfile/javaClasses.hpp | 9 ++ src/hotspot/share/classfile/vmSymbols.hpp | 2 + src/hotspot/share/prims/jvmtiEnv.cpp | 52 +++---- src/hotspot/share/prims/jvmtiEnvBase.cpp | 4 +- .../share/prims/jvmtiEnvThreadState.cpp | 1 - src/hotspot/share/prims/jvmtiThreadState.cpp | 133 ++++++++++++++---- src/hotspot/share/prims/jvmtiThreadState.hpp | 23 +-- 8 files changed, 182 insertions(+), 69 deletions(-) diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 816a7e3f45f..364974666f4 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1516,6 +1516,8 @@ int java_lang_Thread::_contextClassLoader_offset; int java_lang_Thread::_inheritedAccessControlContext_offset; int java_lang_Thread::_eetop_offset; int java_lang_Thread::_jvmti_thread_state_offset; +int java_lang_Thread::_jvmti_VTMS_transition_disable_count_offset; +int java_lang_Thread::_jvmti_is_in_VTMS_transition_offset; int java_lang_Thread::_interrupted_offset; int java_lang_Thread::_tid_offset; int java_lang_Thread::_continuation_offset; @@ -1566,6 +1568,31 @@ void java_lang_Thread::set_jvmti_thread_state(oop java_thread, JvmtiThreadState* java_thread->address_field_put(_jvmti_thread_state_offset, (address)state); } +int java_lang_Thread::VTMS_transition_disable_count(oop java_thread) { + return java_thread->int_field(_jvmti_VTMS_transition_disable_count_offset); +} + +void java_lang_Thread::inc_VTMS_transition_disable_count(oop java_thread) { + assert(JvmtiVTMSTransition_lock->owned_by_self(), "Must be locked"); + int val = VTMS_transition_disable_count(java_thread); + java_thread->int_field_put(_jvmti_VTMS_transition_disable_count_offset, val + 1); +} + +void java_lang_Thread::dec_VTMS_transition_disable_count(oop java_thread) { + assert(JvmtiVTMSTransition_lock->owned_by_self(), "Must be locked"); + int val = VTMS_transition_disable_count(java_thread); + assert(val > 0, "VTMS_transition_disable_count should never be negative"); + java_thread->int_field_put(_jvmti_VTMS_transition_disable_count_offset, val - 1); +} + +bool java_lang_Thread::is_in_VTMS_transition(oop java_thread) { + return java_thread->bool_field_volatile(_jvmti_is_in_VTMS_transition_offset); +} + +void java_lang_Thread::set_is_in_VTMS_transition(oop java_thread, bool val) { + java_thread->bool_field_put_volatile(_jvmti_is_in_VTMS_transition_offset, val); +} + void java_lang_Thread::clear_scopedValueBindings(oop java_thread) { assert(java_thread != nullptr, "need a java_lang_Thread pointer here"); java_thread->obj_field_put(_scopedValueBindings_offset, nullptr); diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp index f02ca41a0f1..1d21c1ab634 100644 --- a/src/hotspot/share/classfile/javaClasses.hpp +++ b/src/hotspot/share/classfile/javaClasses.hpp @@ -334,6 +334,8 @@ class java_lang_Class : AllStatic { #define THREAD_INJECTED_FIELDS(macro) \ macro(java_lang_Thread, jvmti_thread_state, intptr_signature, false) \ + macro(java_lang_Thread, jvmti_VTMS_transition_disable_count, int_signature, false) \ + macro(java_lang_Thread, jvmti_is_in_VTMS_transition, bool_signature, false) \ JFR_ONLY(macro(java_lang_Thread, jfr_epoch, short_signature, false)) class java_lang_Thread : AllStatic { @@ -347,6 +349,8 @@ class java_lang_Thread : AllStatic { static int _inheritedAccessControlContext_offset; static int _eetop_offset; static int _jvmti_thread_state_offset; + static int _jvmti_VTMS_transition_disable_count_offset; + static int _jvmti_is_in_VTMS_transition_offset; static int _interrupted_offset; static int _tid_offset; static int _continuation_offset; @@ -396,6 +400,11 @@ class java_lang_Thread : AllStatic { static JvmtiThreadState* jvmti_thread_state(oop java_thread); static void set_jvmti_thread_state(oop java_thread, JvmtiThreadState* state); + static int VTMS_transition_disable_count(oop java_thread); + static void inc_VTMS_transition_disable_count(oop java_thread); + static void dec_VTMS_transition_disable_count(oop java_thread); + static bool is_in_VTMS_transition(oop java_thread); + static void set_is_in_VTMS_transition(oop java_thread, bool val); // Clear all scoped value bindings on error static void clear_scopedValueBindings(oop java_thread); diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index f6a4d8b2143..b321b7fffd3 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -520,6 +520,8 @@ template(java_lang_Boolean_signature, "Ljava/lang/Boolean;") \ template(url_code_signer_array_void_signature, "(Ljava/net/URL;[Ljava/security/CodeSigner;)V") \ template(jvmti_thread_state_name, "jvmti_thread_state") \ + template(jvmti_VTMS_transition_disable_count_name, "jvmti_VTMS_transition_disable_count") \ + template(jvmti_is_in_VTMS_transition_name, "jvmti_is_in_VTMS_transition") \ template(module_entry_name, "module_entry") \ template(resolved_references_name, "") \ template(init_lock_name, "") \ diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index a2917f1b5b9..37bd3a19729 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -149,7 +149,7 @@ jvmtiError JvmtiEnv::SetThreadLocalStorage(jthread thread, const void* data) { JavaThread* current = JavaThread::current(); JvmtiThreadState* state = nullptr; - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current); JavaThread* java_thread = nullptr; @@ -202,7 +202,7 @@ JvmtiEnv::GetThreadLocalStorage(jthread thread, void** data_ptr) { VM_ENTRY_BASE(jvmtiError, JvmtiEnv::GetThreadLocalStorage , current_thread) debug_only(VMNativeEntryWrapper __vew;) - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -575,7 +575,7 @@ JvmtiEnv::SetEventNotificationMode(jvmtiEventMode mode, jvmtiEvent event_type, j if (event_type == JVMTI_EVENT_CLASS_FILE_LOAD_HOOK && enabled) { record_class_file_load_hook_enabled(); } - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(event_thread); if (event_thread == nullptr) { // Can be called at Agent_OnLoad() time with event_thread == nullptr @@ -856,7 +856,7 @@ JvmtiEnv::GetJLocationFormat(jvmtiJlocationFormat* format_ptr) { jvmtiError JvmtiEnv::GetThreadState(jthread thread, jint* thread_state_ptr) { JavaThread* current_thread = JavaThread::current(); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -1181,7 +1181,7 @@ jvmtiError JvmtiEnv::StopThread(jthread thread, jobject exception) { JavaThread* current_thread = JavaThread::current(); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; oop thread_oop = nullptr; @@ -1213,7 +1213,7 @@ JvmtiEnv::InterruptThread(jthread thread) { JavaThread* current_thread = JavaThread::current(); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -1258,7 +1258,7 @@ JvmtiEnv::GetThreadInfo(jthread thread, jvmtiThreadInfo* info_ptr) { JavaThread* java_thread = nullptr; oop thread_oop = nullptr; - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); // if thread is null the current thread is used @@ -1358,7 +1358,7 @@ JvmtiEnv::GetOwnedMonitorInfo(jthread thread, jint* owned_monitor_count_ptr, job GrowableArray *owned_monitors_list = new (mtServiceability) GrowableArray(1, mtServiceability); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(calling_thread); JavaThread* java_thread = nullptr; @@ -1431,7 +1431,7 @@ JvmtiEnv::GetOwnedMonitorStackDepthInfo(jthread thread, jint* monitor_info_count GrowableArray *owned_monitors_list = new (mtServiceability) GrowableArray(1, mtServiceability); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(calling_thread); JavaThread* java_thread = nullptr; @@ -1501,7 +1501,7 @@ JvmtiEnv::GetCurrentContendedMonitor(jthread thread, jobject* monitor_ptr) { JavaThread* calling_thread = JavaThread::current(); HandleMark hm(calling_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(calling_thread); JavaThread* java_thread = nullptr; @@ -1715,7 +1715,7 @@ JvmtiEnv::GetStackTrace(jthread thread, jint start_depth, jint max_frame_count, JavaThread* current_thread = JavaThread::current(); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -1833,7 +1833,7 @@ JvmtiEnv::GetFrameCount(jthread thread, jint* count_ptr) { JavaThread* current_thread = JavaThread::current(); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -1877,7 +1877,7 @@ JvmtiEnv::PopFrame(jthread thread) { if (thread == nullptr) { return JVMTI_ERROR_INVALID_THREAD; } - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -1925,7 +1925,7 @@ JvmtiEnv::GetFrameLocation(jthread thread, jint depth, jmethodID* method_ptr, jl JavaThread* current_thread = JavaThread::current(); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -1965,7 +1965,7 @@ JvmtiEnv::GetFrameLocation(jthread thread, jint depth, jmethodID* method_ptr, jl jvmtiError JvmtiEnv::NotifyFramePop(jthread thread, jint depth) { ResourceMark rm; - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh; JavaThread* java_thread = nullptr; @@ -2243,7 +2243,7 @@ JvmtiEnv::GetLocalObject(jthread thread, jint depth, jint slot, jobject* value_p // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2284,7 +2284,7 @@ JvmtiEnv::GetLocalInstance(jthread thread, jint depth, jobject* value_ptr){ // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2326,7 +2326,7 @@ JvmtiEnv::GetLocalInt(jthread thread, jint depth, jint slot, jint* value_ptr) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2368,7 +2368,7 @@ JvmtiEnv::GetLocalLong(jthread thread, jint depth, jint slot, jlong* value_ptr) // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2410,7 +2410,7 @@ JvmtiEnv::GetLocalFloat(jthread thread, jint depth, jint slot, jfloat* value_ptr // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2452,7 +2452,7 @@ JvmtiEnv::GetLocalDouble(jthread thread, jint depth, jint slot, jdouble* value_p // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2493,7 +2493,7 @@ JvmtiEnv::SetLocalObject(jthread thread, jint depth, jint slot, jobject value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2530,7 +2530,7 @@ JvmtiEnv::SetLocalInt(jthread thread, jint depth, jint slot, jint value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2567,7 +2567,7 @@ JvmtiEnv::SetLocalLong(jthread thread, jint depth, jint slot, jlong value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2604,7 +2604,7 @@ JvmtiEnv::SetLocalFloat(jthread thread, jint depth, jint slot, jfloat value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; @@ -2641,7 +2641,7 @@ JvmtiEnv::SetLocalDouble(jthread thread, jint depth, jint slot, jdouble value) { // doit_prologue(), but after doit() is finished with it. ResourceMark rm(current_thread); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index 37541bcfcff..6753328d22d 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -680,7 +680,7 @@ JvmtiEnvBase::check_and_skip_hidden_frames(oop vthread, javaVFrame* jvf) { // nothing to skip return jvf; } - jvf = check_and_skip_hidden_frames(state->is_in_VTMS_transition(), jvf); + jvf = check_and_skip_hidden_frames(java_lang_Thread::is_in_VTMS_transition(vthread), jvf); return jvf; } @@ -1912,7 +1912,7 @@ JvmtiEnvBase::force_early_return(jthread thread, jvalue value, TosState tos) { JavaThread* current_thread = JavaThread::current(); HandleMark hm(current_thread); - JvmtiVTMSTransitionDisabler disabler; + JvmtiVTMSTransitionDisabler disabler(thread); ThreadsListHandle tlh(current_thread); JavaThread* java_thread = nullptr; diff --git a/src/hotspot/share/prims/jvmtiEnvThreadState.cpp b/src/hotspot/share/prims/jvmtiEnvThreadState.cpp index d847c60d103..6044cd1ec76 100644 --- a/src/hotspot/share/prims/jvmtiEnvThreadState.cpp +++ b/src/hotspot/share/prims/jvmtiEnvThreadState.cpp @@ -376,7 +376,6 @@ void JvmtiEnvThreadState::reset_current_location(jvmtiEvent event_type, bool ena JavaThread* thread = get_thread_or_saved(); oop thread_oop = jvmti_thread_state()->get_thread_oop(); - assert(!jvmti_thread_state()->is_in_VTMS_transition(), "sanity check"); if (thread == nullptr && event_type == JVMTI_EVENT_SINGLE_STEP && is_virtual()) { // Handle the unmounted virtual thread case. diff --git a/src/hotspot/share/prims/jvmtiThreadState.cpp b/src/hotspot/share/prims/jvmtiThreadState.cpp index 9c247eb7505..97699648613 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.cpp +++ b/src/hotspot/share/prims/jvmtiThreadState.cpp @@ -82,9 +82,7 @@ JvmtiThreadState::JvmtiThreadState(JavaThread* thread, oop thread_oop) _earlyret_tos = ilgl; _earlyret_value.j = 0L; _earlyret_oop = nullptr; - _jvmti_event_queue = nullptr; - _is_in_VTMS_transition = false; _is_virtual = false; _thread_oop_h = OopHandle(JvmtiExport::jvmti_oop_storage(), thread_oop); @@ -218,8 +216,11 @@ JvmtiThreadState::periodic_clean_up() { // VTMS transitions cannot be disabled while this counter is positive. volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_count = 0; -// VTMS transitions is disabled while this counter is positive -volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_disable_count = 0; +// VTMS transitions for one virtual thread are disabled while it is positive +volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_disable_for_one_count = 0; + +// VTMs transitions for all virtual threads are disabled while it is positive +volatile int JvmtiVTMSTransitionDisabler::_VTMS_transition_disable_for_all_count = 0; // There is an active suspender or resumer. volatile bool JvmtiVTMSTransitionDisabler::_SR_mode = false; @@ -228,8 +229,9 @@ volatile bool JvmtiVTMSTransitionDisabler::_SR_mode = false; #ifdef ASSERT void JvmtiVTMSTransitionDisabler::print_info() { - log_error(jvmti)("_VTMS_transition_disable_count: %d _VTMS_transition_count: %d\n\n", - _VTMS_transition_disable_count, _VTMS_transition_count); + log_error(jvmti)("_VTMS_transition_count: %d\n", _VTMS_transition_count); + log_error(jvmti)("_VTMS_transition_disable_for_one_count: %d\n", _VTMS_transition_disable_for_one_count); + log_error(jvmti)("_VTMS_transition_disable_for_all_count: %d\n\n", _VTMS_transition_disable_for_all_count); int attempts = 10000; for (JavaThreadIteratorWithHandle jtiwh; JavaThread *java_thread = jtiwh.next(); ) { ResourceMark rm; @@ -240,15 +242,35 @@ JvmtiVTMSTransitionDisabler::print_info() { } #endif -JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(bool is_SR) { +// disable VTMS transitions for one virtual thread +// no-op if thread is non-NULL and not a virtual thread +JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(jthread thread) + : _is_SR(false), _thread(thread) +{ if (!Continuations::enabled()) { return; // JvmtiVTMSTransitionDisabler is no-op without virtual threads } if (Thread::current_or_null() == nullptr) { return; // Detached thread, can be a call from Agent_OnLoad. } - _is_SR = is_SR; - disable_VTMS_transitions(); + if (_thread != nullptr) { + 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 + } +} + +// disable VTMS transitions for all virtual threads +JvmtiVTMSTransitionDisabler::JvmtiVTMSTransitionDisabler(bool is_SR) + : _is_SR(is_SR), _thread(nullptr) +{ + if (!Continuations::enabled()) { + return; // JvmtiVTMSTransitionDisabler is no-op without virtual threads + } + if (Thread::current_or_null() == nullptr) { + return; // Detached thread, can be a call from Agent_OnLoad. + } + VTMS_transition_disable_for_all(); } JvmtiVTMSTransitionDisabler::~JvmtiVTMSTransitionDisabler() { @@ -258,11 +280,43 @@ JvmtiVTMSTransitionDisabler::~JvmtiVTMSTransitionDisabler() { if (Thread::current_or_null() == nullptr) { return; // Detached thread, can be a call from Agent_OnLoad. } - enable_VTMS_transitions(); + if (_thread != nullptr) { + 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 + } } +// disable VTMS transitions for one virtual thread void -JvmtiVTMSTransitionDisabler::disable_VTMS_transitions() { +JvmtiVTMSTransitionDisabler::VTMS_transition_disable_for_one() { + assert(_thread != NULL, "sanity check"); + JavaThread* thread = JavaThread::current(); + HandleMark hm(thread); + Handle vth = Handle(thread, JNIHandles::resolve_external_guard(_thread)); + if (!java_lang_VirtualThread::is_instance(vth())) { + return; // no-op if _thread is not a virtual thread + } + ThreadBlockInVM tbivm(thread); + MonitorLocker ml(JvmtiVTMSTransition_lock, Mutex::_no_safepoint_check_flag); + + while (_SR_mode) { // suspender or resumer is a JvmtiVTMSTransitionDisabler monopolist + ml.wait(10); // wait while there is an active suspender or resumer + } + Atomic::inc(&_VTMS_transition_disable_for_one_count); + java_lang_Thread::inc_VTMS_transition_disable_count(vth()); + + while (java_lang_Thread::is_in_VTMS_transition(vth())) { + ml.wait(10); // wait while the virtual thread is in transition + } +#ifdef ASSERT + thread->set_is_VTMS_transition_disabler(true); +#endif +} + +// disable VTMS transitions for all virtual threads +void +JvmtiVTMSTransitionDisabler::VTMS_transition_disable_for_all() { JavaThread* thread = JavaThread::current(); int attempts = 50000; { @@ -276,11 +330,11 @@ JvmtiVTMSTransitionDisabler::disable_VTMS_transitions() { } if (_is_SR) { _SR_mode = true; - while (_VTMS_transition_disable_count > 0) { + while (_VTMS_transition_disable_for_all_count > 0) { ml.wait(10); // Wait while there is any active jvmtiVTMSTransitionDisabler. } } - Atomic::inc(&_VTMS_transition_disable_count); + Atomic::inc(&_VTMS_transition_disable_for_all_count); // Block while some mount/unmount transitions are in progress. // Debug version fails and prints diagnostic information. @@ -300,23 +354,44 @@ JvmtiVTMSTransitionDisabler::disable_VTMS_transitions() { #ifdef ASSERT if (attempts == 0) { print_info(); - fatal("stuck in JvmtiVTMSTransitionDisabler::disable_VTMS_transitions"); + fatal("stuck in JvmtiVTMSTransitionDisabler::VTMS_transition_disable"); } #endif } +// enable VTMS transitions for one virtual thread void -JvmtiVTMSTransitionDisabler::enable_VTMS_transitions() { +JvmtiVTMSTransitionDisabler::VTMS_transition_enable_for_one() { + JavaThread* thread = JavaThread::current(); + HandleMark hm(thread); + Handle vth = Handle(thread, JNIHandles::resolve_external_guard(_thread)); + if (!java_lang_VirtualThread::is_instance(vth())) { + return; // no-op if _thread is not a virtual thread + } + MonitorLocker ml(JvmtiVTMSTransition_lock, Mutex::_no_safepoint_check_flag); + java_lang_Thread::dec_VTMS_transition_disable_count(vth()); + Atomic::dec(&_VTMS_transition_disable_for_one_count); + if (_VTMS_transition_disable_for_one_count == 0 || _is_SR) { + ml.notify_all(); + } +#ifdef ASSERT + thread->set_is_VTMS_transition_disabler(false); +#endif +} + +// enable VTMS transitions for all virtual threads +void +JvmtiVTMSTransitionDisabler::VTMS_transition_enable_for_all() { JavaThread* current = JavaThread::current(); { MonitorLocker ml(JvmtiVTMSTransition_lock, Mutex::_no_safepoint_check_flag); - assert(_VTMS_transition_disable_count > 0, "VTMS_transition sanity check"); + assert(_VTMS_transition_disable_for_all_count > 0, "VTMS_transition sanity check"); if (_is_SR) { // Disabler is suspender or resumer. _SR_mode = false; } - Atomic::dec(&_VTMS_transition_disable_count); - if (_VTMS_transition_disable_count == 0 || _is_SR) { + Atomic::dec(&_VTMS_transition_disable_for_all_count); + if (_VTMS_transition_disable_for_all_count == 0 || _is_SR) { ml.notify_all(); } #ifdef ASSERT @@ -335,17 +410,21 @@ JvmtiVTMSTransitionDisabler::start_VTMS_transition(jthread vthread, bool is_moun // Avoid using MonitorLocker on performance critical path, use // two-level synchronization with lock-free operations on counters. Atomic::inc(&_VTMS_transition_count); // Try to enter VTMS transition section optmistically. + java_lang_Thread::set_is_in_VTMS_transition(vth(), true); // Do not allow suspends inside VTMS transitions. // Block while transitions are disabled or there are suspend requests. int64_t thread_id = java_lang_Thread::thread_id(vth()); // Cannot use oops while blocked. - if (_VTMS_transition_disable_count > 0 || + + if (_VTMS_transition_disable_for_all_count > 0 || + java_lang_Thread::VTMS_transition_disable_count(vth()) > 0 || thread->is_suspended() || JvmtiVTSuspender::is_vthread_suspended(thread_id) ) { // Slow path: undo unsuccessful optimistic counter incrementation. // It can cause an extra waiting cycle for VTMS transition disablers. Atomic::dec(&_VTMS_transition_count); + java_lang_Thread::set_is_in_VTMS_transition(vth(), false); while (true) { ThreadBlockInVM tbivm(thread); @@ -353,7 +432,8 @@ JvmtiVTMSTransitionDisabler::start_VTMS_transition(jthread vthread, bool is_moun // Do not allow suspends inside VTMS transitions. // Block while transitions are disabled or there are suspend requests. - if (_VTMS_transition_disable_count > 0 || + if (_VTMS_transition_disable_for_all_count > 0 || + java_lang_Thread::VTMS_transition_disable_count(vth()) > 0 || thread->is_suspended() || JvmtiVTSuspender::is_vthread_suspended(thread_id) ) { @@ -365,6 +445,7 @@ JvmtiVTMSTransitionDisabler::start_VTMS_transition(jthread vthread, bool is_moun continue; // ~ThreadBlockInVM has handshake-based suspend point. } Atomic::inc(&_VTMS_transition_count); + java_lang_Thread::set_is_in_VTMS_transition(vth(), true); break; } } @@ -379,10 +460,6 @@ JvmtiVTMSTransitionDisabler::start_VTMS_transition(jthread vthread, bool is_moun // Enter VTMS transition section. assert(!thread->is_in_VTMS_transition(), "VTMS_transition sanity check"); thread->set_is_in_VTMS_transition(true); - JvmtiThreadState* vstate = java_lang_Thread::jvmti_thread_state(vth()); - if (vstate != nullptr) { - vstate->set_is_in_VTMS_transition(true); - } } void @@ -393,15 +470,13 @@ JvmtiVTMSTransitionDisabler::finish_VTMS_transition(jthread vthread, bool is_mou thread->set_is_in_VTMS_transition(false); oop vt = JNIHandles::resolve_external_guard(vthread); int64_t thread_id = java_lang_Thread::thread_id(vt); - JvmtiThreadState* vstate = java_lang_Thread::jvmti_thread_state(vt); - if (vstate != nullptr) { - vstate->set_is_in_VTMS_transition(false); - } + java_lang_Thread::set_is_in_VTMS_transition(vt, false); Atomic::dec(&_VTMS_transition_count); // Unblock waiting VTMS transition disablers. - if (_VTMS_transition_disable_count > 0) { + if (_VTMS_transition_disable_for_one_count > 0 || + _VTMS_transition_disable_for_all_count > 0) { MonitorLocker ml(JvmtiVTMSTransition_lock, Mutex::_no_safepoint_check_flag); ml.notify_all(); } diff --git a/src/hotspot/share/prims/jvmtiThreadState.hpp b/src/hotspot/share/prims/jvmtiThreadState.hpp index 029f2852eef..1e8bb19c125 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.hpp +++ b/src/hotspot/share/prims/jvmtiThreadState.hpp @@ -79,19 +79,24 @@ class JvmtiEnvThreadStateIterator : public StackObj { // class JvmtiVTMSTransitionDisabler { private: - static volatile bool _SR_mode; // there is an active suspender or resumer - static volatile int _VTMS_transition_count; // current number of VTMS transitions - static volatile int _VTMS_transition_disable_count; // VTMS transitions are disabled while it is non-zero + static volatile int _VTMS_transition_disable_for_one_count; // transitions for one virtual thread are disabled while it is positive + static volatile int _VTMS_transition_disable_for_all_count; // transitions for all virtual threads are disabled while it is positive + static volatile bool _SR_mode; // there is an active suspender or resumer + static volatile int _VTMS_transition_count; // current number of VTMS transitions - bool _is_SR; // is suspender or resumer - - void disable_VTMS_transitions(); - void enable_VTMS_transitions(); + bool _is_SR; // is suspender or resumer + jthread _thread; // virtual thread to disable transitions for, no-op if it is a platform thread DEBUG_ONLY(static void print_info();) + void VTMS_transition_disable_for_one(); + void VTMS_transition_disable_for_all(); + void VTMS_transition_enable_for_one(); + void VTMS_transition_enable_for_all(); + public: // parameter is_SR: suspender or resumer JvmtiVTMSTransitionDisabler(bool is_SR = false); + JvmtiVTMSTransitionDisabler(jthread thread); ~JvmtiVTMSTransitionDisabler(); static void start_VTMS_transition(jthread vthread, bool is_mount); @@ -153,7 +158,6 @@ class JvmtiThreadState : public CHeapObj { OopHandle _thread_oop_h; // Jvmti Events that cannot be posted in their current context. JvmtiDeferredEventQueue* _jvmti_event_queue; - bool _is_in_VTMS_transition; // saved JavaThread.is_in_VTMS_transition() bool _is_virtual; // state belongs to a virtual thread bool _hide_single_stepping; bool _pending_interp_only_mode; @@ -270,9 +274,6 @@ class JvmtiThreadState : public CHeapObj { void set_thread(JavaThread* thread); oop get_thread_oop(); - // The JavaThread is_in_VTMS_transition() bit saved at unmount to restore at mount. - inline bool is_in_VTMS_transition() { return _is_in_VTMS_transition; } - inline void set_is_in_VTMS_transition(bool val) { _is_in_VTMS_transition = val; } inline bool is_virtual() { return _is_virtual; } // the _thread is virtual inline bool is_exception_detected() { return _exception_state == ES_DETECTED; }