During some longer testing runs I noticed similar failures for resume002,
resume003 and resume006. I'll spend a few more cycles to see if a more
general purpose solution could be shared across these tests.

On 7/24/18 7:46 PM, Chris Plummer wrote:
Hi Gary,

It looks like that should work fine.

thanks,

Chris

On 7/24/18 12:28 PM, Gary Adams wrote:
Here's a quick prototype to add a variable to the debuggee.
The debugger sets it at the end of each completed test case.

The debuggee can then check for the value change to delay
hitting the breakpoint which interfered with suspend count checks.

Would need to add a bit more error and timeout checking to
complete the fix. Should also check if the other resume008 test cases
need similar synchronization. Could possibly migrate the code up to
TestDebuggerType1 if other tests also needed this generic capability.


diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume008.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume008.java --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume008.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume008.java
@@ -63,6 +63,9 @@
  *   to be resulting in the event.
  * - Upon getting new event, the debugger
  *   performs the check corresponding to the event.
+ * - The debugger informs the debuggee when it completes
+ *   each test case, so it will wait before hitting
+ *   communication breakpoints.
  */

 public class resume008 extends TestDebuggerType1 {
@@ -234,6 +237,7 @@

                      default: throw new Failure("** default case 1 **");
                 }
+                informDebuggeeTestCase(i);
             }

             display("......--> vm.resume()");
@@ -255,4 +259,25 @@
         }
     }

+    /**
+     * Inform debuggee which thread test the debugger has completed.
+     * Used for synchronization, so the debuggee does not move too quickly.
+     * @param testCase index of just completed test
+     */
+    void informDebuggeeTestCase(int testCase) {
+        if (!EventHandler.isDisconnected() && debuggeeClass != null) {
+            try {
+                ((ClassType)debuggeeClass)
+ .setValue(debuggeeClass.fieldByName("testCase"),
+                              vm.mirrorOf(testCase));
+            } catch (InvalidTypeException ite) {
+                // ignored
+            } catch (ClassNotLoadedException cnle) {
+                // ignored
+            } catch (VMDisconnectedException e) {
+                // ignored
 }
+        }
+    }
+
+}


diff --git a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume008a.java b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume008a.java --- a/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume008a.java +++ b/test/hotspot/jtreg/vmTestbase/nsk/jdi/EventSet/resume/resume008a.java
@@ -62,6 +62,7 @@

     static int exitCode = PASSED;

+    static int testCase = -1;
     static int instruction = 1;
     static int end         = 0;
                                    //    static int quit = 0;
@@ -104,6 +105,15 @@
                             threadStart(thread0);

                             thread1 = new Threadresume008a("thread1");
+                            // Wait for debugger to complete the first test case
+                            // before advancing to the next breakpoint
+                            while (testCase < 0) {
+                                try {
+                                    Thread.sleep(100);
+                                } catch (InterruptedException e) {
+                                    // ignored
+                                }
+                            }
                             methodForCommunication();
                             break;


On 7/20/18, 2:37 PM, Chris Plummer wrote:
Hi Gary,

The test fails if the breakpoint event comes in after the test captures the initial thread suspend counts and before the test captures the 2nd suspend counts.

debugger>         getting : Map<String, Integer> suspendsCounts1
debugger> {Reference Handler=1, Common-Cleaner=1, main=1, Signal Dispatcher=1, Finalizer=1}
debugger>         eventSet.resume;
debugger>         getting : Map<String, Integer> suspendsCounts2
EventHandler> Received event set with policy = SUSPEND_ALL
EventHandler> Event: BreakpointEventImpl req breakpoint request nsk.jdi.EventSet.resume.resume008a:60 (enabled)
debugger> Received communication breakpoint event.
debugger> {Reference Handler=2, Common-Cleaner=2, main=1, Signal Dispatcher=2, Finalizer=2}

So we end up with some threads starting with 1 suspend and ending with 2 (not clear to me why main is still at 1).

It will pass if the breakpoint comes in after it does both of suspend count checks, as you have shown with the sleep(100) solution. Output looks like this:

debugger>        got new ThreadStartEvent with propety 'number' == ThreadStartRequest1
...
debugger> ......--> vm.suspend();
debugger>         getting : Map<String, Integer> suspendsCounts1
debugger> {Reference Handler=1, thread0=1, Common-Cleaner=1, main=1, Signal Dispatcher=1, Finalizer=1}
debugger>         eventSet.resume;
debugger>         getting : Map<String, Integer> suspendsCounts2
debugger> {Reference Handler=1, thread0=1, Common-Cleaner=1, main=1, Signal Dispatcher=1, Finalizer=1}
...
debugger> Received communication breakpoint event.

I've also shown that it passes if the breakpoint always comes in before capturing the initial suspend counts. I added a sleep on the debugger side right after eventHandler.waitForRequestedEventSet() returns. Output looks like:

debugger> Received communication breakpoint event.
debugger>        got new ThreadStartEvent with propety 'number' == ThreadStartRequest1
...
debugger> ......--> vm.suspend();
debugger>         getting : Map<String, Integer> suspendsCounts1
debugger> {Reference Handler=2, thread0=2, Common-Cleaner=2, main=2, Signal Dispatcher=2, Finalizer=2}
debugger>         eventSet.resume;
debugger>         getting : Map<String, Integer> suspendsCounts2
debugger> {Reference Handler=2, thread0=2, Common-Cleaner=2, main=2, Signal Dispatcher=2, Finalizer=2}

I think we should add synchronization to force one of these two outcomes. For the first, you would need to make the debugger modify some variable that the debuggee is watching (sitting in a loop waiting for it to change). For the second, you can rely on the existing methodForCommunication() approach. You just need to restructure the debugger a bit. I had started down this path late Wednesday, but got sidetracked by a few other things. I can look into it some more if you'd like.

thanks,

Chris


Reply via email to