mirror of
https://github.com/openjdk/jdk.git
synced 2026-06-06 10:42:45 +00:00
8376621: Should not suspend thread in start_transition if _is_disable_suspend set
Reviewed-by: dholmes, sspitsyn
This commit is contained in:
parent
d60fead5cf
commit
b2bf91bf12
@ -87,7 +87,8 @@ class UnmountBeginMark : public StackObj {
|
||||
}
|
||||
~UnmountBeginMark() {
|
||||
assert(!_current->is_suspended()
|
||||
JVMTI_ONLY(|| (_current->is_vthread_transition_disabler() && _result != freeze_ok)), "must be");
|
||||
JVMTI_ONLY(|| (_result != freeze_ok &&
|
||||
(_current->is_vthread_transition_disabler() || _current->is_disable_suspend()))), "must be");
|
||||
assert(_current->is_in_vthread_transition(), "must be");
|
||||
|
||||
if (_result != freeze_ok) {
|
||||
|
||||
@ -873,7 +873,7 @@ public:
|
||||
// Atomic version; invoked by a thread other than the owning thread.
|
||||
bool in_critical_atomic() { return AtomicAccess::load(&_jni_active_critical) > 0; }
|
||||
|
||||
bool jni_deferred_suspension() { return AtomicAccess::load(&_jni_deferred_suspension_count); }
|
||||
bool jni_deferred_suspension() const { return AtomicAccess::load(&_jni_deferred_suspension_count); }
|
||||
inline void enter_jni_deferred_suspension();
|
||||
void exit_jni_deferred_suspension() {
|
||||
precond(Thread::current() == this);
|
||||
|
||||
@ -129,7 +129,7 @@ bool MountUnmountDisabler::is_start_transition_disabled(JavaThread* thread, oop
|
||||
int base_disable_count = notify_jvmti_events() ? 1 : 0;
|
||||
return java_lang_Thread::vthread_transition_disable_count(vthread) > 0
|
||||
|| global_vthread_transition_disable_count() > base_disable_count
|
||||
JVMTI_ONLY(|| (!thread->is_vthread_transition_disabler() &&
|
||||
JVMTI_ONLY(|| (!thread->is_vthread_transition_disabler() && !thread->is_disable_suspend() &&
|
||||
(JvmtiVTSuspender::is_vthread_suspended(java_lang_Thread::thread_id(vthread)) || thread->is_suspended())));
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Copyright (c) 2026, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8376621
|
||||
* @summary Suspend virtual thread while it's inside disableSuspendAndPreempt region
|
||||
* @requires vm.continuations
|
||||
* @requires vm.jvmti
|
||||
* @library /test/lib /test/hotspot/jtreg/testlibrary
|
||||
* @run main/othervm SuspendResume4
|
||||
*/
|
||||
|
||||
import jdk.test.lib.Utils;
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import jvmti.JVMTIUtils;
|
||||
|
||||
public class SuspendResume4 {
|
||||
native static void suspendThread(Thread thread);
|
||||
native static void resumeThread(Thread thread);
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
// Run test in child VM where Locale won't be initialized already by jtreg
|
||||
ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(
|
||||
"-Djava.library.path=" + Utils.TEST_NATIVE_PATH,
|
||||
"-agentpath:" + Utils.TEST_NATIVE_PATH + File.separator + System.mapLibraryName("SuspendResume4"),
|
||||
"SuspendResume4$Test");
|
||||
OutputAnalyzer output = ProcessTools.executeProcess(pb);
|
||||
System.out.println(output.getStdout());
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
static class Test{
|
||||
static String targetName;
|
||||
|
||||
private void runTest() throws Exception {
|
||||
// start target vthread
|
||||
Thread target = Thread.ofVirtual().name("target").start(() -> {
|
||||
// Give time for reader to get suspended in
|
||||
// disableSuspendAndPreempt region.
|
||||
spinWaitMillis(100);
|
||||
// Force unmounting. If reader was suspended inside
|
||||
// disableSuspendAndPreempt region this will block
|
||||
// in VirtualThread.unmount.
|
||||
Thread.yield();
|
||||
});
|
||||
|
||||
// start clinit contender
|
||||
Thread contender = Thread.ofPlatform().name("contender").start(() -> {
|
||||
"JAVA".toLowerCase(java.util.Locale.ROOT);
|
||||
});
|
||||
|
||||
// start vthread that reads target's state
|
||||
Thread reader = Thread.ofVirtual().name("reader").start(() -> {
|
||||
targetName = "name: " + target;
|
||||
});
|
||||
|
||||
// start suspend/resumer
|
||||
Thread suspender = Thread.ofPlatform().name("suspender").start(() -> {
|
||||
SuspendResume4.suspendThread(reader);
|
||||
// Give target time for Thread.yield
|
||||
spinWaitMillis(100);
|
||||
SuspendResume4.resumeThread(reader);
|
||||
});
|
||||
|
||||
target.join();
|
||||
contender.join();
|
||||
suspender.join();
|
||||
reader.join();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Exception {
|
||||
Test obj = new Test();
|
||||
obj.runTest();
|
||||
}
|
||||
|
||||
static void spinWaitMillis(long millis) {
|
||||
long durationNanos = millis * 1_000_000L;
|
||||
long start = System.nanoTime();
|
||||
while (System.nanoTime() - start < durationNanos) {
|
||||
Thread.onSpinWait();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) 2026, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include <jni.h>
|
||||
#include <jvmti.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "jvmti_common.hpp"
|
||||
|
||||
// set by Agent_OnLoad
|
||||
static jvmtiEnv* jvmti = nullptr;
|
||||
|
||||
extern "C" {
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_SuspendResume4_suspendThread(JNIEnv* jni, jclass klass, jthread thread) {
|
||||
jvmtiError err = jvmti->SuspendThread(thread);
|
||||
if (err != JVMTI_ERROR_NONE && err != JVMTI_ERROR_THREAD_NOT_ALIVE) {
|
||||
jni->FatalError("error in JVMTI SuspendThread");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_SuspendResume4_resumeThread(JNIEnv* jni, jclass klass, jthread thread) {
|
||||
jvmtiError err = jvmti->ResumeThread(thread);
|
||||
if (err != JVMTI_ERROR_NONE && err != JVMTI_ERROR_THREAD_NOT_ALIVE) {
|
||||
jni->FatalError("error in JVMTI ResumeThread");
|
||||
}
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL
|
||||
Agent_OnLoad(JavaVM* jvm, char* options, void* reserved) {
|
||||
jvmtiCapabilities caps;
|
||||
jvmtiError err;
|
||||
|
||||
printf("Agent_OnLoad: started\n");
|
||||
if (jvm->GetEnv((void **) (&jvmti), JVMTI_VERSION) != JNI_OK) {
|
||||
LOG("Agent_OnLoad: error in GetEnv");
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
memset(&caps, 0, sizeof(caps));
|
||||
caps.can_suspend = 1;
|
||||
err = jvmti->AddCapabilities(&caps);
|
||||
if (err != JVMTI_ERROR_NONE) {
|
||||
LOG("Agent_OnLoad: error in JVMTI AddCapabilities: %d\n", err);
|
||||
}
|
||||
|
||||
printf("Agent_OnLoad: finished\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
Loading…
x
Reference in New Issue
Block a user