8307399: get rid of compatibility ThreadStart/ThreadEnd events for virtual threads

Reviewed-by: alanb, pchilanomate, cjplummer
This commit is contained in:
Serguei Spitsyn 2023-05-10 01:48:03 +00:00
parent f5a6b7f7c0
commit 2be1f10fec
6 changed files with 41 additions and 53 deletions
src/hotspot/share
test/hotspot/jtreg/serviceability/jvmti/vthread/VirtualThreadStartTest

@ -9697,6 +9697,7 @@ myInit() {
<li><eventlink id="VMStart"></eventlink></li>
<li><eventlink id="VMDeath"></eventlink></li>
<li><eventlink id="ThreadStart"></eventlink></li>
<li><eventlink id="VirtualThreadStart"></eventlink></li>
<li><eventlink id="CompiledMethodLoad"></eventlink></li>
<li><eventlink id="CompiledMethodUnload"></eventlink></li>
<li><eventlink id="DynamicCodeGenerated"></eventlink></li>
@ -12249,6 +12250,8 @@ myInit() {
<li><eventlink id="VMDeath"></eventlink></li>
<li><eventlink id="ThreadStart"></eventlink></li>
<li><eventlink id="ThreadEnd"></eventlink></li>
<li><eventlink id="VirtualThreadStart"></eventlink></li>
<li><eventlink id="VirtualThreadEnd"></eventlink></li>
<li><eventlink id="ClassLoad"></eventlink></li>
<li><eventlink id="ClassPrepare"></eventlink></li>
</ul>
@ -12937,16 +12940,10 @@ myInit() {
A thread start event is generated by a new thread before its initial
method executes.
<p/>
This event is generated by platform threads. It is also generated by
virtual threads when the capability
<internallink id="jvmtiCapabilities.can_support_virtual_threads">
<code>can_support_virtual_threads</code></internallink> is not enabled.
Agents without support for virtual threads that enable this event will
therefore be notified by all newly started threads.
This event is generated by platform thread. It is not generated by virtual threads.
<p/>
If the capability <code>can_support_virtual_threads</code> is enabled then
this event is not generated by virtual threads. Agents with support for
virtual threads can enable <eventlink id="VirtualThreadStart"></eventlink>
Agents with the <code>can_support_virtual_threads</code> capability
can enable the <eventlink id="VirtualThreadStart"></eventlink> event
to be notified by newly started virtual threads.
<p/>
A platform thread may be listed in the array returned by
@ -12984,16 +12981,10 @@ myInit() {
A thread end event is generated by a terminating thread after its
initial method has finished execution.
<p/>
This event is generated by platform threads. It is also generated by
virtual threads when the capability
<internallink id="jvmtiCapabilities.can_support_virtual_threads">
<code>can_support_virtual_threads</code></internallink> is not enabled.
Agents without support for virtual threads that enable this event for
all threads will therefore be notified by all terminating threads.
This event is generated by platform thread. It is not generated by virtual threads.
<p/>
If the capability <code>can_support_virtual_threads</code> is enabled then
this event is not generated by virtual threads. Agents with support for
virtual threads can enable <eventlink id="VirtualThreadEnd"></eventlink>
Agents with the <code>can_support_virtual_threads</code> capability
can enable the <eventlink id="VirtualThreadEnd"></eventlink> event
to be notified by terminating virtual threads.
<p/>
A platform thread may be listed in the array returned by

@ -1476,11 +1476,13 @@ void JvmtiExport::post_thread_start(JavaThread *thread) {
// do JVMTI thread initialization (if needed)
JvmtiEventController::thread_started(thread);
if (JvmtiExport::can_support_virtual_threads() && thread->threadObj()->is_a(vmClasses::BoundVirtualThread_klass())) {
// Check for VirtualThreadStart event instead.
HandleMark hm(thread);
Handle vthread(thread, thread->threadObj());
JvmtiExport::post_vthread_start((jthread)vthread.raw_value());
if (thread->threadObj()->is_a(vmClasses::BoundVirtualThread_klass())) {
if (JvmtiExport::can_support_virtual_threads()) {
// Check for VirtualThreadStart event instead.
HandleMark hm(thread);
Handle vthread(thread, thread->threadObj());
JvmtiExport::post_vthread_start((jthread)vthread.raw_value());
}
return;
}
@ -1520,11 +1522,13 @@ void JvmtiExport::post_thread_end(JavaThread *thread) {
return;
}
if (JvmtiExport::can_support_virtual_threads() && thread->threadObj()->is_a(vmClasses::BoundVirtualThread_klass())) {
// Check for VirtualThreadEnd event instead.
HandleMark hm(thread);
Handle vthread(thread, thread->threadObj());
JvmtiExport::post_vthread_end((jthread)vthread.raw_value());
if (thread->threadObj()->is_a(vmClasses::BoundVirtualThread_klass())) {
if (JvmtiExport::can_support_virtual_threads()) {
// Check for VirtualThreadEnd event instead.
HandleMark hm(thread);
Handle vthread(thread, thread->threadObj());
JvmtiExport::post_vthread_end((jthread)vthread.raw_value());
}
return;
}

@ -526,17 +526,11 @@ JvmtiVTMSTransitionDisabler::VTMS_vthread_start(jobject vthread) {
assert(!thread->is_in_VTMS_transition(), "sanity check");
assert(!thread->is_in_tmp_VTMS_transition(), "sanity check");
JvmtiEventController::thread_started(thread);
if (JvmtiExport::can_support_virtual_threads()) {
JvmtiEventController::thread_started(thread);
if (JvmtiExport::should_post_vthread_start()) {
JvmtiExport::post_vthread_start(vthread);
}
} else { // compatibility for vthread unaware agents: legacy thread_start
if (PostVirtualThreadCompatibleLifecycleEvents &&
JvmtiExport::should_post_thread_life()) {
// JvmtiEventController::thread_started is called here
JvmtiExport::post_thread_start(thread);
}
}
// post VirtualThreadMount event after VirtualThreadStart
if (JvmtiExport::should_post_vthread_mount()) {
@ -559,11 +553,6 @@ JvmtiVTMSTransitionDisabler::VTMS_vthread_end(jobject vthread) {
if (JvmtiExport::should_post_vthread_end()) {
JvmtiExport::post_vthread_end(vthread);
}
} else { // compatibility for vthread unaware agents: legacy thread_end
if (PostVirtualThreadCompatibleLifecycleEvents &&
JvmtiExport::should_post_thread_life()) {
JvmtiExport::post_thread_end(thread);
}
}
if (thread->jvmti_thread_state() != nullptr) {
JvmtiExport::cleanup_thread(thread);

@ -698,10 +698,6 @@ const int ObjectAlignmentInBytes = 8;
"Disable the use of stack guard pages if the JVM is loaded " \
"on the primordial process thread") \
\
product(bool, PostVirtualThreadCompatibleLifecycleEvents, true, EXPERIMENTAL, \
"Post virtual thread ThreadStart and ThreadEnd events for " \
"virtual thread unaware agents") \
\
product(bool, DoJVMTIVirtualThreadTransitions, true, EXPERIMENTAL, \
"Do JVMTI virtual thread mount/unmount transitions " \
"(disabling this flag implies no JVMTI events are posted)") \

@ -46,6 +46,7 @@ public class VirtualThreadStartTest {
private static final String AGENT_LIB = "VirtualThreadStartTest";
private static final int THREAD_CNT = 10;
private static native boolean canSupportVirtualThreads();
private static native int getAndResetStartedThreads();
public static void main(String[] args) throws Exception {
@ -55,8 +56,6 @@ public class VirtualThreadStartTest {
String arg = args.length == 2 ? args[1] : "";
VirtualMachine vm = VirtualMachine.attach(String.valueOf(ProcessHandle.current().pid()));
vm.loadAgentLibrary(AGENT_LIB, arg);
} else {
System.loadLibrary(AGENT_LIB);
}
getAndResetStartedThreads();
@ -64,11 +63,15 @@ public class VirtualThreadStartTest {
Thread.ofVirtual().name("Tested-VT-" + i).start(() -> {}).join();
}
// No VirtualThreadStart events are expected if can_support_virtual_threads is disabled.
int expStartedThreads = canSupportVirtualThreads() ? THREAD_CNT : 0;
int startedThreads = getAndResetStartedThreads();
System.out.println("ThreadStart event count: " + startedThreads + ", expected: " + THREAD_CNT);
if (startedThreads != THREAD_CNT) {
System.out.println("ThreadStart event count: " + startedThreads + ", expected: " + expStartedThreads);
if (startedThreads != expStartedThreads) {
throw new RuntimeException("Failed: wrong ThreadStart count: " +
startedThreads + " expected: " + THREAD_CNT);
startedThreads + " expected: " + expStartedThreads);
}
}
}

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2022, 2023, 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
@ -67,12 +67,18 @@ void JNICALL VirtualThreadStart(jvmtiEnv *jvmti, JNIEnv* jni, jthread thread) {
if (!can_support_vt_enabled) {
fatal(jni, "Failed: expected ThreadStart instead of VirtualThreadStart event");
}
printf("VirtualThreadStart event: %s\n", tname);
LOG("VirtualThreadStart event: %s\n", tname);
started_thread_cnt++;
}
deallocate(jvmti, jni, (void*)tname);
}
JNIEXPORT jboolean JNICALL
Java_VirtualThreadStartTest_canSupportVirtualThreads(JNIEnv* jni, jclass clazz) {
LOG("can_support_virtual_threads: %d\n", can_support_vt_enabled);
return can_support_vt_enabled ? JNI_TRUE : JNI_FALSE;
}
JNIEXPORT jint JNICALL
Java_VirtualThreadStartTest_getAndResetStartedThreads(JNIEnv* jni, jclass clazz) {
RawMonitorLocker agent_start_locker(jvmti, jni, agent_event_lock);
@ -116,8 +122,7 @@ jint agent_init(JavaVM *jvm, char *options, void *reserved) {
return JNI_ERR;
}
}
printf("agent_init: can_support_virtual_threads capability: %d\n",
caps.can_support_virtual_threads);
LOG("agent_init: can_support_virtual_threads: %d\n", caps.can_support_virtual_threads);
err = jvmti->SetEventCallbacks(&callbacks, (jint)sizeof(callbacks));
if (err != JVMTI_ERROR_NONE) {