1 /*
   2  * Copyright (c) 2002, 2018, 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 4629548
  27  * @summary Deferred StepRequests are lost in multithreaded debuggee
  28  * @comment converted from test/jdk/com/sun/jdi/DeferredStepTest.sh
  29  *
  30  * @library /test/lib
  31  * @build DeferredStepTest
  32  * @run main/othervm DeferredStepTest
  33  */
  34 
  35 import jdk.test.lib.Asserts;
  36 import jdk.test.lib.Utils;
  37 import lib.jdb.JdbCommand;
  38 import lib.jdb.JdbTest;
  39 
  40 import java.util.HashMap;
  41 import java.util.List;
  42 import java.util.Map;
  43 import java.util.regex.Matcher;
  44 import java.util.regex.Pattern;
  45 import java.util.stream.Collectors;
  46 
  47 class DeferredStepTestTarg {
  48     static class  jj1 implements Runnable {
  49         public void  run() {
  50             int count = 0;
  51 
  52             for ( int ii = 0; ii < 10; ii++) {
  53                 int intInPotato04 = 666;
  54                 ++count;                        // @1 breakpoint
  55                 System.out.println("Thread: " + Thread.currentThread().getName());
  56             }
  57         }
  58     }
  59 
  60     static class jj2 implements Runnable {
  61         public void run() {
  62             int count2 = 0;
  63 
  64             for (int ii = 0; ii < 10; ii++) {
  65                 String StringInPotato05 = "I am";
  66                 ++count2;                           // @2 breakpoint
  67                 System.out.println("Thread: " + Thread.currentThread().getName());
  68             }
  69         }
  70     }
  71 
  72     public static void  main(String argv[]) {
  73         System.out.println("Version = " + System.getProperty("java.version"));
  74 
  75         jj1 obj1 = new jj1();
  76         jj2 obj2 = new jj2();
  77         new Thread(obj1, "jj1").start();
  78         new Thread(obj2, "jj2").start();
  79     }
  80 }
  81 
  82 public class DeferredStepTest extends JdbTest {
  83     public static void main(String argv[]) {
  84         new DeferredStepTest().run();
  85     }
  86 
  87     private DeferredStepTest() {
  88         super(DeferredStepTestTarg.class.getName());
  89     }
  90 
  91     private static class ThreadData {
  92         int lastLine = -1;  // line of the last stop
  93         int minLine = -1;   // min line (-1 means "not known yet")
  94         int maxLine = -1;   // max line (-1 means "not known yet")
  95     }
  96 
  97     private Map<String, ThreadData> threadData = new HashMap<>();
  98 
  99     private Pattern threadRegexp = Pattern.compile("^(.+)\\[\\d+\\].*");
 100     private Pattern lineRegexp = Pattern.compile("^(\\d+)\\b.*", Pattern.MULTILINE);
 101 
 102     // returns the 1st group of the pattern.
 103     private String parse(Pattern p, String input) {
 104         Matcher m = p.matcher(input);
 105         if (!m.find()) {
 106             throw new RuntimeException("Input '" + input + "' does not matches '" + p.pattern() + "'");
 107         }
 108         return m.group(1);
 109     }
 110 
 111     private void next() {
 112         List<String> reply = jdb.command(JdbCommand.next());
 113         /*
 114          * Each "next" produces something like ("Breakpoint hit" line only if the line has BP)
 115          *   Step completed:
 116          *     Breakpoint hit: "thread=jj2", DeferredStepTestTarg$jj2.run(), line=74 bci=12
 117          *     74                    ++count2;                           // @ 2 breakpoint
 118          *     <empty line>
 119          *     jj2[1]
 120          */
 121         // detect thread from the last line
 122         String lastLine = reply.get(reply.size() - 1);
 123         String threadName = parse(threadRegexp, lastLine);
 124         String wholeReply = reply.stream().collect(Collectors.joining(Utils.NEW_LINE));
 125         int lineNum = Integer.parseInt(parse(lineRegexp, wholeReply));
 126 
 127         System.out.println("got: thread=" + threadName + ", line=" + lineNum);
 128 
 129         ThreadData data = threadData.get(threadName);
 130         if (data == null) {
 131             data = new ThreadData();
 132             threadData.put(threadName, data);
 133         }
 134         processThreadData(threadName, lineNum, data);
 135     }
 136 
 137     private void processThreadData(String threadName, int lineNum, ThreadData data) {
 138         int lastLine = data.lastLine;
 139         data.lastLine = lineNum;
 140         if (lastLine < 0) {
 141             // the 1st stop in the thread
 142             return;
 143         }
 144         if (lineNum == lastLine + 1) {
 145             // expected.
 146             return;
 147         }
 148         if (lineNum < lastLine) {
 149             // looks like step to the beginning of the cycle
 150             if (data.minLine > 0) {
 151                 // minLine and maxLine are not set - verify
 152                 Asserts.assertEquals(lineNum, data.minLine, threadName + " - minLine");
 153                 Asserts.assertEquals(lastLine, data.maxLine, threadName + " - maxLine");
 154             } else {
 155                 // set minLine/maxLine
 156                 data.minLine = lineNum;
 157                 data.maxLine = lastLine;
 158             }
 159             return;
 160         }
 161         throw new RuntimeException(threadName + " (line " + lineNum + ") - unexpected."
 162                 + " lastLine=" + lastLine + ", minLine=" + data.minLine + ", maxLine=" + data.maxLine);
 163     }
 164 
 165     @Override
 166     protected void runCases() {
 167         setBreakpoints(jdb, DeferredStepTestTarg.jj1.class.getName(),
 168                 getTestSourcePath("DeferredStepTest.java"), 1);
 169         setBreakpoints(jdb, DeferredStepTestTarg.jj2.class.getName(),
 170                 getTestSourcePath("DeferredStepTest.java"), 2);
 171 
 172         // Run to breakpoint #1
 173         jdb.command(JdbCommand.run());
 174 
 175         // 2 cycles with 4 lines each - maximum 80 stops
 176         for (int i=0; i<50; i++) {
 177             next();
 178         }
 179     }
 180 }