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