1 /*
   2  * Copyright (c) 2017, 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 import java.util.ArrayList;
  25 import java.util.Scanner;
  26 import java.util.List;
  27 import java.io.File;
  28 import java.io.IOException;
  29 import java.util.stream.Collectors;
  30 import java.io.OutputStream;
  31 import jdk.test.lib.apps.LingeredApp;
  32 import jdk.test.lib.JDKToolLauncher;
  33 import jdk.test.lib.Platform;
  34 import jdk.test.lib.process.ProcessTools;
  35 import jdk.test.lib.process.OutputAnalyzer;
  36 import jdk.test.lib.Utils;
  37 import jdk.test.lib.Asserts;
  38 
  39 /*
  40  * @test
  41  * @library /test/lib
  42  * @run main/othervm TestClhsdbJstackLock
  43  */
  44 
  45 public class TestClhsdbJstackLock {
  46 
  47     private static final String JSTACK_OUT_FILE = "jstack_out.txt";
  48 
  49     private static void verifyJStackOutput() throws Exception {
  50 
  51         Exception unexpected = null;
  52         File jstackFile = new File(JSTACK_OUT_FILE);
  53         Asserts.assertTrue(jstackFile.exists() && jstackFile.isFile(),
  54                            "File with jstack output not created: " +
  55                            jstackFile.getAbsolutePath());
  56         try {
  57             Scanner scanner = new Scanner(jstackFile);
  58 
  59             boolean classLockOwnerFound = false;
  60             boolean classLockWaiterFound = false;
  61             boolean objectLockOwnerFound = false;
  62             boolean primitiveLockOwnerFound = false;
  63 
  64             while (scanner.hasNextLine()) {
  65                 String line = scanner.nextLine();
  66                 System.out.println(line);
  67 
  68                 if (line.contains("missing reason for ")) {
  69                     unexpected = new RuntimeException("Unexpected msg: missing reason for ");
  70                     break;
  71                 }
  72                 if (line.matches("^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Class for LingeredAppWithLock\\)$")) {
  73                     classLockOwnerFound = true;
  74                 }
  75                 if (line.matches("^\\s+- waiting to lock <0x[0-9a-f]+> \\(a java\\.lang\\.Class for LingeredAppWithLock\\)$")) {
  76                     classLockWaiterFound = true;
  77                 }
  78                 if (line.matches("^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Thread\\)$")) {
  79                     objectLockOwnerFound = true;
  80                 }
  81                 if (line.matches("^\\s+- locked <0x[0-9a-f]+> \\(a java\\.lang\\.Class for int\\)$")) {
  82                     primitiveLockOwnerFound = true;
  83                 }
  84             }
  85 
  86             if (!classLockOwnerFound || !classLockWaiterFound ||
  87                 !objectLockOwnerFound || !primitiveLockOwnerFound) {
  88                 unexpected = new RuntimeException(
  89                       "classLockOwnerFound = " + classLockOwnerFound +
  90                       ", classLockWaiterFound = " + classLockWaiterFound +
  91                       ", objectLockOwnerFound = " + objectLockOwnerFound +
  92                       ", primitiveLockOwnerFound = " + primitiveLockOwnerFound);
  93             }
  94             if (unexpected != null) {
  95                 throw unexpected;
  96             }
  97         } catch (Exception ex) {
  98            throw new RuntimeException("Test ERROR " + ex, ex);
  99         } finally {
 100            jstackFile.delete();
 101         }
 102     }
 103 
 104     private static void startClhsdbForLock(long lingeredAppPid) throws Exception {
 105 
 106         Process p;
 107         JDKToolLauncher launcher = JDKToolLauncher.createUsingTestJDK("jhsdb");
 108         launcher.addToolArg("clhsdb");
 109         launcher.addToolArg("--pid");
 110         launcher.addToolArg(Long.toString(lingeredAppPid));
 111 
 112         ProcessBuilder pb = new ProcessBuilder();
 113         pb.command(launcher.getCommand());
 114         System.out.println(
 115             pb.command().stream().collect(Collectors.joining(" ")));
 116 
 117         try {
 118             p = pb.start();
 119         } catch (Exception attachE) {
 120             throw new Error("Couldn't start jhsdb or attach to LingeredApp : " + attachE);
 121         }
 122 
 123         // Issue the 'jstack' input at the clhsdb prompt.
 124         OutputStream input = p.getOutputStream();
 125         String str = "jstack > " + JSTACK_OUT_FILE + "\nquit\n";
 126         try {
 127             input.write(str.getBytes());
 128             input.flush();
 129         } catch (IOException ioe) {
 130             throw new Error("Problem issuing the jstack command: " + str, ioe);
 131         }
 132 
 133         try {
 134             p.waitFor();
 135         } catch (InterruptedException ie) {
 136             throw new Error("Problem awaiting the child process: " + ie, ie);
 137         }
 138 
 139         int exitValue = p.exitValue();
 140         if (exitValue != 0) {
 141             String output;
 142             try {
 143                 output = new OutputAnalyzer(p).getOutput();
 144             } catch (IOException ioe) {
 145                 throw new Error("Can't get failed clhsdb process output: " + ioe, ioe);
 146             }
 147             throw new AssertionError("clhsdb wasn't run successfully: " + output);
 148         }
 149     }
 150 
 151     public static void main (String... args) throws Exception {
 152 
 153         LingeredApp app = null;
 154 
 155         if (!Platform.shouldSAAttach()) {
 156             System.out.println(
 157                "SA attach not expected to work - test skipped.");
 158             return;
 159         }
 160 
 161         try {
 162             List<String> vmArgs = new ArrayList<String>(Utils.getVmOptions());
 163 
 164             app = new LingeredAppWithLock();
 165             LingeredApp.startApp(vmArgs, app);
 166             System.out.println ("Started LingeredApp with pid " + app.getPid());
 167             startClhsdbForLock(app.getPid());
 168             verifyJStackOutput();
 169         } finally {
 170             LingeredApp.stopApp(app);
 171         }
 172     }
 173 }