test/hotspot/jtreg/runtime/Thread/TestThreadDumpClassInitMonitor.java
changeset 53305 d193d58ae79d
child 53396 d74b1c8e632a
equal deleted inserted replaced
53304:9e968a576dd2 53305:d193d58ae79d
       
     1 /*
       
     2  * Copyright (c) 2019, 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     8213397
       
    27  * @summary Check that the thread dump shows when a thread is blocked
       
    28  *          on a class initialization monitor
       
    29  *
       
    30  * @library /test/lib
       
    31  * @run main/othervm TestThreadDumpClassInitMonitor
       
    32  */
       
    33 
       
    34 import jdk.test.lib.process.OutputAnalyzer;
       
    35 import jdk.test.lib.JDKToolFinder;
       
    36 
       
    37 import java.io.IOException;
       
    38 import java.util.List;
       
    39 
       
    40 public class TestThreadDumpClassInitMonitor {
       
    41     // jstack tends to be closely bound to the VM that we are running
       
    42     // so use getTestJDKTool() instead of getCompileJDKTool() or even
       
    43     // getJDKTool() which can fall back to "compile.jdk".
       
    44     final static String JSTACK = JDKToolFinder.getTestJDKTool("jstack");
       
    45     final static String PID = "" + ProcessHandle.current().pid();
       
    46 
       
    47     final static Thread current = Thread.currentThread();
       
    48 
       
    49     /*
       
    50      * This is the output we're looking for:
       
    51      *
       
    52      * "TestThread" #22 prio=5 os_prio=0 cpu=1.19ms elapsed=0.80s tid=0x00007f8f9405d800 nid=0x568b in Object.wait()  [0x00007f8fd94d0000]
       
    53      *   java.lang.Thread.State: RUNNABLE
       
    54      * Thread: 0x00007f8f9405d800  [0x568b] State: _at_safepoint _has_called_back 0 _at_poll_safepoint 0
       
    55      *   JavaThread state: _thread_blocked
       
    56      *         at TestThreadDumpClassInitMonitor$Target$1.run(TestThreadDumpClassInitMonitor.java:69)
       
    57      *         - waiting on the Class initialization monitor for TestThreadDumpClassInitMonitor$Target
       
    58      *
       
    59      */
       
    60     final static String TEST_THREAD = "TestThread";
       
    61     final static String TEST_THREAD_ENTRY = "\"" + TEST_THREAD;
       
    62     final static String IN_OBJECT_WAIT = "in Object.wait()";
       
    63     final static String THREAD_STATE = "java.lang.Thread.State: RUNNABLE";
       
    64     final static String THREAD_INFO = "Thread:"; // the details are not important
       
    65     final static String JAVATHREAD_STATE = "JavaThread state: _thread_blocked";
       
    66     final static String CURRENT_METHOD = "at TestThreadDumpClassInitMonitor$Target$1.run";
       
    67     final static String WAIT_INFO = "- waiting on the Class initialization monitor for TestThreadDumpClassInitMonitor$Target";
       
    68 
       
    69     volatile static boolean ready = false;
       
    70 
       
    71     static List<String> stackDump;  // jstack output as lines
       
    72 
       
    73     static class Target {
       
    74 
       
    75         static int field;
       
    76 
       
    77         // The main thread will initialize this class and so
       
    78         // execute the actual test logic here.
       
    79         static {
       
    80             if (Thread.currentThread() != current) {
       
    81                 throw new Error("Initialization logic error");
       
    82             }
       
    83             System.out.println("Initializing Target class in main thread");
       
    84 
       
    85             Thread t  = new Thread() {
       
    86                     public void run() {
       
    87                         System.out.println("Test thread about to access Target");
       
    88                         ready = true; // tell main thread we're close
       
    89                         // This will block until the main thread completes
       
    90                         // static initialization of target
       
    91                         Target.field = 42;
       
    92                         System.out.println("Test thread done");
       
    93                     }
       
    94                 };
       
    95             t.setName(TEST_THREAD);
       
    96             t.start();
       
    97 
       
    98             // We want to run jstack once the test thread is blocked but
       
    99             // there's no programmatic way to detect that. So we check the flag
       
   100             // that will be set just before it should block, then by the time
       
   101             // we can exec jstack it should be ready.
       
   102             try {
       
   103                 while (!ready) {
       
   104                     Thread.sleep(200);
       
   105                 }
       
   106             }
       
   107             catch (InterruptedException ie) {
       
   108                 throw new Error("Shouldn't happen");
       
   109             }
       
   110 
       
   111             // Now run jstack
       
   112             try {
       
   113                 ProcessBuilder pb = new ProcessBuilder(JSTACK, PID);
       
   114                 OutputAnalyzer output = new OutputAnalyzer(pb.start());
       
   115                 output.shouldHaveExitValue(0);
       
   116                 stackDump = output.asLines();
       
   117             }
       
   118             catch (IOException ioe) {
       
   119                 throw new Error("Launching jstack failed", ioe);
       
   120             }
       
   121         }
       
   122     }
       
   123 
       
   124 
       
   125     public static void main(String[] args) throws Throwable {
       
   126         // Implicitly run the main test logic
       
   127         Target.field = 21;
       
   128 
       
   129         // Now check the output of jstack
       
   130         try {
       
   131             int foundLines = 0;
       
   132             parseStack: for (String line : stackDump) {
       
   133                 switch(foundLines) {
       
   134                 case 0: {
       
   135                     if (!line.startsWith(TEST_THREAD_ENTRY)) {
       
   136                         continue;
       
   137                     }
       
   138                     foundLines++;
       
   139                     if (!line.contains(IN_OBJECT_WAIT)) {
       
   140                         throw new Error("Unexpected initial stack line: " + line);
       
   141                     }
       
   142                     continue;
       
   143                 }
       
   144                 case 1: {
       
   145                     if (!line.trim().equals(THREAD_STATE)) {
       
   146                         throw new Error("Unexpected thread state line: " + line);
       
   147                     }
       
   148                     foundLines++;
       
   149                     continue;
       
   150                 }
       
   151                 case 2: {
       
   152                     if (!line.startsWith(THREAD_INFO)) {
       
   153                         throw new Error("Unexpected thread info line: " + line);
       
   154                     }
       
   155                     foundLines++;
       
   156                     continue;
       
   157                 }
       
   158                 case 3: {
       
   159                     if (!line.trim().equals(JAVATHREAD_STATE)) {
       
   160                         throw new Error("Unexpected JavaThread state line: " + line);
       
   161                     }
       
   162                     foundLines++;
       
   163                     continue;
       
   164                 }
       
   165                 case 4: {
       
   166                     if (!line.trim().startsWith(CURRENT_METHOD)) {
       
   167                         throw new Error("Unexpected current method line: " + line);
       
   168                     }
       
   169                     foundLines++;
       
   170                     continue;
       
   171                 }
       
   172                 case 5: {
       
   173                     if (!line.trim().equals(WAIT_INFO)) {
       
   174                         throw new Error("Unexpected monitor information line: " + line);
       
   175                     }
       
   176                     break parseStack;
       
   177                 }
       
   178                 default: throw new Error("Logic error in case statement");
       
   179                 }
       
   180             }
       
   181 
       
   182             if (foundLines == 0) {
       
   183                 throw new Error("Unexpected stack content - did not find line starting with "
       
   184                                 + TEST_THREAD_ENTRY);
       
   185             }
       
   186         }
       
   187         catch (Error e) {
       
   188             // Dump the full stack trace on error so we can check the content
       
   189             for (String line : stackDump) {
       
   190                 System.out.println(line);
       
   191             }
       
   192             throw e;
       
   193         }
       
   194     }
       
   195 }