I have not tracked down the specific root cause of this failure, yet.
It appears that the suspend is being attempted *before* the thread has been
recorded in *threadControl*.
Adding diagnostic messages is tricky because it changes the timing.
Here's a minimal probe to track threadControl addNode and clearThread
transactions. See attached log.txt.
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c
b/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c
--- a/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/eventHelper.c
@@ -491,7 +491,9 @@
static void
suspendWithInvokeEnabled(jbyte policy, jthread thread)
{
+ /* if (threadControl_getInvokeRequest(thread) != NULL) { */
invoker_enableInvokeRequests(thread);
+ /* } */
if (policy == JDWP_SUSPEND_POLICY(ALL)) {
(void)threadControl_suspendAll();
diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c
b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c
--- a/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c
+++ b/src/jdk.jdwp.agent/share/native/libjdwp/threadControl.c
@@ -285,6 +285,7 @@
static void
addNode(ThreadList *list, ThreadNode *node)
{
+ printf ("addNode %p \n", node->thread);
node->next = NULL;
node->prev = NULL;
node->list = NULL;
@@ -362,6 +363,7 @@
static void
clearThread(JNIEnv *env, ThreadNode *node)
{
+ printf("clearThread %p\n", node->thread);
if (node->pendingStop != NULL) {
tossGlobalRef(env, &(node->pendingStop));
}
@@ -1646,6 +1648,8 @@
node = findThread(&runningThreads, thread);
if (node != NULL) {
request = &node->currentInvoke;
+ } else {
+ printf ("threadControl_getInvokeRequest %p\n", thread);
}
debugMonitorExit(threadLock);
The AGENT_ERROR_INVALID_THREAD is reported when invoker_enableInvokeRequest
does not find the thread. I added the print out in
threadControl_getInvokeRequest
when the thread is not found.
The workaround bypasses the error and falls through to the threadControl
CommonSuspend
path where runningThreads is complimented with an otherThreads mechanism
to ensure
threads that are not between start and end events will be properly
resumed later on.
On 5/23/19, 1:23 PM, Chris Plummer wrote:
Hi Gary,
So a JVMTI event came in on a valid thread, got processed by the Debug
Agent and enqueued to be sent to the Debugger. However, before it was
actually sent, the thread became invalid. Am I understanding this
issue correctly?
thanks,
Chris
On 5/23/19 2:59 AM, [email protected] wrote:
This proposed workaround ensures that the delay between a suspend
request
passing through the jdwp command queue will not fail due to a no longer
running thread.
Webrev: http://cr.openjdk.java.net/~gadams/8218701/webrev/
Issue: https://bugs.openjdk.java.net/browse/JDK-8218701
launcher > Starting jdb launching local debuggee
Creating file for jdb stdout stream: .\\jdb.stdout
Creating file for jdb session: .\\jdb.session
Creating file for jdb stderr stream: .\\jdb.stderr
Setting first breakpoint
Sending command: stop in nsk.jdb.dump.dump002.dump002a.main
reply[0]: Deferring breakpoint nsk.jdb.dump.dump002.dump002a.main.
It will be set after the class is loaded.
reply[1]: >
Starting debuggee class
Sending command: run
reply[0]: run nsk.jdb.dump.dump002.dump002a
reply[1]: Set uncaught java.lang.Throwable
reply[2]: Set deferred uncaught java.lang.Throwable
reply[3]: >
reply[4]: VM Started: addNode 000000D4466E3270
addNode 000000D4466E3278
addNode 000000D4466E3280
addNode 000000D4466E3288
addNode 000000D4466E3290
addNode 000000D4466E3298
addNode 000000D4466E32A0
addNode 000000D4466E32A8
addNode 000000D4466E32C8
addNode 000000D4466E32D0
addNode 000000D4466E32D0
Set deferred breakpoint nsk.jdb.dump.dump002.dump002a.main
reply[5]:
reply[6]: Breakpoint hit: "thread=main", nsk.jdb.dump.dump002.dump002a.main(),
line=37 bci=0
reply[7]: 37 System.exit(dump002.JCK_STATUS_BASE +
_dump002a.runIt(args, System.out));
reply[8]:
reply[9]: main[1]
Test cases starts.
Sending command: stop in nsk.jdb.dump.dump002.dump002a.lastBreak
reply[0]: Set breakpoint nsk.jdb.dump.dump002.dump002a.lastBreak
reply[1]: main[1]
Sending command: cont
reply[0]: >
reply[1]: Breakpoint hit: "thread=main",
nsk.jdb.dump.dump002.dump002a.lastBreak(), line=40 bci=0
reply[2]: 40 static void lastBreak () {}
reply[3]:
reply[4]: main[1]
Sending command: dump nsk.jdb.dump.dump002.dump002a._dump002a
reply[0]: nsk.jdb.dump.dump002.dump002a._dump002a = {
reply[1]: _dump002a: instance of nsk.jdb.dump.dump002.dump002a(id=1382)
reply[2]: iStatic: 0
reply[3]: iPrivate: 1
reply[4]: iProtect: 2
reply[5]: iPublic: 3
reply[6]: iFinal: 4
reply[7]: iTransient: 5
reply[8]: iVolatile: 6
reply[9]: iArray: instance of int[1] (id=1383)
reply[10]: sStatic: "zero"
reply[11]: sPrivate: "one"
reply[12]: sProtected: "two"
reply[13]: sPublic: "three"
reply[14]: sFinal: "four"
reply[15]: sTransient: "five"
reply[16]: sVolatile: "six"
reply[17]: sArray: instance of java.lang.String[1] (id=1391)
reply[18]: fBoolean: true
reply[19]: fByte: 127
reply[20]: fChar: ?
reply[21]: fDouble: 1.7976931348623157E308
reply[22]: fFloat: 3.4028235E38
reply[23]: fInt: 2147483647
reply[24]: fLong: 9223372036854775807
reply[25]: fShort: 32767
reply[26]: }
reply[27]: main[1]
Sending command: dump nsk.jdb.dump.dump002.dump002a.iArray[0]
reply[0]: nsk.jdb.dump.dump002.dump002a.iArray[0] = 7
reply[1]: main[1]
Sending command: dump nsk.jdb.dump.dump002.dump002a.sArray[0]
reply[0]: nsk.jdb.dump.dump002.dump002a.sArray[0] = "seven"
reply[1]: main[1]
Sending command: cont
reply[0]: > FATAL ERROR in native method: JDWP getting thread invoke request,
jvmtiError=AGENT_ERROR_INVALID_THREAD(203)
addNode 000000D447822000
addNode 000000D447768A80
addNode 000000D4477699F8
addNode 000000D447768A88
clearThread 000000D447768A88
clearThread 000000D4466E3270
addNode 000000D4466E3270
clearThread 000000D447768A80
clearThread 000000D4466E3270
addNode 000000D44799B080
addNode 000000D450FFA880
clearThread 000000D447822000
clearThread 000000D44799B080
threadControl_getInvokeRequest 000000D450FFBB98
JDWP exit error AGENT_ERROR_INVALID_THREAD(203): getting thread invoke request
[invoker.c:315]
reply[1]: The application has been disconnected
Sending command: quit
# ERROR: Caught unexpected exception while executing the test:
nsk.share.Failure: Debuggee did not exit after 1 <cont> commands