Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/hotspot/share/prims/jvmtiEnv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,10 @@ JvmtiEnv::SuspendThread(jthread thread) {

// Do not use MountUnmountDisabler in context of self suspend to avoid deadlocks.
if (java_thread != current) {
bool is_virtual = thread_oop != nullptr && thread_oop->is_a(vmClasses::BaseVirtualThread_klass());
// Allow other VTs to progress by explicitly releasing the transition disabler.
disabler.reenable_all_except(current, is_virtual ? thread_oop : nullptr);

err = suspend_thread(thread_oop, java_thread, /* single_suspend */ true);
return err;
}
Expand Down
61 changes: 46 additions & 15 deletions src/hotspot/share/runtime/mountUnmountDisabler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,8 @@ MountUnmountDisabler::MountUnmountDisabler(jthread thread)
// disable transitions for all threads if thread is nullptr or a platform thread
MountUnmountDisabler::MountUnmountDisabler(oop thread_oop)
: _is_exclusive(false),
_is_self(false)
_is_self(false),
_did_reenable(false)
{
if (!Continuations::enabled()) {
return; // MountUnmountDisabler is no-op without virtual threads
Expand All @@ -230,6 +231,10 @@ MountUnmountDisabler::MountUnmountDisabler(oop thread_oop)
// 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
MonitorLocker ml(VThreadTransition_lock);
while (exclusive_operation_ongoing()) {
ml.wait(10);
}
if (is_virtual) {
_vthread = Handle(current, thread_oop);
disable_transition_for_one(); // disable transitions for one virtual thread
Expand All @@ -241,7 +246,8 @@ MountUnmountDisabler::MountUnmountDisabler(oop thread_oop)
// disable transitions for all virtual threads
MountUnmountDisabler::MountUnmountDisabler(bool exclusive)
: _is_exclusive(exclusive),
_is_self(false)
_is_self(false),
_did_reenable(false)
{
if (!Continuations::enabled()) {
return; // MountUnmountDisabler is no-op without virtual threads
Expand All @@ -250,10 +256,19 @@ MountUnmountDisabler::MountUnmountDisabler(bool exclusive)
return; // Detached thread, can be a call from Agent_OnLoad.
}
assert(!JavaThread::current()->is_in_vthread_transition(), "");
MonitorLocker ml(VThreadTransition_lock);
while (exclusive_operation_ongoing()) {
ml.wait(10);
}
disable_transition_for_all();
}

MountUnmountDisabler::~MountUnmountDisabler() {
do_reenable();
}

void
MountUnmountDisabler::do_reenable() {
if (!Continuations::enabled()) {
return; // MountUnmountDisabler is a no-op without virtual threads
}
Expand All @@ -265,27 +280,46 @@ MountUnmountDisabler::~MountUnmountDisabler() {
}
if (_vthread() != nullptr) {
enable_transition_for_one(); // enable transitions for one virtual thread
} else {
} else if (!_did_reenable) {
enable_transition_for_all(); // enable transitions for all virtual threads
}
}

// disable transitions for one virtual thread
// Special destructor partial replacement for when we need to reduce a disabling
// of all threads, to potentially just one, earlier than when the destructor would
// run. This is not for use with single-thread mode.
void
MountUnmountDisabler::disable_transition_for_one() {
MonitorLocker ml(VThreadTransition_lock);
while (exclusive_operation_ongoing()) {
ml.wait(10);
MountUnmountDisabler::reenable_all_except(JavaThread* current, oop target) {
assert(_vthread() == nullptr, "not for use in single-thread mode!");
precond(current != nullptr);

if (target != nullptr) {
// Perform a single extra disable on the target before we reenable
// all threads. The target will be enabled again when the destructor runs.
_vthread = Handle(current, target);
MonitorLocker ml(VThreadTransition_lock);
// Note we don't wait for no exclusive use, because we are
// the exclusive use.
disable_transition_for_one();
_vthread = Handle(); // clear again for the global enable
}
do_reenable();
_vthread = Handle(current, target); // now the destructor will reenable the target
_did_reenable = true;
}

// disable transitions for one virtual thread
void
MountUnmountDisabler::disable_transition_for_one() {
precond(VThreadTransition_lock->owned_by_self());
inc_active_disablers();
java_lang_Thread::inc_vthread_transition_disable_count(_vthread());

// Prevent load of transition flag from floating up.
OrderAccess::storeload();

while (java_lang_Thread::is_in_vthread_transition(_vthread())) {
ml.wait(10); // wait while the virtual thread is in transition
VThreadTransition_lock->wait(10); // wait while the virtual thread is in transition
}

// Start of the critical section. If the target is unmounted, we need an acquire
Expand All @@ -303,15 +337,12 @@ void
MountUnmountDisabler::disable_transition_for_all() {
DEBUG_ONLY(JavaThread* thread = JavaThread::current();)
DEBUG_ONLY(thread->set_is_disabler_at_start(true);)
precond(VThreadTransition_lock->owned_by_self());

MonitorLocker ml(VThreadTransition_lock);
while (exclusive_operation_ongoing()) {
ml.wait(10);
}
if (_is_exclusive) {
set_exclusive_operation_ongoing(true);
while (active_disablers() > 0) {
ml.wait(10);
VThreadTransition_lock->wait(10);
}
}
inc_active_disablers();
Expand All @@ -325,7 +356,7 @@ MountUnmountDisabler::disable_transition_for_all() {
// Debug version fails and prints diagnostic information.
for (JavaThreadIteratorWithHandle jtiwh; JavaThread *jt = jtiwh.next(); ) {
while (jt->is_in_vthread_transition()) {
ml.wait(10);
VThreadTransition_lock->wait(10);
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/hotspot/share/runtime/mountUnmountDisabler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,19 +48,23 @@ class MountUnmountDisabler : public AnyObj {
bool _is_virtual; // target thread is virtual
bool _is_self; // MountUnmountDisabler is a no-op for current platform, carrier or virtual thread
Handle _vthread; // virtual thread to disable transitions for, no-op if it is a platform thread
bool _did_reenable; // indicates we've already reenabled all threads before running a destructor - see
// reenable_all_except(oop target) for description

//DEBUG_ONLY(static void print_info();)
void disable_transition_for_one();
void disable_transition_for_all();
void enable_transition_for_one();
void enable_transition_for_all();
void do_reenable();

public:
MountUnmountDisabler(bool exlusive = false);
MountUnmountDisabler(oop thread_oop);
MountUnmountDisabler(jthread thread);
~MountUnmountDisabler();

void reenable_all_except(JavaThread* current, oop target);
static int global_vthread_transition_disable_count();
static void inc_global_vthread_transition_disable_count();
static void dec_global_vthread_transition_disable_count();
Expand Down
1 change: 0 additions & 1 deletion test/hotspot/jtreg/ProblemList-Virtual.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
####
# Bugs

runtime/jni/critical/SuspendInCritical.java 8384369 generic-all
serviceability/AsyncGetCallTrace/MyPackage/ASGCTBaseTest.java 8308026 generic-all
serviceability/jvmti/Heap/IterateHeapWithEscapeAnalysisEnabled.java 8264699 generic-all
vmTestbase/vm/mlvm/indy/func/jvmti/mergeCP_indy2manyDiff_a/TestDescription.java 8308367 generic-all
Expand Down