1 /*
   2  * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /**
  25  *  @test
  26  *  @bug 6485605
  27  *  @summary com.sun.jdi.InternalException: Inconsistent suspend policy in internal event handler
  28  *
  29  *  @author jjh
  30  *
  31  *  @modules jdk.jdi
  32  *  @run build TestScaffold VMConnection TargetListener TargetAdapter
  33  *  @run compile -g SuspendThreadTest.java
  34  *  @run driver SuspendThreadTest
  35  */
  36 import com.sun.jdi.*;
  37 import com.sun.jdi.event.*;
  38 import com.sun.jdi.request.*;
  39 
  40 
  41     /********** target program **********/
  42 
  43 class SuspendThreadTarg {
  44     public static long count;
  45     public static boolean active = true;
  46 
  47     public static void bkpt() {
  48         count++;
  49     }
  50 
  51     public static void main(String[] args){
  52         System.out.println("Howdy!");
  53 
  54         // We need this to be running so the bkpt
  55         // can be hit immediately when it is enabled
  56         // in the back-end.
  57         while(active) {
  58             bkpt();
  59         }
  60         System.out.println("Goodbye from SuspendThreadTarg, count = " + count);
  61     }
  62 }
  63 
  64     /********** test program **********/
  65 
  66 public class SuspendThreadTest extends TestScaffold {
  67     ClassType targetClass;
  68     ThreadReference mainThread;
  69 
  70     SuspendThreadTest (String args[]) {
  71         super(args);
  72     }
  73 
  74     public static void main(String[] args)      throws Exception {
  75         new SuspendThreadTest(args).startTests();
  76     }
  77 
  78     /********** event handlers **********/
  79 
  80     // 1000 makes the test take over 2 mins on win32
  81     static int maxBkpts = 200;
  82     volatile int bkptCount;
  83     // to guard against spurious wakeups from bkptSignal.wait()
  84     boolean signalSent;
  85     // signal that a breakpoint has happened
  86     final private Object bkptSignal = new Object() {};
  87     BreakpointRequest bkptRequest;
  88     Field debuggeeCountField, debuggeeActiveField;
  89 
  90     // When we get a bkpt we want to disable the request,
  91     // resume the debuggee, and then re-enable the request
  92     public void breakpointReached(BreakpointEvent event) {
  93         System.out.println("Got BreakpointEvent: " + bkptCount +
  94                            ", debuggeeCount = " +
  95                            ((LongValue)targetClass.
  96                             getValue(debuggeeCountField)).value()
  97                            );
  98         bkptRequest.disable();
  99     }
 100 
 101     public void eventSetComplete(EventSet set) {
 102         set.resume();
 103 
 104         // The main thread watchs the bkptCount to
 105         // see if bkpts stop coming in.  The
 106         // test _should_ fail well before maxBkpts bkpts.
 107         synchronized (bkptSignal) {
 108             if (bkptCount++ < maxBkpts) {
 109                 bkptRequest.enable();
 110             }
 111             signalSent = true;
 112             bkptSignal.notifyAll();
 113         }
 114     }
 115 
 116     public void vmDisconnected(VMDisconnectEvent event) {
 117         println("Got VMDisconnectEvent");
 118     }
 119 
 120     /********** test core **********/
 121 
 122     protected void runTests() throws Exception {
 123         try {
 124             /*
 125              * Get to the top of main()
 126              * to determine targetClass and mainThread
 127              */
 128             BreakpointEvent bpe = startToMain("SuspendThreadTarg");
 129             targetClass = (ClassType)bpe.location().declaringType();
 130             mainThread = bpe.thread();
 131             EventRequestManager erm = vm().eventRequestManager();
 132 
 133             Location loc1 = findMethod(targetClass, "bkpt", "()V").location();
 134 
 135             bkptRequest = erm.createBreakpointRequest(loc1);
 136 
 137             // Without this, it is a SUSPEND_ALL bkpt and the test will pass
 138             bkptRequest.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
 139             bkptRequest.enable();
 140 
 141             debuggeeCountField = targetClass.fieldByName("count");
 142             debuggeeActiveField = targetClass.fieldByName("active");
 143             try {
 144                 addListener (this);
 145             } catch (Exception ex){
 146                 ex.printStackTrace();
 147                 failure("failure: Could not add listener");
 148                 throw new Exception("SuspendThreadTest: failed", ex);
 149             }
 150 
 151             int prevBkptCount;
 152             vm().resume();
 153             synchronized (bkptSignal) {
 154                 while (bkptCount < maxBkpts) {
 155                     prevBkptCount = bkptCount;
 156                     // If we don't get a bkpt within 5 secs,
 157                     // the test fails
 158                     signalSent = false;
 159                     do {
 160                         try {
 161                             bkptSignal.wait(5000);
 162                         } catch (InterruptedException ee) {
 163                         }
 164                     } while (signalSent == false);
 165                     if (prevBkptCount == bkptCount) {
 166                         failure("failure: test hung");
 167                         break;
 168                     }
 169                 }
 170             }
 171             println("done with loop");
 172             bkptRequest.disable();
 173             removeListener(this);
 174 
 175             /*
 176              * deal with results of test
 177              * if anything has called failure("foo") testFailed will be true
 178              */
 179             if (!testFailed) {
 180                 println("SuspendThreadTest: passed");
 181             } else {
 182                 throw new Exception("SuspendThreadTest: failed");
 183             }
 184         } finally {
 185             if (targetClass != null && debuggeeActiveField != null) {
 186                 targetClass.setValue(debuggeeActiveField, vm().mirrorOf(false));
 187             }
 188         }
 189     }
 190 }