a663d5d694
Reviewed-by: sspitsyn
199 lines
7.0 KiB
Java
199 lines
7.0 KiB
Java
/*
|
|
* Copyright (c) 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
|
|
* 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
|
|
* @summary Verifies JVMTI works for agents loaded into running VM
|
|
* @requires vm.jvmti
|
|
* @requires vm.continuations
|
|
* @enablePreview
|
|
* @library /test/lib /test/hotspot/jtreg
|
|
* @build jdk.test.whitebox.WhiteBox
|
|
*
|
|
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
|
* @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. -agentlib:ToggleNotifyJvmtiTest ToggleNotifyJvmtiTest
|
|
* @run main/othervm/native -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:. -Djdk.attach.allowAttachSelf=true ToggleNotifyJvmtiTest attach
|
|
*/
|
|
|
|
import com.sun.tools.attach.VirtualMachine;
|
|
import java.util.concurrent.ThreadFactory;
|
|
import jdk.test.whitebox.WhiteBox;
|
|
|
|
// The TestTask mimics some thread activity, but it is important
|
|
// to have sleep() calls to provide yielding as some frequency of virtual
|
|
// thread mount state transitions is needed for this test scenario.
|
|
class TestTask implements Runnable {
|
|
private String name;
|
|
private volatile boolean threadReady = false;
|
|
private volatile boolean shouldFinish = false;
|
|
|
|
// make thread with specific name
|
|
public TestTask(String name) {
|
|
this.name = name;
|
|
}
|
|
|
|
// run thread continuously
|
|
public void run() {
|
|
// run in a loop
|
|
threadReady = true;
|
|
System.out.println("# Started: " + name);
|
|
|
|
int i = 0;
|
|
int n = 1000;
|
|
while (!shouldFinish) {
|
|
if (n <= 0) {
|
|
n = 1000;
|
|
ToggleNotifyJvmtiTest.sleep(1);
|
|
}
|
|
if (i > n) {
|
|
i = 0;
|
|
n = n - 1;
|
|
}
|
|
i = i + 1;
|
|
}
|
|
}
|
|
|
|
// ensure thread is ready
|
|
public void ensureReady() {
|
|
while (!threadReady) {
|
|
ToggleNotifyJvmtiTest.sleep(1);
|
|
}
|
|
}
|
|
|
|
public void letFinish() {
|
|
shouldFinish = true;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The testing scenario consists of a number of serialized test cycles.
|
|
* Each cycle has initially zero virtual threads and the following steps:
|
|
* - disable notifyJvmti events mode
|
|
* - start N virtual threads
|
|
* - enable notifyJvmti events mode
|
|
* - shut the virtual threads down
|
|
* The JVMTI agent is loaded at a start-up or at a dynamic attach.
|
|
* It collects events:
|
|
* - VirtualThreadStart, VirtualThreadEnd, ThreadStart and ThreadEnd
|
|
*/
|
|
public class ToggleNotifyJvmtiTest {
|
|
private static final int VTHREADS_CNT = 20;
|
|
private static final String AGENT_LIB = "ToggleNotifyJvmtiTest";
|
|
private static final WhiteBox WB = WhiteBox.getWhiteBox();
|
|
|
|
private static native boolean IsAgentStarted();
|
|
private static native int VirtualThreadStartedCount();
|
|
private static native int VirtualThreadEndedCount();
|
|
private static native int ThreadStartedCount();
|
|
private static native int ThreadEndedCount();
|
|
|
|
static void log(String str) { System.out.println(str); }
|
|
|
|
static public void sleep(long millis) {
|
|
try {
|
|
Thread.sleep(millis);
|
|
} catch (InterruptedException e) {
|
|
throw new RuntimeException("Interruption in TestTask.sleep: \n\t" + e);
|
|
}
|
|
}
|
|
|
|
static TestTask[] tasks = new TestTask[VTHREADS_CNT];
|
|
static Thread vthreads[] = new Thread[VTHREADS_CNT];
|
|
|
|
static private void startVirtualThreads() {
|
|
log("\n# Java: Starting vthreads");
|
|
for (int i = 0; i < VTHREADS_CNT; i++) {
|
|
String name = "TestTask" + i;
|
|
TestTask task = new TestTask(name);
|
|
vthreads[i] = Thread.ofVirtual().name(name).start(task);
|
|
tasks[i] = task;
|
|
}
|
|
}
|
|
|
|
static private void finishVirtualThreads() {
|
|
try {
|
|
for (int i = 0; i < VTHREADS_CNT; i++) {
|
|
tasks[i].ensureReady();
|
|
tasks[i].letFinish();
|
|
vthreads[i].join();
|
|
}
|
|
} catch (InterruptedException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
static private void setVirtualThreadsNotifyJvmtiMode(int iter, boolean enable) {
|
|
boolean status = WB.setVirtualThreadsNotifyJvmtiMode(enable);
|
|
if (!status) {
|
|
throw new RuntimeException("Java: failed to set VirtualThreadsNotifyJvmtiMode: " + enable);
|
|
}
|
|
log("\n# main: SetNotifyJvmtiEvents: #" + iter + " enable: " + enable);
|
|
}
|
|
|
|
// Accumulative results after each finished test cycle.
|
|
static private void printResults() {
|
|
log(" VirtualThreadStart events: " + VirtualThreadStartedCount());
|
|
log(" VirtualThreadEnd events: " + VirtualThreadEndedCount());
|
|
log(" ThreadStart events: " + ThreadStartedCount());
|
|
log(" ThreadEnd events: " + ThreadEndedCount());
|
|
}
|
|
|
|
static private void run_test_cycle(int iter) throws Exception {
|
|
log("\n# Java: Started test cycle #" + iter);
|
|
|
|
// Disable notifyJvmti events mode at test cycle start.
|
|
// It is unsafe to do so if any virtual threads are executed.
|
|
setVirtualThreadsNotifyJvmtiMode(iter, false);
|
|
|
|
startVirtualThreads();
|
|
|
|
// We want this somewhere in the middle of virtual threads execution.
|
|
setVirtualThreadsNotifyJvmtiMode(iter, true);
|
|
|
|
finishVirtualThreads();
|
|
|
|
log("\n# Java: Finished test cycle #" + iter);
|
|
printResults();
|
|
}
|
|
|
|
public static void main(String[] args) throws Exception {
|
|
log("# main: loading " + AGENT_LIB + " lib");
|
|
|
|
if (args.length > 0 && args[0].equals("attach")) { // agent loaded into running VM case
|
|
String arg = args.length == 2 ? args[1] : "";
|
|
VirtualMachine vm = VirtualMachine.attach(String.valueOf(ProcessHandle.current().pid()));
|
|
vm.loadAgentLibrary(AGENT_LIB, arg);
|
|
}
|
|
int waitCount = 0;
|
|
while (!IsAgentStarted()) {
|
|
log("# main: waiting for native agent to start: #" + waitCount++);
|
|
sleep(20);
|
|
}
|
|
|
|
// The testing scenario consists of a number of sequential testing cycles.
|
|
for (int iter = 0; iter < 10; iter++) {
|
|
run_test_cycle(iter);
|
|
}
|
|
}
|
|
}
|