TraveledLockTest.java revision 11098:927d84d0b391
138032Speter/* 238032Speter * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 338032Speter * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 438032Speter * 538032Speter * This code is free software; you can redistribute it and/or modify it 638032Speter * under the terms of the GNU General Public License version 2 only, as 738032Speter * published by the Free Software Foundation. 838032Speter * 938032Speter * This code is distributed in the hope that it will be useful, but WITHOUT 1038032Speter * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1138032Speter * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1238032Speter * version 2 for more details (a copy is included in the LICENSE file that 1338032Speter * accompanied this code). 1438032Speter * 1543730Speter * You should have received a copy of the GNU General Public License version 1638032Speter * 2 along with this work; if not, write to the Free Software Foundation, 1738032Speter * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1838032Speter * 1938032Speter * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2042575Speter * or visit www.oracle.com if you need additional information or have any 2138032Speter * questions. 2238032Speter */ 2338032Speter 2438032Speter/* 2538032Speter * @test 2638032Speter * @summary Create a thread which stops in methods a(), a()->b(), a()->b()->c(), 2738032Speter * synchronizing on one monitor inside of each method. 2838032Speter * After checking that lock info is correct free the lock and 2938032Speter * invoke another method. Repeat this action. 3038032Speter * @modules java.base/jdk.internal.misc 3138032Speter * @library /test/lib/share/classes 3238032Speter * @library ../share 3338032Speter * @build common.* 3438032Speter * 3538032Speter * @run main/othervm -XX:+UsePerfData TraveledLockTest 3638032Speter */ 3738032Speterimport common.ToolResults; 3838032Speterimport java.util.Iterator; 3938032Speterimport utils.*; 4038032Speter 4138032Speterclass TraveledLockDebuggee extends Thread { 4238032Speter 4338032Speter static final String THREAD_NAME = "MyThread"; 4438032Speter 4538032Speter TraveledLockDebuggee() { 4638032Speter setName(THREAD_NAME); 4738032Speter } 4838032Speter 4938032Speter Object monitor = new Object(); 5038032Speter 5138032Speter public void c() { 5238032Speter synchronized (monitor) { 5338032Speter Utils.sleep(); 5438032Speter } 5538032Speter } 5638032Speter 5738032Speter public void b() { 5838032Speter try { 5938032Speter synchronized (monitor) { 6038032Speter while (true) { 6138032Speter Thread.sleep(Long.MAX_VALUE); 6238032Speter } 6338032Speter } 6438032Speter } catch (InterruptedException e) { 6538032Speter c(); 6638032Speter } 6738032Speter } 6838032Speter 6938032Speter public void a() { 7038032Speter try { 7138032Speter synchronized (monitor) { 7238032Speter while (true) { 7338032Speter Thread.sleep(Long.MAX_VALUE); 7438032Speter } 7538032Speter } 7638032Speter } catch (InterruptedException e) { 7738032Speter b(); 7838032Speter } 7938032Speter } 8038032Speter 8138032Speter public void run() { 8238032Speter a(); 8338032Speter } 8438032Speter 8538032Speter} 8638032Speter 8738032Speterpublic class TraveledLockTest { 8838032Speter 8938032Speter public static void main(String[] args) throws Exception { 9038032Speter new TraveledLockTest().doTest(); 9138032Speter } 9238032Speter 9338032Speter private void doTest() throws Exception { 9438032Speter TraveledLockDebuggee debuggee = new TraveledLockDebuggee(); 9538032Speter 9638032Speter // Start in method a() 9738032Speter debuggee.start(); 9838032Speter 9938032Speter // Collect output from the jstack tool 10038032Speter JstackTool jstackTool = new JstackTool(ProcessHandle.current().getPid()); 10138032Speter ToolResults results1 = jstackTool.measure(); 10238032Speter 10338032Speter // Go to method b() 10438032Speter debuggee.interrupt(); 10538032Speter 10638032Speter // Collect output from the jstack tool 10738032Speter ToolResults results2 = jstackTool.measure(); 10838032Speter 10938032Speter // Go to method c() 11038032Speter debuggee.interrupt(); 11138032Speter 11238032Speter // Collect output from the jstack tool 11338032Speter ToolResults results3 = jstackTool.measure(); 11438032Speter 11538032Speter analyse(results1.getStdoutString(), results2.getStdoutString(), results3.getStdoutString()); 11638032Speter } 11738032Speter 11838032Speter // Analyzsing the outputs from the 3 jstack runs 11938032Speter public void analyse(String results1, String results2, String results3) { 12038032Speter 12138032Speter String jstackStr1 = results1; 12238032Speter String jstackStr2 = results2; 12338032Speter String jstackStr3 = results3; 12438032Speter 12538032Speter if (jstackStr1 == null) { 12638032Speter throw new RuntimeException("First jstack output is empty"); 12738032Speter } 12838032Speter if (jstackStr2 == null) { 12938032Speter throw new RuntimeException("Second jstack output is empty"); 13038032Speter } 13138032Speter if (jstackStr3 == null) { 13238032Speter throw new RuntimeException("Third jstack output is empty"); 13338032Speter } 13438032Speter 13538032Speter Format format = new DefaultFormat(); 13638032Speter JStack jstack1 = format.parse(jstackStr1); 13738032Speter JStack jstack2 = format.parse(jstackStr2); 13838032Speter JStack jstack3 = format.parse(jstackStr3); 13938032Speter 14038032Speter ThreadStack ts1 = jstack1.getThreadStack(TraveledLockDebuggee.THREAD_NAME); 14138032Speter ThreadStack ts2 = jstack2.getThreadStack(TraveledLockDebuggee.THREAD_NAME); 14238032Speter ThreadStack ts3 = jstack3.getThreadStack(TraveledLockDebuggee.THREAD_NAME); 14338032Speter 14438032Speter if (ts1 == null || ts2 == null || ts3 == null) { 14538032Speter throw new RuntimeException( 14638032Speter "One of thread stack trace is null in the first jstack output : " 14738032Speter + ts1 + ", " + ts2 + ", " + ts3); 14838032Speter } 14938032Speter 15038032Speter MonitorInfo monitorInfo1 = null; 15138032Speter MonitorInfo monitorInfo2 = null; 15238032Speter MonitorInfo monitorInfo3 = null; 15338032Speter 15438032Speter Iterator<MethodInfo> it = ts1.getStack().iterator(); 15538032Speter while (it.hasNext()) { 15638032Speter MethodInfo mi = it.next(); 15738032Speter if (mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".a")) { 15838032Speter monitorInfo1 = haveToHaveOneLock(mi); 15938032Speter } 16038032Speter } 16138032Speter 16238032Speter it = ts2.getStack().iterator(); 16338032Speter while (it.hasNext()) { 16438032Speter MethodInfo mi = it.next(); 16538032Speter if (mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".a")) { 16638032Speter haveToBeEmpty(mi); 16738032Speter } else if (mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".b")) { 16838032Speter monitorInfo2 = haveToHaveOneLock(mi); 16938032Speter } 17038032Speter } 17138032Speter 17238032Speter it = ts3.getStack().iterator(); 17338032Speter while (it.hasNext()) { 17438032Speter MethodInfo mi = it.next(); 17538032Speter if (mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".a") 17638032Speter || mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".b")) { 17738032Speter haveToBeEmpty(mi); 17838032Speter } else if (mi.getName().startsWith(TraveledLockDebuggee.class.getName() + ".c")) { 17938032Speter monitorInfo3 = haveToHaveOneLock(mi); 18038032Speter } 18138032Speter } 18238032Speter 18338032Speter System.out.println("All monitors found - passed"); 18438032Speter } 18538032Speter 18638032Speter private MonitorInfo haveToHaveOneLock(MethodInfo mi) { 18738032Speter if (mi.getLocks().size() == 1) { 18838032Speter System.out.println("Method \"" + mi.getName() 18938032Speter + "\" contain 1 lock - correct"); 19038032Speter return mi.getLocks().getFirst(); 19138032Speter } else { 19238032Speter throw new RuntimeException("Lock count (" 19338032Speter + mi.getLocks().size() + ") is incorrect in method \"" 19438032Speter + mi.getName() + "\""); 19538032Speter } 19638032Speter } 19738032Speter 19838032Speter private void haveToBeEmpty(MethodInfo mi) { 19938032Speter if (mi.getLocks().size() == 0) { 20038032Speter System.out.println("Method \"" + mi.getName() 20138032Speter + "\" does not lock anything - correct"); 20238032Speter } else { 20338032Speter throw new RuntimeException( 20438032Speter "Unexpected lock found in method \"" + mi.getName() + "\""); 20538032Speter } 20638032Speter } 20738032Speter 20838032Speter} 20938032Speter