mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
8304839: Move TestScaffold.main() to the separate class DebugeeWrapper
Reviewed-by: amenkov, cjplummer
This commit is contained in:
parent
36ac83904c
commit
ee9776fa23
19 changed files with 158 additions and 121 deletions
|
@ -50,12 +50,12 @@ class ClassesByName2Targ {
|
||||||
System.out.println("Howdy!");
|
System.out.println("Howdy!");
|
||||||
try {
|
try {
|
||||||
|
|
||||||
Thread zero = TestScaffold.newThread (() -> {
|
Thread zero = DebuggeeWrapper.newThread (() -> {
|
||||||
System.setProperty("java.awt.headless", "true");
|
System.setProperty("java.awt.headless", "true");
|
||||||
java.awt.Toolkit tk = java.awt.Toolkit.getDefaultToolkit();
|
java.awt.Toolkit tk = java.awt.Toolkit.getDefaultToolkit();
|
||||||
}, "ZERO");
|
}, "ZERO");
|
||||||
|
|
||||||
Thread one = TestScaffold.newThread (() -> {
|
Thread one = DebuggeeWrapper.newThread (() -> {
|
||||||
try {
|
try {
|
||||||
java.security.KeyPairGenerator keyGen =
|
java.security.KeyPairGenerator keyGen =
|
||||||
java.security.KeyPairGenerator.getInstance("DSA", "SUN");
|
java.security.KeyPairGenerator.getInstance("DSA", "SUN");
|
||||||
|
@ -64,7 +64,7 @@ class ClassesByName2Targ {
|
||||||
}
|
}
|
||||||
}, "ONE");
|
}, "ONE");
|
||||||
|
|
||||||
Thread two = TestScaffold.newThread (() -> {
|
Thread two = DebuggeeWrapper.newThread (() -> {
|
||||||
try {
|
try {
|
||||||
String s = String.format("%02x", 0xff);
|
String s = String.format("%02x", 0xff);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
123
test/jdk/com/sun/jdi/DebuggeeWrapper.java
Normal file
123
test/jdk/com/sun/jdi/DebuggeeWrapper.java
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
|
||||||
|
public class DebuggeeWrapper {
|
||||||
|
|
||||||
|
public static String PROPERTY_NAME = "main.wrapper";
|
||||||
|
|
||||||
|
private static final String OLD_MAIN_THREAD_NAME = "old-m-a-i-n";
|
||||||
|
|
||||||
|
private static ThreadFactory threadFactory = r -> new Thread(r);
|
||||||
|
|
||||||
|
private static final String wrapperName = System.getProperty(PROPERTY_NAME);
|
||||||
|
|
||||||
|
public static String getWrapperName() {
|
||||||
|
return wrapperName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isVirtual() {
|
||||||
|
return "Virtual".equals(wrapperName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Thread newThread(Runnable task) {
|
||||||
|
return threadFactory.newThread(task);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Thread newThread(Runnable task, String name) {
|
||||||
|
Thread t = newThread(task);
|
||||||
|
t.setName(name);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Throwable {
|
||||||
|
String className = args[0];
|
||||||
|
String[] classArgs = new String[args.length - 1];
|
||||||
|
System.arraycopy(args, 1, classArgs, 0, args.length - 1);
|
||||||
|
Class c = Class.forName(className);
|
||||||
|
java.lang.reflect.Method mainMethod = c.getMethod("main", new Class[] { String[].class });
|
||||||
|
mainMethod.setAccessible(true);
|
||||||
|
|
||||||
|
if (isVirtual()) {
|
||||||
|
threadFactory = Thread.ofVirtual().factory();
|
||||||
|
MainThreadGroup tg = new MainThreadGroup();
|
||||||
|
Thread vthread = Thread.ofVirtual().unstarted(() -> {
|
||||||
|
try {
|
||||||
|
mainMethod.invoke(null, new Object[] { classArgs });
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
tg.uncaughtThrowable = e.getCause();
|
||||||
|
} catch (Throwable error) {
|
||||||
|
tg.uncaughtThrowable = error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Thread.currentThread().setName(OLD_MAIN_THREAD_NAME);
|
||||||
|
vthread.setName("main");
|
||||||
|
vthread.start();
|
||||||
|
vthread.join();
|
||||||
|
if (tg.uncaughtThrowable != null) {
|
||||||
|
// Note we cant just rethrow tg.uncaughtThrowable because there are tests
|
||||||
|
// that track ExceptionEvents, and they will complain about the extra
|
||||||
|
// exception. So instead mimic what happens when the main thread exits
|
||||||
|
// with an exception.
|
||||||
|
System.out.println("Uncaught Exception: " + tg.uncaughtThrowable);
|
||||||
|
tg.uncaughtThrowable.printStackTrace(System.out);
|
||||||
|
System.exit(1);
|
||||||
|
}
|
||||||
|
} else if (getWrapperName().equals("Kernel")) {
|
||||||
|
MainThreadGroup tg = new MainThreadGroup();
|
||||||
|
Thread t = new Thread(tg, () -> {
|
||||||
|
try {
|
||||||
|
mainMethod.invoke(null, new Object[] { classArgs });
|
||||||
|
} catch (InvocationTargetException e) {
|
||||||
|
tg.uncaughtThrowable = e.getCause();
|
||||||
|
} catch (Throwable error) {
|
||||||
|
tg.uncaughtThrowable = error;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
t.start();
|
||||||
|
t.join();
|
||||||
|
if (tg.uncaughtThrowable != null) {
|
||||||
|
throw new RuntimeException(tg.uncaughtThrowable);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mainMethod.invoke(null, new Object[] { classArgs });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static class MainThreadGroup extends ThreadGroup {
|
||||||
|
MainThreadGroup() {
|
||||||
|
super("MainThreadGroup");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void uncaughtException(Thread t, Throwable e) {
|
||||||
|
if (e instanceof ThreadDeath) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
e.printStackTrace(System.err);
|
||||||
|
uncaughtThrowable = e;
|
||||||
|
}
|
||||||
|
Throwable uncaughtThrowable = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -74,8 +74,8 @@ class DeferredStepTestTarg {
|
||||||
|
|
||||||
jj1 obj1 = new jj1();
|
jj1 obj1 = new jj1();
|
||||||
jj2 obj2 = new jj2();
|
jj2 obj2 = new jj2();
|
||||||
Thread thread1 = TestScaffold.newThread(obj1, "jj1");
|
Thread thread1 = DebuggeeWrapper.newThread(obj1, "jj1");
|
||||||
Thread thread2 = TestScaffold.newThread(obj2, "jj2");
|
Thread thread2 = DebuggeeWrapper.newThread(obj2, "jj2");
|
||||||
thread1.start();
|
thread1.start();
|
||||||
thread2.start();
|
thread2.start();
|
||||||
// Threads might be deamon threads, so wait here for them to complete.
|
// Threads might be deamon threads, so wait here for them to complete.
|
||||||
|
|
|
@ -843,7 +843,7 @@ abstract class EATestCaseBaseTarget extends EATestCaseBaseShared implements Runn
|
||||||
public static void staticSetUp() {
|
public static void staticSetUp() {
|
||||||
inflatedLock = new XYVal(1, 1);
|
inflatedLock = new XYVal(1, 1);
|
||||||
synchronized (inflatedLock) {
|
synchronized (inflatedLock) {
|
||||||
inflatorThread = TestScaffold.newThread(() -> {
|
inflatorThread = DebuggeeWrapper.newThread(() -> {
|
||||||
synchronized (inflatedLock) {
|
synchronized (inflatedLock) {
|
||||||
inflatedLockIsPermanentlyInflated = true;
|
inflatedLockIsPermanentlyInflated = true;
|
||||||
inflatedLock.notify(); // main thread
|
inflatedLock.notify(); // main thread
|
||||||
|
|
|
@ -169,7 +169,7 @@ public class ForceEarlyReturnTest extends TestScaffold {
|
||||||
protected void runTests() throws Exception {
|
protected void runTests() throws Exception {
|
||||||
BreakpointEvent bpe = startTo("ForceEarlyReturnTestTarg", "loopOrSleep", "()V");
|
BreakpointEvent bpe = startTo("ForceEarlyReturnTestTarg", "loopOrSleep", "()V");
|
||||||
ThreadReference mainThread = bpe.thread();
|
ThreadReference mainThread = bpe.thread();
|
||||||
boolean is_vthread_mode = "Virtual".equals(System.getProperty("main.wrapper"));
|
boolean is_vthread_mode = DebuggeeWrapper.isVirtual();
|
||||||
|
|
||||||
// Resume main thread until it is in Thread.sleep() or the infinite loop.
|
// Resume main thread until it is in Thread.sleep() or the infinite loop.
|
||||||
mainThread.resume();
|
mainThread.resume();
|
||||||
|
|
|
@ -47,7 +47,7 @@ class InterruptHangTarg {
|
||||||
public static void main(String[] args){
|
public static void main(String[] args){
|
||||||
int answer = 0;
|
int answer = 0;
|
||||||
System.out.println("Howdy!");
|
System.out.println("Howdy!");
|
||||||
Thread interruptorThread = TestScaffold.newThread(new Interruptor(Thread.currentThread()));
|
Thread interruptorThread = DebuggeeWrapper.newThread(new Interruptor(Thread.currentThread()));
|
||||||
|
|
||||||
synchronized(sync) {
|
synchronized(sync) {
|
||||||
interruptorThread.start();
|
interruptorThread.start();
|
||||||
|
|
|
@ -54,8 +54,8 @@ class InvokeHangTarg implements Runnable {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
System.out.println("Howdy!");
|
System.out.println("Howdy!");
|
||||||
Thread t1 = TestScaffold.newThread(new InvokeHangTarg(), name1);
|
Thread t1 = DebuggeeWrapper.newThread(new InvokeHangTarg(), name1);
|
||||||
Thread t2 = TestScaffold.newThread(new InvokeHangTarg(), name2);
|
Thread t2 = DebuggeeWrapper.newThread(new InvokeHangTarg(), name2);
|
||||||
|
|
||||||
t1.start();
|
t1.start();
|
||||||
t2.start();
|
t2.start();
|
||||||
|
|
|
@ -39,7 +39,7 @@ class JdbLockTestTarg {
|
||||||
static String jj = "jj";
|
static String jj = "jj";
|
||||||
public static void main(String args[]) {
|
public static void main(String args[]) {
|
||||||
synchronized(jj) {
|
synchronized(jj) {
|
||||||
Thread xx = TestScaffold.newThread(new Sleeper());
|
Thread xx = DebuggeeWrapper.newThread(new Sleeper());
|
||||||
xx.start();
|
xx.start();
|
||||||
// Give the sleeper a chance to run and get to
|
// Give the sleeper a chance to run and get to
|
||||||
// the synchronized statement.
|
// the synchronized statement.
|
||||||
|
|
|
@ -51,9 +51,9 @@ class JdbStopThreadidTestTarg {
|
||||||
MyTask myTask1 = test.new MyTask();
|
MyTask myTask1 = test.new MyTask();
|
||||||
MyTask myTask2 = test.new MyTask();
|
MyTask myTask2 = test.new MyTask();
|
||||||
MyTask myTask3 = test.new MyTask();
|
MyTask myTask3 = test.new MyTask();
|
||||||
Thread myThread1 = TestScaffold.newThread(myTask1, "MYTHREAD-1");
|
Thread myThread1 = DebuggeeWrapper.newThread(myTask1, "MYTHREAD-1");
|
||||||
Thread myThread2 = TestScaffold.newThread(myTask2, "MYTHREAD-2");
|
Thread myThread2 = DebuggeeWrapper.newThread(myTask2, "MYTHREAD-2");
|
||||||
Thread myThread3 = TestScaffold.newThread(myTask3, "MYTHREAD-3");
|
Thread myThread3 = DebuggeeWrapper.newThread(myTask3, "MYTHREAD-3");
|
||||||
|
|
||||||
synchronized (lockObj) {
|
synchronized (lockObj) {
|
||||||
myThread1.start();
|
myThread1.start();
|
||||||
|
|
|
@ -61,7 +61,7 @@ class MonitorEventTestTarg {
|
||||||
endingMonitor = new Object();
|
endingMonitor = new Object();
|
||||||
startingMonitor = new Object();
|
startingMonitor = new Object();
|
||||||
|
|
||||||
Thread t1 = TestScaffold.newThread(new MyTask());
|
Thread t1 = DebuggeeWrapper.newThread(new MyTask());
|
||||||
foo();
|
foo();
|
||||||
aboutEnterLock = false;
|
aboutEnterLock = false;
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ class MultiBreakpointsTarg {
|
||||||
//
|
//
|
||||||
//final String threadName = "DebuggeeThread: " + num;
|
//final String threadName = "DebuggeeThread: " + num;
|
||||||
final String threadName = "" + num;
|
final String threadName = "" + num;
|
||||||
Thread thrd = TestScaffold.newThread(() -> {
|
Thread thrd = DebuggeeWrapper.newThread(() -> {
|
||||||
synchronized( isr ) {
|
synchronized( isr ) {
|
||||||
boolean done = false;
|
boolean done = false;
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -186,7 +186,7 @@ public class PopAsynchronousTest extends TestScaffold {
|
||||||
/*
|
/*
|
||||||
* start popping wildly away
|
* start popping wildly away
|
||||||
*/
|
*/
|
||||||
TestScaffold.newThread(new HarassThread()).start();
|
DebuggeeWrapper.newThread(new HarassThread()).start();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* resume the target listening for events
|
* resume the target listening for events
|
||||||
|
|
|
@ -318,8 +318,7 @@ public class PopFramesTest extends TestScaffold {
|
||||||
* works. So you have an unmounted virtual thread with no native frames, which
|
* works. So you have an unmounted virtual thread with no native frames, which
|
||||||
* results in OpaqueFrameException being thrown.
|
* results in OpaqueFrameException being thrown.
|
||||||
*/
|
*/
|
||||||
String mainWrapper = System.getProperty("main.wrapper");
|
if (DebuggeeWrapper.isVirtual()) {
|
||||||
if ("Virtual".equals(mainWrapper)) {
|
|
||||||
expected_exception = OpaqueFrameException.class;
|
expected_exception = OpaqueFrameException.class;
|
||||||
} else {
|
} else {
|
||||||
expected_exception = NativeMethodException.class;
|
expected_exception = NativeMethodException.class;
|
||||||
|
|
|
@ -43,8 +43,8 @@ class ResumeOneThreadTarg implements Runnable {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
System.out.println(" Debuggee: Howdy!");
|
System.out.println(" Debuggee: Howdy!");
|
||||||
Thread t1 = TestScaffold.newThread(new ResumeOneThreadTarg(), name1);
|
Thread t1 = DebuggeeWrapper.newThread(new ResumeOneThreadTarg(), name1);
|
||||||
Thread t2 = TestScaffold.newThread(new ResumeOneThreadTarg(), name2);
|
Thread t2 = DebuggeeWrapper.newThread(new ResumeOneThreadTarg(), name2);
|
||||||
t1.start();
|
t1.start();
|
||||||
t2.start();
|
t2.start();
|
||||||
// We must block until these threads exit. Otherwise for virtual threads
|
// We must block until these threads exit. Otherwise for virtual threads
|
||||||
|
|
|
@ -174,7 +174,7 @@ public class SetLocalWhileThreadInNative extends TestScaffold {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
boolean isVirtualThread = "Virtual".equals(System.getProperty("main.wrapper"));
|
boolean isVirtualThread = DebuggeeWrapper.isVirtual();
|
||||||
Asserts.assertTrue(caughtOFE == isVirtualThread);
|
Asserts.assertTrue(caughtOFE == isVirtualThread);
|
||||||
Asserts.assertTrue(changedLocal == !isVirtualThread);
|
Asserts.assertTrue(changedLocal == !isVirtualThread);
|
||||||
|
|
||||||
|
|
|
@ -50,8 +50,8 @@ class SimulResumerTarg implements Runnable {
|
||||||
static int count = 10000;
|
static int count = 10000;
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
System.out.println("Howdy!");
|
System.out.println("Howdy!");
|
||||||
Thread t1 = TestScaffold.newThread(new SimulResumerTarg(), name1);
|
Thread t1 = DebuggeeWrapper.newThread(new SimulResumerTarg(), name1);
|
||||||
Thread t2 = TestScaffold.newThread(new SimulResumerTarg(), name2);
|
Thread t2 = DebuggeeWrapper.newThread(new SimulResumerTarg(), name2);
|
||||||
|
|
||||||
t1.start();
|
t1.start();
|
||||||
t2.start();
|
t2.start();
|
||||||
|
|
|
@ -24,10 +24,9 @@
|
||||||
import com.sun.jdi.*;
|
import com.sun.jdi.*;
|
||||||
import com.sun.jdi.request.*;
|
import com.sun.jdi.request.*;
|
||||||
import com.sun.jdi.event.*;
|
import com.sun.jdi.event.*;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.util.concurrent.ThreadFactory;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Framework used by all JDI regression tests
|
* Framework used by all JDI regression tests
|
||||||
|
@ -67,7 +66,6 @@ abstract public class TestScaffold extends TargetAdapter {
|
||||||
final String[] args;
|
final String[] args;
|
||||||
protected boolean testFailed = false;
|
protected boolean testFailed = false;
|
||||||
protected long startTime;
|
protected long startTime;
|
||||||
public static final String OLD_MAIN_THREAD_NAME = "old-m-a-i-n";
|
|
||||||
|
|
||||||
static private class ArgInfo {
|
static private class ArgInfo {
|
||||||
String targetVMArgs = "";
|
String targetVMArgs = "";
|
||||||
|
@ -513,8 +511,8 @@ abstract public class TestScaffold extends TargetAdapter {
|
||||||
// argInfo.targetAppCommandLine : Frames2Targ
|
// argInfo.targetAppCommandLine : Frames2Targ
|
||||||
// argInfo.targetVMArgs : -Xss4M
|
// argInfo.targetVMArgs : -Xss4M
|
||||||
// The result with wrapper enabled:
|
// The result with wrapper enabled:
|
||||||
// argInfo.targetAppCommandLine : TestScaffold Virtual Frames2Targ
|
// argInfo.targetAppCommandLine : DebuggeeWrapper Frames2Targ
|
||||||
// argInfo.targetVMArgs : -Xss4M
|
// argInfo.targetVMArgs : -Xss4M -Dmain.wrapper=Virtual
|
||||||
boolean classNameParsed = false;
|
boolean classNameParsed = false;
|
||||||
for (int i = 0; i < args.length; i++) {
|
for (int i = 0; i < args.length; i++) {
|
||||||
String arg = args[i].trim();
|
String arg = args[i].trim();
|
||||||
|
@ -549,12 +547,12 @@ abstract public class TestScaffold extends TargetAdapter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to change args to run wrapper using command like 'TestScaffold Virtual <app-name>'
|
// Need to change args to run wrapper using command like 'DebuggeeWrapper <app-name>'
|
||||||
String mainWrapper = System.getProperty("main.wrapper");
|
// and set property 'main.wrapper' so test could use DebuggeeWrapper.isVirtual() method
|
||||||
|
String mainWrapper = DebuggeeWrapper.getWrapperName();
|
||||||
if (mainWrapper != null && !argInfo.targetAppCommandLine.isEmpty()) {
|
if (mainWrapper != null && !argInfo.targetAppCommandLine.isEmpty()) {
|
||||||
argInfo.targetVMArgs += "-Dmain.wrapper=" + mainWrapper;
|
argInfo.targetVMArgs += "-D" + DebuggeeWrapper.PROPERTY_NAME + "=" + mainWrapper;
|
||||||
argInfo.targetAppCommandLine = TestScaffold.class.getName() + ' '
|
argInfo.targetAppCommandLine = DebuggeeWrapper.class.getName() + ' ' + argInfo.targetAppCommandLine;
|
||||||
+ mainWrapper + ' ' + argInfo.targetAppCommandLine;
|
|
||||||
} else if ("true".equals(System.getProperty("test.enable.preview"))) {
|
} else if ("true".equals(System.getProperty("test.enable.preview"))) {
|
||||||
// the test specified @enablePreview.
|
// the test specified @enablePreview.
|
||||||
argInfo.targetVMArgs += "--enable-preview ";
|
argInfo.targetVMArgs += "--enable-preview ";
|
||||||
|
@ -1044,86 +1042,4 @@ abstract public class TestScaffold extends TargetAdapter {
|
||||||
vmDisconnected = true;
|
vmDisconnected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ThreadFactory threadFactory = r -> new Thread(r);
|
|
||||||
|
|
||||||
public static void main(String[] args) throws Throwable {
|
|
||||||
String wrapper = args[0];
|
|
||||||
String className = args[1];
|
|
||||||
String[] classArgs = new String[args.length - 2];
|
|
||||||
System.arraycopy(args, 2, classArgs, 0, args.length - 2);
|
|
||||||
Class c = Class.forName(className);
|
|
||||||
java.lang.reflect.Method mainMethod = c.getMethod("main", new Class[] { String[].class });
|
|
||||||
mainMethod.setAccessible(true);
|
|
||||||
|
|
||||||
if (wrapper.equals("Virtual")) {
|
|
||||||
threadFactory = Thread.ofVirtual().factory();
|
|
||||||
MainThreadGroup tg = new MainThreadGroup();
|
|
||||||
// TODO fix to set virtual scheduler group when become available
|
|
||||||
Thread vthread = Thread.ofVirtual().unstarted(() -> {
|
|
||||||
try {
|
|
||||||
mainMethod.invoke(null, new Object[] { classArgs });
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
tg.uncaughtThrowable = e.getCause();
|
|
||||||
} catch (Throwable error) {
|
|
||||||
tg.uncaughtThrowable = error;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Thread.currentThread().setName(OLD_MAIN_THREAD_NAME);
|
|
||||||
vthread.setName("main");
|
|
||||||
vthread.start();
|
|
||||||
vthread.join();
|
|
||||||
if (tg.uncaughtThrowable != null) {
|
|
||||||
// Note we cant just rethrow tg.uncaughtThrowable because there are tests
|
|
||||||
// that track ExceptionEvents, and they will complain about the extra
|
|
||||||
// exception. So instead mimic what happens when the main thread exits
|
|
||||||
// with an exception.
|
|
||||||
System.out.println("Uncaught Exception: " + tg.uncaughtThrowable);
|
|
||||||
tg.uncaughtThrowable.printStackTrace(System.out);
|
|
||||||
System.exit(1);
|
|
||||||
}
|
|
||||||
} else if (wrapper.equals("Kernel")) {
|
|
||||||
MainThreadGroup tg = new MainThreadGroup();
|
|
||||||
Thread t = new Thread(tg, () -> {
|
|
||||||
try {
|
|
||||||
mainMethod.invoke(null, new Object[] { classArgs });
|
|
||||||
} catch (InvocationTargetException e) {
|
|
||||||
tg.uncaughtThrowable = e.getCause();
|
|
||||||
} catch (Throwable error) {
|
|
||||||
tg.uncaughtThrowable = error;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
t.start();
|
|
||||||
t.join();
|
|
||||||
if (tg.uncaughtThrowable != null) {
|
|
||||||
throw new RuntimeException(tg.uncaughtThrowable);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mainMethod.invoke(null, new Object[] { classArgs });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class MainThreadGroup extends ThreadGroup {
|
|
||||||
MainThreadGroup() {
|
|
||||||
super("MainThreadGroup");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void uncaughtException(Thread t, Throwable e) {
|
|
||||||
if (e instanceof ThreadDeath) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
e.printStackTrace(System.err);
|
|
||||||
uncaughtThrowable = e;
|
|
||||||
}
|
|
||||||
Throwable uncaughtThrowable = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Thread newThread(Runnable task) {
|
|
||||||
return threadFactory.newThread(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Thread newThread(Runnable task, String name) {
|
|
||||||
Thread t = newThread(task);
|
|
||||||
t.setName(name);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,19 +58,18 @@ class ThreadMemoryLeakTarg {
|
||||||
while (System.currentTimeMillis() - startTime < 100 * 1000) {
|
while (System.currentTimeMillis() - startTime < 100 * 1000) {
|
||||||
iterations++;
|
iterations++;
|
||||||
semaphore.acquire();
|
semaphore.acquire();
|
||||||
TestScaffold.newThread(() -> {
|
DebuggeeWrapper.newThread(() -> {
|
||||||
adder.increment();
|
adder.increment();
|
||||||
long sum = adder.sum();
|
long sum = adder.sum();
|
||||||
if ((sum % 1000) == 0) {
|
if ((sum % 1000) == 0) {
|
||||||
System.out.println("Progress: " + sum);
|
System.out.println("Progress: " + sum);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
String mainWrapper = System.getProperty("main.wrapper");
|
|
||||||
// Virtual thread creation tends to overwhelm the debugger,
|
// Virtual thread creation tends to overwhelm the debugger,
|
||||||
// leading to high memory use for all the unprocessed events
|
// leading to high memory use for all the unprocessed events
|
||||||
// that get queued up, so we need to slow it down a bit more
|
// that get queued up, so we need to slow it down a bit more
|
||||||
// than we do for platform threads to avoid getting OOME.
|
// than we do for platform threads to avoid getting OOME.
|
||||||
long timeToSleep = "Virtual".equals(mainWrapper) ? 100 : 50;
|
long timeToSleep = DebuggeeWrapper.isVirtual() ? 100 : 50;
|
||||||
Thread.sleep(timeToSleep);
|
Thread.sleep(timeToSleep);
|
||||||
}
|
}
|
||||||
catch (InterruptedException e) {
|
catch (InterruptedException e) {
|
||||||
|
|
|
@ -50,8 +50,8 @@ class TwoThreadsTarg implements Runnable {
|
||||||
|
|
||||||
public static void main(String[] args) {
|
public static void main(String[] args) {
|
||||||
System.out.println("Howdy!");
|
System.out.println("Howdy!");
|
||||||
Thread t1 = TestScaffold.newThread(new TwoThreadsTarg(), name1);
|
Thread t1 = DebuggeeWrapper.newThread(new TwoThreadsTarg(), name1);
|
||||||
Thread t2 = TestScaffold.newThread(new TwoThreadsTarg(), name2);
|
Thread t2 = DebuggeeWrapper.newThread(new TwoThreadsTarg(), name2);
|
||||||
|
|
||||||
t1.start();
|
t1.start();
|
||||||
t2.start();
|
t2.start();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue