8306471: Add virtual threads support to JDWP ThreadReference.Stop and JDI ThreadReference.stop()
Reviewed-by: sspitsyn, alanb
This commit is contained in:
parent
4441a2306f
commit
d809823fe4
@ -2004,10 +2004,11 @@ JDWP "Java(tm) Debug Wire Protocol"
|
||||
(Command Stop=10
|
||||
"Stops the thread with an asynchronous exception. "
|
||||
"<p>"
|
||||
"The target VM may not support, or may only provide limited support, for "
|
||||
"this command when the thread is a virtual thread. It may, for example, "
|
||||
"only support this command when the virtual thread is suspended at a "
|
||||
"breakpoint or singlestep event."
|
||||
"This command may be used to send an asynchronous "
|
||||
"exception to a virtual thread when it is suspended at an event. "
|
||||
"An implementation may support sending an asynchronous exception "
|
||||
"to a suspended virtual thread in other cases."
|
||||
|
||||
(Out
|
||||
(threadObject thread "The thread object ID. ")
|
||||
(object throwable "Asynchronous exception. This object must "
|
||||
@ -2018,8 +2019,10 @@ JDWP "Java(tm) Debug Wire Protocol"
|
||||
(ErrorSet
|
||||
(Error INVALID_THREAD "The thread is null, not a valid thread, or the thread "
|
||||
"is not alive.")
|
||||
(Error NOT_IMPLEMENTED "The thread is a virtual thread and the target "
|
||||
"VM does not support the command on virtual threads.")
|
||||
(Error THREAD_NOT_SUSPENDED "The thread is a virtual thread and was not suspended.")
|
||||
(Error OPAQUE_FRAME "The thread is a suspended virtual thread and the implementation "
|
||||
"was unable to throw an asynchronous exception "
|
||||
"from the thread's current frame.")
|
||||
(Error INVALID_OBJECT "If thread is not a known ID or the asynchronous "
|
||||
"exception has been garbage collected.")
|
||||
(Error VM_DEAD)
|
||||
@ -3166,7 +3169,7 @@ JDWP "Java(tm) Debug Wire Protocol"
|
||||
"call stack.")
|
||||
(Constant OPAQUE_FRAME =32 "Information about the frame is not available "
|
||||
"(e.g. native frame) or the target VM is unable "
|
||||
"to perform an operation on the frame.")
|
||||
"to perform an operation on the thread's current frame.")
|
||||
(Constant NOT_CURRENT_FRAME =33 "Operation can only be performed on current frame.")
|
||||
(Constant TYPE_MISMATCH =34 "The variable is not an appropriate type for "
|
||||
"the function used.")
|
||||
|
@ -116,18 +116,20 @@ public interface ThreadReference extends ObjectReference {
|
||||
* A debugger thread in the target VM will stop this thread
|
||||
* with the given {@link java.lang.Throwable} object.
|
||||
* <p>
|
||||
* The target VM may not support, or may only provide limited support,
|
||||
* for stopping a virtual thread with an asynchronous exception. It may,
|
||||
* for example, only support this operation when the virtual thread is
|
||||
* suspended at a breakpoint or singlestep event.
|
||||
* This method may be used to send an asynchronous
|
||||
* exception to a virtual thread when it is suspended at an event.
|
||||
* An implementation may support sending an asynchronous exception
|
||||
* to a suspended virtual thread in other cases.
|
||||
|
||||
*
|
||||
* @param throwable the asynchronous exception to throw
|
||||
* @throws InvalidTypeException if <code>throwable</code> is not
|
||||
* an instance of java.lang.Throwable in the target VM
|
||||
* @throws IllegalThreadStateException if the thread has terminated
|
||||
* @throws UnsupportedOperationException if the thread is a virtual
|
||||
* thread and the target VM does not support this operation on
|
||||
* virtual threads
|
||||
* @throws IllegalThreadStateException if the thread has terminated,
|
||||
* or if the thread is a virtual thread and was not suspended
|
||||
* @throws OpaqueFrameException if the thread is a suspended
|
||||
* virtual thread and the implementation was unable to throw an
|
||||
* asynchronous exception from the thread's current frame
|
||||
* @throws VMCannotBeModifiedException if the VirtualMachine is read-only
|
||||
* @see VirtualMachine#canBeModified()
|
||||
*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 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
|
||||
@ -719,9 +719,13 @@ class Commands {
|
||||
} catch (InvalidTypeException e) {
|
||||
MessageOutput.println("Invalid exception object");
|
||||
} catch (IllegalThreadStateException its) {
|
||||
MessageOutput.println("Illegal thread state");
|
||||
} catch (UnsupportedOperationException uoe) {
|
||||
MessageOutput.println("Operation is not supported on the target VM");
|
||||
if (!thread.isSuspended() && thread.isVirtual()) {
|
||||
MessageOutput.println("Illegal thread state (virtual thread not suspended)");
|
||||
} else {
|
||||
MessageOutput.println("Illegal thread state");
|
||||
}
|
||||
} catch (OpaqueFrameException ope) {
|
||||
MessageOutput.println("Operation is not supported on the current frame");
|
||||
}
|
||||
} else {
|
||||
MessageOutput.println("Expression must evaluate to an object");
|
||||
|
@ -142,6 +142,7 @@ public class TTYResources extends java.util.ListResourceBundle {
|
||||
{"Illegal Argument Exception", "Illegal Argument Exception"},
|
||||
{"Illegal connector argument", "Illegal connector argument: {0}"},
|
||||
{"Illegal thread state", "Illegal thread state"},
|
||||
{"Illegal thread state (virtual thread not suspended)", "Illegal thread state (virtual thread not suspended)"},
|
||||
{"implementor:", "implementor: {0}"},
|
||||
{"implements:", "implements: {0}"},
|
||||
{"Initializing progname", "Initializing {0} ..."},
|
||||
@ -244,7 +245,7 @@ public class TTYResources extends java.util.ListResourceBundle {
|
||||
{"Not waiting for a monitor", " Not waiting for a monitor"},
|
||||
{"Nothing suspended.", "Nothing suspended."},
|
||||
{"object description and id", "({0}){1}"},
|
||||
{"Operation is not supported on the target VM", "Operation is not supported on the target VM"},
|
||||
{"Operation is not supported on the current frame", "Operation is not supported on the current frame"},
|
||||
{"operation not yet supported", "operation not yet supported"},
|
||||
{"Owned by:", " Owned by: {0}, entry count: {1,number,integer}"},
|
||||
{"Owned monitor:", " Owned monitor: {0}"},
|
||||
|
@ -273,7 +273,18 @@ public class ThreadReferenceImpl extends ObjectReferenceImpl
|
||||
JDWP.ThreadReference.Stop.process(vm, this,
|
||||
(ObjectReferenceImpl)throwable);
|
||||
} catch (JDWPException exc) {
|
||||
throw exc.toJDIException();
|
||||
switch (exc.errorCode()) {
|
||||
case JDWP.Error.OPAQUE_FRAME:
|
||||
assert isVirtual(); // can only happen with virtual threads
|
||||
throw new OpaqueFrameException();
|
||||
case JDWP.Error.THREAD_NOT_SUSPENDED:
|
||||
assert isVirtual(); // can only happen with virtual threads
|
||||
throw new IllegalThreadStateException("virtual thread not suspended");
|
||||
case JDWP.Error.INVALID_THREAD:
|
||||
throw new IllegalThreadStateException("thread has terminated");
|
||||
default:
|
||||
throw exc.toJDIException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -35,16 +35,21 @@ import nsk.share.jpda.*;
|
||||
import nsk.share.jdi.*;
|
||||
|
||||
/**
|
||||
* The test checks that the JDI method:<br>
|
||||
* <code>com.sun.jdi.ThreadReference.stop()</code><br>
|
||||
* properly throws <i>InvalidTypeException</i> - if specified
|
||||
* throwable is not an instance of java.lang.Throwable in the
|
||||
* target VM.<p>
|
||||
* The test checks that the JDI method:<br><code>com.sun.jdi.ThreadReference.stop()</code><br>
|
||||
* behaves properly in various situations. It consists of 5 subtests.
|
||||
*
|
||||
* Debugger part of the test tries to stop debuggee thread
|
||||
* through the JDI method using as a parameter an object
|
||||
* reference of the main debuggee class <i>stop002t</i> itself
|
||||
* which is not <code>Throwable</code>.
|
||||
* TEST #1: Tests that stop() properly throws <i>InvalidTypeException</i> if
|
||||
* specified throwable is not an instance of java.lang.Throwable in the target VM.<p>
|
||||
*
|
||||
* TEST #2: Verify that stop() works when suspended at a breakpoint.
|
||||
*
|
||||
* TEST #3: Verify that stop() works when not suspended in a loop. For virtual threads
|
||||
* we expect an IncompatibleThreadStateException.
|
||||
*
|
||||
* TEST #4: Verify that stop() works when suspended in a loop.
|
||||
*
|
||||
* TEST #5: Verify that stop() works when suspended in Thread.sleep(). For virtual
|
||||
* threads we expect an OpaqueFrameException.
|
||||
*/
|
||||
public class stop002 {
|
||||
static final String DEBUGGEE_CLASS =
|
||||
@ -54,12 +59,15 @@ public class stop002 {
|
||||
static final String DEBUGGEE_THRNAME = "stop002tThr";
|
||||
|
||||
// debuggee local var used to find needed non-throwable object
|
||||
static final String DEBUGGEE_LOCALVAR = "stop002tNonThrowable";
|
||||
// debuggee field used to indicate that testing is over
|
||||
static final String DEBUGGEE_FIELD = "stopLooping";
|
||||
static final String DEBUGGEE_NON_THROWABLE_VAR= "stop002tNonThrowable";
|
||||
// debuggee local var used to find needed throwable object
|
||||
static final String DEBUGGEE_THROWABLE_VAR = "stop002tThrowable";
|
||||
// debuggee fields used to indicate to exit infinite loops
|
||||
static final String DEBUGGEE_STOP_LOOP1_FIELD = "stopLooping1";
|
||||
static final String DEBUGGEE_STOP_LOOP2_FIELD = "stopLooping2";
|
||||
|
||||
// debuggee source line where it should be stopped
|
||||
static final int DEBUGGEE_STOPATLINE = 69;
|
||||
static final int DEBUGGEE_STOPATLINE = 88;
|
||||
|
||||
static final int DELAY = 500; // in milliseconds
|
||||
|
||||
@ -67,12 +75,15 @@ public class stop002 {
|
||||
static final String COMMAND_GO = "go";
|
||||
static final String COMMAND_QUIT = "quit";
|
||||
|
||||
static final boolean vthreadMode = "Virtual".equals(System.getProperty("main.wrapper"));
|
||||
|
||||
private ArgumentHandler argHandler;
|
||||
private Log log;
|
||||
private IOPipe pipe;
|
||||
private Debugee debuggee;
|
||||
private VirtualMachine vm;
|
||||
private BreakpointRequest BPreq;
|
||||
private ReferenceType mainClass;
|
||||
private volatile int tot_res = Consts.TEST_PASSED;
|
||||
private volatile boolean gotEvent = false;
|
||||
|
||||
@ -101,68 +112,180 @@ public class stop002 {
|
||||
return quitDebuggee();
|
||||
}
|
||||
|
||||
ThreadReference thrRef = null;
|
||||
if ((thrRef =
|
||||
debuggee.threadByName(DEBUGGEE_THRNAME)) == null) {
|
||||
ThreadReference thrRef = debuggee.threadByName(DEBUGGEE_THRNAME);
|
||||
if (thrRef == null) {
|
||||
log.complain("TEST FAILURE: method Debugee.threadByName() returned null for debuggee thread "
|
||||
+ DEBUGGEE_THRNAME);
|
||||
tot_res = Consts.TEST_FAILED;
|
||||
return quitDebuggee();
|
||||
}
|
||||
|
||||
Field doExit = null;
|
||||
Field stopLoop1 = null;
|
||||
Field stopLoop2 = null;
|
||||
ObjectReference objRef = null;
|
||||
ObjectReference throwableRef = null;
|
||||
try {
|
||||
// debuggee main class
|
||||
ReferenceType rType = debuggee.classByName(DEBUGGEE_CLASS);
|
||||
mainClass = debuggee.classByName(DEBUGGEE_CLASS);
|
||||
|
||||
suspendAtBP(rType, DEBUGGEE_STOPATLINE);
|
||||
objRef = findObjRef(thrRef, DEBUGGEE_LOCALVAR);
|
||||
suspendAtBP(mainClass, DEBUGGEE_STOPATLINE);
|
||||
objRef = findObjRef(thrRef, DEBUGGEE_NON_THROWABLE_VAR);
|
||||
throwableRef = findObjRef(thrRef, DEBUGGEE_THROWABLE_VAR);
|
||||
|
||||
// this field is used to indicate that debuggee has to
|
||||
// stop looping
|
||||
doExit = rType.fieldByName(DEBUGGEE_FIELD);
|
||||
|
||||
log.display("Resuming debuggee VM ...");
|
||||
vm.resume();
|
||||
log.display("Resumption of debuggee VM done");
|
||||
|
||||
log.display("\nTrying to stop debuggee thread \"" + thrRef
|
||||
+ "\"\n\tusing non-throwable object reference \""
|
||||
+ objRef + "\" as a parameter ...");
|
||||
|
||||
// Check the tested assersion
|
||||
try {
|
||||
thrRef.stop(objRef);
|
||||
log.complain("TEST FAILED: expected IllegalArgumentException was not thrown"
|
||||
+ "\n\twhen attempted to stop debuggee thread \"" + thrRef
|
||||
+ "\"\n\tusing non-throwable object reference \""
|
||||
+ objRef + "\" as a parameter");
|
||||
tot_res = Consts.TEST_FAILED;
|
||||
} catch(InvalidTypeException ee) {
|
||||
log.display("CHECK PASSED: caught expected " + ee);
|
||||
} catch(Exception ue) {
|
||||
ue.printStackTrace();
|
||||
log.complain("TEST FAILED: ThreadReference.stop(): caught unexpected "
|
||||
+ ue + "\n\tinstead of InvalidTypeException"
|
||||
+ "\n\twhen attempted to stop debuggee thread \"" + thrRef
|
||||
+ "\"\n\tusing non-throwable object reference \""
|
||||
+ objRef + "\" as a parameter");
|
||||
tot_res = Consts.TEST_FAILED;
|
||||
// These fields are used to indicate that debuggee has to stop looping
|
||||
stopLoop1 = mainClass.fieldByName(DEBUGGEE_STOP_LOOP1_FIELD);
|
||||
stopLoop2 = mainClass.fieldByName(DEBUGGEE_STOP_LOOP2_FIELD);
|
||||
if (stopLoop1 == null || stopLoop2 == null) {
|
||||
throw new RuntimeException("Failed to find a \"stop loop\" field");
|
||||
}
|
||||
|
||||
log.display("non-throwable object: \"" + objRef + "\"");
|
||||
log.display("throwable object: \"" + throwableRef + "\"");
|
||||
log.display("debuggee thread: \"" + thrRef + "\"");
|
||||
|
||||
/*
|
||||
* Test #1: verify using a non-throwable object with stop() fails appropriately.
|
||||
*/
|
||||
log.display("\nTEST #1: Trying to stop debuggee thread using non-throwable object.");
|
||||
try {
|
||||
thrRef.stop(objRef); // objRef is an instance of the debuggee class, not a Throwable
|
||||
log.complain("TEST #1 FAILED: expected InvalidTypeException was not thrown");
|
||||
tot_res = Consts.TEST_FAILED;
|
||||
} catch (InvalidTypeException ee) {
|
||||
log.display("TEST #1 PASSED: caught expected " + ee);
|
||||
} catch (Exception ue) {
|
||||
ue.printStackTrace();
|
||||
log.complain("TEST #1 FAILED: caught unexpected " + ue + "instead of InvalidTypeException");
|
||||
tot_res = Consts.TEST_FAILED;
|
||||
}
|
||||
log.display("TEST #1: all done.");
|
||||
|
||||
/*
|
||||
* Test #2: verify that stop() works when suspended at a breakpoint.
|
||||
*/
|
||||
log.display("\nTEST #2: Trying to stop debuggee thread while suspended at a breakpoint.");
|
||||
try {
|
||||
thrRef.stop(throwableRef);
|
||||
log.display("TEST #2 PASSED: stop() call succeeded.");
|
||||
} catch (Exception ue) {
|
||||
ue.printStackTrace();
|
||||
log.complain("TEST #2 FAILED: caught unexpected " + ue);
|
||||
tot_res = Consts.TEST_FAILED;
|
||||
}
|
||||
log.display("TEST #2: Resuming debuggee VM to allow async exception to be handled");
|
||||
vm.resume();
|
||||
log.display("TEST #2: all done.");
|
||||
|
||||
/*
|
||||
* Test #3: verify that stop() works when not suspended in a loop. Expect
|
||||
* IllegalThreadStateException for virtual threads.
|
||||
*/
|
||||
log.display("\nTEST #3: Trying to stop debuggee thread while not suspended in a loop.");
|
||||
waitForTestReady(3);
|
||||
try {
|
||||
thrRef.stop(throwableRef);
|
||||
if (vthreadMode) {
|
||||
log.complain("TEST #3 FAILED: expected IllegalThreadStateException"
|
||||
+ " was not thrown for virtual thread");
|
||||
tot_res = Consts.TEST_FAILED;
|
||||
} else {
|
||||
log.display("TEST #3 PASSED: stop() call succeeded.");
|
||||
}
|
||||
} catch (Exception ue) {
|
||||
if (vthreadMode && ue instanceof IllegalThreadStateException) {
|
||||
log.display("TEST #3 PASSED: stop() call threw IllegalThreadStateException"
|
||||
+ " for virtual thread");
|
||||
} else {
|
||||
ue.printStackTrace();
|
||||
log.complain("TEST #3 FAILED: caught unexpected " + ue);
|
||||
tot_res = Consts.TEST_FAILED;
|
||||
}
|
||||
} finally {
|
||||
// Force the debuggee out of the loop. Not really needed if the stop() call
|
||||
// successfully threw the async exception, but it's easier to just always do this.
|
||||
log.display("TEST #3: clearing loop flag.");
|
||||
objRef.setValue(stopLoop1, vm.mirrorOf(true));
|
||||
}
|
||||
log.display("TEST #3: all done.");
|
||||
|
||||
/*
|
||||
* Test #4: verify that stop() works when suspended in a loop
|
||||
*/
|
||||
log.display("\nTEST #4: Trying to stop debuggee thread while suspended in a loop.");
|
||||
waitForTestReady(4);
|
||||
try {
|
||||
thrRef.suspend();
|
||||
log.display("TEST #4: thread is suspended.");
|
||||
thrRef.stop(throwableRef);
|
||||
log.display("TEST #4 PASSED: stop() call succeeded.");
|
||||
} catch (Throwable ue) {
|
||||
ue.printStackTrace();
|
||||
log.complain("TEST #4 FAILED: caught unexpected " + ue);
|
||||
tot_res = Consts.TEST_FAILED;
|
||||
} finally {
|
||||
log.display("TEST #4: resuming thread.");
|
||||
thrRef.resume();
|
||||
// Force the debuggee out of the loop. Not really needed if the stop() call
|
||||
// successfully threw the async exception, but it's easier to just always do this.
|
||||
log.display("TEST #4: clearing loop flag.");
|
||||
objRef.setValue(stopLoop2, vm.mirrorOf(true));
|
||||
}
|
||||
log.display("TEST #4: all done.");
|
||||
|
||||
/*
|
||||
* Test #5: verify that stop() works when suspended in Thread.sleep(). Expect
|
||||
* OpaqueFrameException for virtual threads.
|
||||
*/
|
||||
log.display("\nTEST #5: Trying to stop debuggee thread while suspended in Thread.sleep().");
|
||||
waitForTestReady(5);
|
||||
// Allow debuggee to reach Thread.sleep() first.
|
||||
log.display("TEST #5: waiting for debuggee to sleep...");
|
||||
while (true) {
|
||||
int status = thrRef.status();
|
||||
if (status == ThreadReference.THREAD_STATUS_SLEEPING ||
|
||||
status == ThreadReference.THREAD_STATUS_WAIT)
|
||||
{
|
||||
break;
|
||||
}
|
||||
Thread.sleep(50);
|
||||
}
|
||||
log.display("TEST #5: debuggee is sleeping.");
|
||||
try {
|
||||
thrRef.suspend();
|
||||
log.display("TEST #5: thread is suspended.");
|
||||
thrRef.stop(throwableRef);
|
||||
if (vthreadMode) {
|
||||
log.complain("TEST #5 FAILED: expected OpaqueFrameException was not thrown");
|
||||
tot_res = Consts.TEST_FAILED;
|
||||
} else {
|
||||
log.display("TEST #5 PASSED: stop() call for suspended thread succeeded");
|
||||
}
|
||||
} catch (Throwable ue) {
|
||||
if (vthreadMode && ue instanceof OpaqueFrameException) {
|
||||
log.display("TEST #5 PASSED: stop() call threw OpaqueFrameException for virtual thread");
|
||||
} else {
|
||||
ue.printStackTrace();
|
||||
log.complain("TEST #5 FAILED: caught unexpected " + ue);
|
||||
tot_res = Consts.TEST_FAILED;
|
||||
}
|
||||
} finally {
|
||||
log.display("TEST #5: resuming thread.");
|
||||
thrRef.resume();
|
||||
}
|
||||
log.display("TEST #5: all done.");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
log.complain("TEST FAILURE: caught unexpected exception: " + e);
|
||||
tot_res = Consts.TEST_FAILED;
|
||||
} finally {
|
||||
// Finish the test
|
||||
// force an method to exit
|
||||
if (objRef != null && doExit != null) {
|
||||
// Force the debuggee out of both loops
|
||||
if (objRef != null && stopLoop1 != null && stopLoop2 != null) {
|
||||
try {
|
||||
objRef.setValue(doExit, vm.mirrorOf(true));
|
||||
} catch(Exception sve) {
|
||||
objRef.setValue(stopLoop1, vm.mirrorOf(true));
|
||||
objRef.setValue(stopLoop2, vm.mirrorOf(true));
|
||||
} catch (Exception sve) {
|
||||
sve.printStackTrace();
|
||||
tot_res = Consts.TEST_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -170,6 +293,15 @@ public class stop002 {
|
||||
return quitDebuggee();
|
||||
}
|
||||
|
||||
private void waitForTestReady(int testNum) {
|
||||
log.display("TEST #" + testNum + ": waiting for test ready...");
|
||||
IntegerValue ival;
|
||||
do {
|
||||
ival = (IntegerValue)mainClass.getValue(mainClass.fieldByName("testNumReady"));
|
||||
} while (ival.value() != testNum);
|
||||
log.display("TEST #" + testNum + ": test ready.");
|
||||
}
|
||||
|
||||
private ObjectReference findObjRef(ThreadReference thrRef, String varName) {
|
||||
try {
|
||||
List frames = thrRef.frames();
|
||||
@ -184,9 +316,9 @@ public class stop002 {
|
||||
return (ObjectReference)
|
||||
stackFr.getValue(locVar);
|
||||
}
|
||||
} catch(AbsentInformationException e) {
|
||||
} catch (AbsentInformationException e) {
|
||||
// this is not needed stack frame, ignoring
|
||||
} catch(NativeMethodException ne) {
|
||||
} catch (NativeMethodException ne) {
|
||||
// current method is native, also ignoring
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 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
|
||||
@ -35,7 +35,10 @@ import nsk.share.jdi.*;
|
||||
public class stop002t {
|
||||
private Log log;
|
||||
private IOPipe pipe;
|
||||
volatile boolean stopLooping = false;
|
||||
volatile boolean stopLooping1 = false;
|
||||
volatile boolean stopLooping2 = false;
|
||||
volatile static int testNumReady = 0;
|
||||
static final boolean vthreadMode = "Virtual".equals(System.getProperty("main.wrapper"));
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.exit(run(args) + Consts.JCK_STATUS_BASE);
|
||||
@ -57,23 +60,138 @@ public class stop002t {
|
||||
// as wrong parameter of JDI method ThreadReference.stop()
|
||||
stop002t stop002tNonThrowable = this;
|
||||
|
||||
// throwable object which will be used by debugger
|
||||
// as valid parameter of JDI method ThreadReference.stop()
|
||||
Throwable stop002tThrowable = new MyThrowable("Async exception");
|
||||
|
||||
// Now the debuggee is ready for testing
|
||||
pipe.println(stop002.COMMAND_READY);
|
||||
String cmd = pipe.readln();
|
||||
if (cmd.equals(stop002.COMMAND_QUIT)) {
|
||||
log.complain("Debuggee: exiting due to the command "
|
||||
log.complain("Debuggee: premature debuggee exit due to the command "
|
||||
+ cmd);
|
||||
return Consts.TEST_PASSED;
|
||||
return Consts.TEST_FAILED;
|
||||
}
|
||||
|
||||
int stopMeHere = 0; // stop002.DEBUGGEE_STOPATLINE
|
||||
/*
|
||||
* TEST #1: Tests that stop() properly throws InvalidTypeException if
|
||||
* the specified throwable is not an instance of java.lang.Throwable
|
||||
* in the debuggee. It does not involve the debuggee at all, so there
|
||||
* is no code here for it.
|
||||
*/
|
||||
|
||||
log.display("Debuggee: going to loop ...");
|
||||
while(!stopLooping) { // looping
|
||||
stopMeHere++; stopMeHere--;
|
||||
/*
|
||||
* TEST #2: async exception while suspended at a breakpoint.
|
||||
*/
|
||||
int stopMeHere = 0;
|
||||
try {
|
||||
stopMeHere = 1; // stop002.DEBUGGEE_STOPATLINE
|
||||
log.complain("TEST #2: Failed to throw expected exception");
|
||||
return Consts.TEST_FAILED;
|
||||
} catch (Throwable t) {
|
||||
// Call Thread.interrupted(). Workaround for JDK-8306324
|
||||
log.display("TEST #2: interrupted = " + Thread.interrupted());
|
||||
if (t instanceof MyThrowable) {
|
||||
log.display("TEST #2: Caught expected exception while at breakpoint: " + t);
|
||||
} else {
|
||||
log.complain("TEST #2: Unexpected exception caught: " + t);
|
||||
t.printStackTrace();
|
||||
return Consts.TEST_FAILED;
|
||||
}
|
||||
}
|
||||
log.display("Debuggee: looping done");
|
||||
log.display("TEST #2: all done");
|
||||
|
||||
/*
|
||||
* TEST #3: async exception while not suspended in a loop.
|
||||
*/
|
||||
log.display("TEST #3: going to loop ...");
|
||||
try {
|
||||
while (!stopLooping1) { // looping
|
||||
testNumReady = 3; // signal debugger side of test that we are ready
|
||||
stopMeHere++; stopMeHere--;
|
||||
}
|
||||
if (vthreadMode) {
|
||||
log.display("TEST #3: Correctly did not throw async exception for virtual thread");
|
||||
} else {
|
||||
log.complain("TEST #3: Failed to throw expected exception");
|
||||
return Consts.TEST_FAILED;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// Call Thread.interrupted(). Workaround for JDK-8306324
|
||||
log.display("TEST #3: interrupted = " + Thread.interrupted());
|
||||
// We don't expect the exception to be thrown when in vthread mode.
|
||||
if (!vthreadMode && t instanceof MyThrowable) {
|
||||
log.display("TEST #3: Caught expected exception while in loop: " + t);
|
||||
} else {
|
||||
log.complain("TEST #3: Unexpected exception caught: " + t);
|
||||
t.printStackTrace();
|
||||
return Consts.TEST_FAILED;
|
||||
}
|
||||
}
|
||||
log.display("TEST #3: all done");
|
||||
|
||||
/*
|
||||
* TEST #4: async exception while suspended in a loop.
|
||||
*/
|
||||
log.display("TEST #4: going to loop ...");
|
||||
try {
|
||||
while (!stopLooping2) { // looping
|
||||
testNumReady = 4; // signal debugger side of test that we are ready
|
||||
stopMeHere++; stopMeHere--;
|
||||
}
|
||||
log.complain("TEST #4: Failed to throw expected exception");
|
||||
return Consts.TEST_FAILED;
|
||||
} catch (Throwable t) {
|
||||
// Call Thread.interrupted(). Workaround for JDK-8306324
|
||||
log.display("TEST #4: interrupted = " + Thread.interrupted());
|
||||
if (t instanceof MyThrowable) {
|
||||
log.display("TEST #4: Caught expected exception while in loop: " + t);
|
||||
} else {
|
||||
log.complain("TEST #4: Unexpected exception caught: " + t);
|
||||
t.printStackTrace();
|
||||
return Consts.TEST_FAILED;
|
||||
}
|
||||
}
|
||||
log.display("TEST #4: all done");
|
||||
|
||||
/*
|
||||
* TEST #5: async exception while suspended doing Thread.sleep().
|
||||
*/
|
||||
try {
|
||||
try {
|
||||
// Signal debugger side of test that we are "almost" ready. The
|
||||
// debugger will still need to check that we are in the sleep state.
|
||||
testNumReady = 5;
|
||||
log.display("TEST #5: going to sleep ...");
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException e) {
|
||||
log.complain("TEST #5: Unexpected InterruptedException");
|
||||
e.printStackTrace();
|
||||
return Consts.TEST_FAILED;
|
||||
}
|
||||
if (vthreadMode) {
|
||||
log.display("TEST #5: Correctly did not throw exception while in sleep");
|
||||
} else {
|
||||
log.complain("TEST #5: Failed to throw expected exception");
|
||||
return Consts.TEST_FAILED;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// Call Thread.interrupted(). Workaround for JDK-8306324
|
||||
log.display("TEST #5: interrupted = " + Thread.interrupted());
|
||||
// We don't expect the exception to be thrown when in vthread mode.
|
||||
if (!vthreadMode && t instanceof MyThrowable) {
|
||||
log.display("TEST #5: Caught expected exception while in loop: " + t);
|
||||
} else {
|
||||
log.complain("TEST #5: Unexpected exception caught: " + t);
|
||||
t.printStackTrace();
|
||||
return Consts.TEST_FAILED;
|
||||
}
|
||||
}
|
||||
log.display("TEST #5: all done");
|
||||
|
||||
/*
|
||||
* Test shutdown.
|
||||
*/
|
||||
cmd = pipe.readln();
|
||||
if (!cmd.equals(stop002.COMMAND_QUIT)) {
|
||||
log.complain("TEST BUG: unknown debugger command: "
|
||||
@ -83,3 +201,10 @@ public class stop002t {
|
||||
return Consts.TEST_PASSED;
|
||||
}
|
||||
}
|
||||
|
||||
class MyThrowable extends Throwable
|
||||
{
|
||||
MyThrowable(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user