Here's the updated webrev to avoid the NPE, but still
fail the test with more information about the premature
completed threads.
Issue: https://bugs.openjdk.java.net/browse/JDK-8210252
Webrev: http://cr.openjdk.java.net/~gadams/8210252/webrev.00/
On 9/5/18, 3:16 PM, Gary Adams wrote:
After a quick local check of finishedThreads =1,
I moved the check til after the full list of threads is checked,
rather than repeating the stderr failure after each entry was
processed.
I also implemented a resumeVM() in TestScaffold and called it before
dumpThreads(). That did not fail locally, so I submitted a mach5 job
so I can
run more tests in batches.
...
On 9/5/18, 2:56 PM, Chris Plummer wrote:
I was thinking something like the resume() call. At the very least
just try setting finishedThreads = 1 to exercise the error handling.
Chris
On 9/5/18 11:49 AM, Gary Adams wrote:
I had tried sleeping after each entry in dumpThreads was checked,
but the
failure never occurred.
I had tried using mach5 --jvm-args to set UseZGC, but that never
failed.
Could attempt a resume() before calling dumpThreads() - haven't
tried that , yet.
On 9/5/18, 2:31 PM, Chris Plummer wrote:
Ok. Have you found a way to test your changes? Maybe just force or
simulate a failure somehow.
Chris
On 9/5/18 11:26 AM, Gary Adams wrote:
If we go ahead with this proposed fix, the next time it fails
we will have more information about the other threads
captured in the log.
One last observation, the test that failed was running with UseZGC.
Not sure how that might impact this particular test.
On 9/5/18, 2:07 PM, Chris Plummer wrote:
Hi Gary,
If the DebugThreadTarg is resumed prematurely,
The failure explanation seems to hinge on this, but I don't see
how this can happen. What is resuming DebugThreadTarg? Only the
call to listenUntilVMDisconnect() should be doing this, and we
aren't even getting that far. The only thing I can think of is
due to some other issue (maybe host out of memory so process was
killed off), the DebugThreadTarg process has exited unexpectedly.
In this case I guess the fix you have is appropriate defensive
programming, causing the test to fail when this happens, but
still won't explain why it happens and also won't prevent future
failures of this test. Also, this type of Debuggee early exit
problem could happen with other tests too. I'm leaning towards
just closing this bug as CNR. I don't think we want to be writing
our tests to defend against random system related failures,
especially when the end result is still going to be a test
failure that we don't fully understand.
thanks,
Chris
On 9/5/18 7:33 AM, Gary Adams wrote:
The DebuggerThreadTest ensures it is in sync
at the beginning of RunTests with a breakpoint event
in DebuggerThreadTarg ready() method.
The DebuggerThreadTest then continues with
dumpThreads() and listenUntilVMDisconnect()
completes.
If the DebugThreadTarg is resumed prematurely,
the main thread in the debuggee could complete
before the dumpThreads enumeration is complete.
DebuggerThreadTest
main()
startTests()
runTests()
startTo( "DebuggerThreadTarg.ready()")
dumpThreads()
listenUntilVMDisconnect()
DebuggerThreadTarg
main()
ready()
Revised fix:
- Prevents the NPE from a finished thread group
- Fails the test with a message indicating
number of premature completed threads.
diff --git a/test/jdk/com/sun/jdi/DebuggerThreadTest.java
b/test/jdk/com/sun/jdi/DebuggerThreadTest.java
--- a/test/jdk/com/sun/jdi/DebuggerThreadTest.java
+++ b/test/jdk/com/sun/jdi/DebuggerThreadTest.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2015, Oracle and/or its affiliates. All
rights reserved.
+ * Copyright (c) 2001, 2018, 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
@@ -76,8 +76,16 @@
Thread list[] = new Thread[listThreads * 2];
int gotThreads = tg.enumerate(list, true);
for (int i = 0; i < Math.min(gotThreads, list.length);
i++){
+ int finishedThreads = 0;
Thread t = list[i];
- String groupName = t.getThreadGroup().getName();
+ ThreadGroup tga = t.getThreadGroup();
+ String groupName;
+ if (tga == null) {
+ groupName = "<completed>";
+ finishedThreads++ ;
+ } else {
+ groupName =tga.getName();
+ }
System.out.println("Thread [" + i + "] group = '" +
groupName +
@@ -89,7 +97,10 @@
failure("FAIL: non-daemon thread '" +
t.getName() +
"' found in ThreadGroup '" + groupName
+ "'");
}
-
+ if (finishedThreads > 0 ) {
+ failure("FAIL: " + finishedThreads +
+ " threads completed while VM suspended.");
+ }
}
}
On 9/4/18, 3:15 PM, Chris Plummer wrote:
Hi Gary,
The failed case only had:
Thread [0] group = 'system' name = 'Reference Handler' daemon =
true
Thread [1] group = 'system' name = 'Finalizer' daemon = true
Thread [2] group = 'system' name = 'Signal Dispatcher' daemon =
true
Thread [3] group = 'system' name = 'process reaper' daemon = true
That would indicate that 'main' is likely the thread that
exited. Seems odd. Isn't that the thread that the test is
executing in?
If you can't reproduce it, maybe it would be better to commit a
diagnostic fix like the one I suggested and keep an eye on it.
However, it only seems to have failed once due to this reason,
so unless it is a new problem we may never see it again.
Chris
On 9/4/18 11:28 AM, Gary Adams wrote:
I haven't been able to reproduce the problem locally.
Trying larger test runs on mach5 now.
Here's the output from a successful test run.
If any of the threads exited, they would have a null group name.
Howdy!
Thread [0] group = 'system' name = 'Reference Handler' daemon
= true
Thread [1] group = 'system' name = 'Finalizer' daemon = true
Thread [2] group = 'system' name = 'Signal Dispatcher' daemon
= true
Thread [3] group = 'system' name = 'process reaper' daemon = true
Thread [4] group = 'main' name = 'main' daemon = false
Thread [5] group = 'main' name = 'pool-1-thread-1' daemon = true
Thread [6] group = 'AgentVMThreadGroup' name = 'AgentVMThread'
daemon = false
Thread [7] group = 'AgentVMThreadGroup' name = 'output reader'
daemon = false
Thread [8] group = 'AgentVMThreadGroup' name = 'output reader'
daemon = false
Thread [9] group = 'AgentVMThreadGroup' name = 'Thread-5'
daemon = true
Thread [10] group = 'InnocuousThreadGroup' name =
'Common-Cleaner' daemon = true
Thread [11] group = 'JDI [1485331767]' name = 'JDI Internal
Event Handler' daemon = true
Thread [12] group = 'JDI [1485331767]' name = 'JDI Target VM
Interface' daemon = true
Goodbye from DebuggerThreadTarg!
On 9/4/18, 2:16 PM, Chris Plummer wrote:
Can you reproduce the problem? If so, maybe to find out which
thread is a problem you could check for null, print the
thread info, and then fail the test.
Chris
On 9/4/18 11:14 AM, Gary Adams wrote:
I'm not sure which thread exited causes the NPE.
This patch will let the test continue and at least
let the list of threads be processed.
The test walks up the parents to the initial thread
and then "enumerates()" the set of the threads to check.
There is an inherent race condition in enumerate()
that recognizes it is a snapshot of a moving target.
On 9/4/18, 1:51 PM, Chris Plummer wrote:
Hi Gary,
Why has the thread exited if the debuggee is still running?
Chris
On 9/4/18 5:22 AM, Gary Adams wrote:
Here's a quick fix to avoid the NPE using a
getThreadGroup() which could be null
if the thread has terminated.
Issue: https://bugs.openjdk.java.net/browse/JDK-8210252
diff --git a/test/jdk/com/sun/jdi/DebuggerThreadTest.java
b/test/jdk/com/sun/jdi/DebuggerThreadTest.java
--- a/test/jdk/com/sun/jdi/DebuggerThreadTest.java
+++ b/test/jdk/com/sun/jdi/DebuggerThreadTest.java
@@ -77,7 +77,8 @@
int gotThreads = tg.enumerate(list, true);
for (int i = 0; i < Math.min(gotThreads,
list.length); i++){
Thread t = list[i];
- String groupName = t.getThreadGroup().getName();
+ ThreadGroup tga = t.getThreadGroup();
+ String groupName = (tga == null ? "<completed>":
tga.getName());
System.out.println("Thread [" + i + "] group
= '" +
groupName +