1 /*
   2  * Copyright (c) 2008, 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 6751643
  27  *  @summary  ThreadReference.ownedMonitors() can return null
  28  *
  29  *  @author jjh
  30  *
  31  *  @modules jdk.jdi
  32  *  @run build TestScaffold VMConnection TargetListener TargetAdapter
  33  *  @run compile -g SimulResumerTest.java
  34  *  @run driver SimulResumerTest
  35  */
  36 import com.sun.jdi.*;
  37 import com.sun.jdi.event.*;
  38 import com.sun.jdi.request.*;
  39 
  40 import java.util.*;
  41 
  42 /*
  43  * This debuggee basically runs two threads each of
  44  * which loop, hitting a bkpt in each iteration.
  45  *
  46  */
  47 class SimulResumerTarg extends Thread {
  48     static boolean one = false;
  49     static String name1 = "Thread 1";
  50     static String name2 = "Thread 2";
  51     static int count = 10000;
  52     public static void main(String[] args) {
  53         System.out.println("Howdy!");
  54         SimulResumerTarg t1 = new SimulResumerTarg(name1);
  55         SimulResumerTarg t2 = new SimulResumerTarg(name2);
  56 
  57         t1.start();
  58         t2.start();
  59     }
  60 
  61     public SimulResumerTarg(String name) {
  62         super(name);
  63     }
  64 
  65     public void run() {
  66         if (getName().equals(name1)) {
  67             run1();
  68         } else {
  69             run2();
  70         }
  71     }
  72 
  73     public void bkpt1(int i) {
  74         synchronized(name1) {
  75             yield();
  76         }
  77     }
  78 
  79     public void run1() {
  80         int i = 0;
  81         while (i < count) {
  82             i++;
  83             bkpt1(i);
  84         }
  85     }
  86 
  87     public void bkpt2(int i) {
  88         synchronized(name2) {
  89             yield();
  90         }
  91     }
  92 
  93     public void run2() {
  94         int i = 0;
  95         while (i < count) {
  96             i++;
  97             bkpt2(i);
  98         }
  99     }
 100 }
 101 
 102 /********** test program **********/
 103 
 104 public class SimulResumerTest extends TestScaffold {
 105     ReferenceType targetClass;
 106     ThreadReference mainThread;
 107     BreakpointRequest request1;
 108     BreakpointRequest request2;
 109     static volatile int bkpts = 0;
 110     static int iters = 0;
 111     Thread resumerThread;
 112     static int waitTime = 100;
 113     ThreadReference debuggeeThread1 = null;
 114     ThreadReference debuggeeThread2 = null;
 115 
 116     SimulResumerTest (String args[]) {
 117         super(args);
 118     }
 119 
 120     public static void main(String[] args)      throws Exception {
 121         new SimulResumerTest(args).startTests();
 122     }
 123 
 124     /* BreakpointEvent handler */
 125 
 126     public void breakpointReached(BreakpointEvent event) {
 127         // save ThreadRefs for the two debuggee threads
 128         ThreadReference thr = event.thread();
 129         if (bkpts == 0) {
 130             resumerThread.start();
 131             debuggeeThread1 = thr;
 132             System.out.println("thr1 = " + debuggeeThread1);
 133         }
 134 
 135         if (debuggeeThread2 == null && thr != debuggeeThread1) {
 136             debuggeeThread2 = thr;
 137             System.out.println("thr2 = " + debuggeeThread2);
 138         }
 139 
 140         synchronized("abc") {
 141             bkpts++;
 142         }
 143         /**
 144         if (bkpts >= SimulResumerTarg.count * 2) {
 145             resumerThread.interrupt();
 146         }
 147         *****/
 148 
 149     }
 150 
 151     /********** test core **********/
 152 
 153     void check(ThreadReference thr) {
 154         // This calls each ThreadReference method that could fail due to the bug
 155         // that occurs if a resume is done while a call to the method is in process.
 156         String kind = "";
 157         if (thr != null) {
 158             try {
 159                 kind = "ownedMonitors()";
 160                 System.out.println("kind = " + kind);
 161                 if (thr.ownedMonitors() == null) {
 162                     failure("failure: ownedMonitors = null");
 163                 }
 164 
 165                 kind = "ownedMonitorsAndFrames()";
 166                 System.out.println("kind = " + kind);
 167                 if (thr.ownedMonitorsAndFrames() == null) {
 168                     failure("failure: ownedMonitorsAndFrames = null");
 169                 }
 170 
 171                 kind = "currentContendedMonitor()";
 172                 System.out.println("kind = " + kind);
 173                 thr.currentContendedMonitor();
 174                 // no failure return value here; could cause an NPE
 175 
 176                 kind = "frames()";
 177                 System.out.println("kind = " + kind);
 178                 List<StackFrame> frames = thr.frames();
 179                 // no failure return value here; could cause an NPE
 180 
 181                 kind = "frames(0, size - 1)";
 182                 System.out.println("kind = " + kind);
 183                 int nframes = frames.size();
 184                 while (nframes > 0) {
 185                     try {
 186                         thr.frames(0, nframes - 1);
 187                         break;
 188                     } catch (IndexOutOfBoundsException iobe) {
 189                         // 6815126. let's try to get less frames
 190                         iobe.printStackTrace();
 191                         nframes--;
 192                     }
 193                 }
 194 
 195                 kind = "frameCount()";
 196                 System.out.println("kind = " + kind);
 197                 if (thr.frameCount() == -1) {
 198                     failure("failure: frameCount = -1");
 199                 }
 200 
 201                 kind = "name()";
 202                 System.out.println("kind = " + kind);
 203                 if (thr.name() == null) {
 204                     failure("failure: name = null");
 205                 }
 206 
 207                 kind = "status()";
 208                 System.out.println("kind = " + kind);
 209                 if (thr.status() < 0) {
 210                     failure("failure: status < 0");
 211                 }
 212 
 213             } catch (IncompatibleThreadStateException ee) {
 214                 // ignore
 215             } catch (VMDisconnectedException ee) {
 216                 // This is how we stop.  The debuggee runs to completion
 217                 // and we get this exception.
 218                 throw ee;
 219             } catch (Exception ee) {
 220                 failure("failure: Got exception from " + kind + ": " + ee );
 221             }
 222         }
 223     }
 224 
 225     protected void runTests() throws Exception {
 226         /*
 227          * Get to the top of main()
 228          * to determine targetClass and mainThread
 229          */
 230         BreakpointEvent bpe = startToMain("SimulResumerTarg");
 231         targetClass = bpe.location().declaringType();
 232         mainThread = bpe.thread();
 233         EventRequestManager erm = vm().eventRequestManager();
 234         final Thread mainThread = Thread.currentThread();
 235 
 236         /*
 237          * Set event requests
 238          */
 239         Location loc1 = findMethod(targetClass, "bkpt1", "(I)V").location();
 240         Location loc2 = findMethod(targetClass, "bkpt2", "(I)V").location();
 241         request1 = erm.createBreakpointRequest(loc1);
 242         request2 = erm.createBreakpointRequest(loc2);
 243         request1.enable();
 244         request2.enable();
 245 
 246         /*
 247          * This thread will be started when we get the first bkpt.
 248          */
 249         resumerThread = new Thread("test resumer") {
 250                 public void run() {
 251                     while (true) {
 252                         iters++;
 253                         System.out.println("bkpts = " + bkpts + ", iters = " + iters);
 254                         try {
 255                             Thread.sleep(waitTime);
 256                             check(debuggeeThread1);
 257                             check(debuggeeThread2);
 258                         } catch (InterruptedException ee) {
 259                             // If the test completes, this occurs.
 260                             println("resumer Interrupted");
 261                             break;
 262                         } catch (VMDisconnectedException ee) {
 263                             println("VMDisconnectedException");
 264                             break;
 265                         }
 266                     }
 267                 }
 268             };
 269 
 270         /*
 271          * resume the target, listening for events
 272          */
 273         listenUntilVMDisconnect();
 274         resumerThread.interrupt();
 275         /*
 276          * deal with results of test
 277          * if anything has called failure("foo") testFailed will be true
 278          */
 279         if (!testFailed) {
 280             println("SimulResumerTest: passed; bkpts = " + bkpts + ", iters = " + iters);
 281         } else {
 282             throw new Exception("SimulResumerTest: failed; bkpts = " + bkpts + ", iters = " + iters);
 283         }
 284     }
 285 }