1/*
2 * Copyright (c) 2005, 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 * @summary MonitorDeadlock creates threads that are deadlocked on
26 *          object monitors.
27 * @author  Mandy Chung
28 * @build Barrier
29 */
30
31import java.lang.management.*;
32import java.util.*;
33
34public class MonitorDeadlock {
35
36    private final int EXPECTED_THREADS = 3;
37    private Barrier go = new Barrier(1);
38    private Barrier barr = new Barrier(EXPECTED_THREADS);
39
40    private Object a = new Object();
41    private Object b = new Object();
42    private Object c = new Object();
43    private Thread[] dThreads = new Thread[EXPECTED_THREADS];
44
45    public MonitorDeadlock() {
46        dThreads[0] = new DeadlockingThread("MThread-1", a, b);
47        dThreads[1] = new DeadlockingThread("MThread-2", b, c);
48        dThreads[2] = new DeadlockingThread("MThread-3", c, a);
49
50        // make them daemon threads so that the test will exit
51        for (int i = 0; i < EXPECTED_THREADS; i++) {
52            dThreads[i].setDaemon(true);
53            dThreads[i].start();
54        }
55    }
56
57    void goDeadlock() {
58        // Wait until all threads have started
59        barr.await();
60
61        // reset for later signals
62        barr.set(EXPECTED_THREADS);
63
64        while (go.getWaiterCount() != EXPECTED_THREADS) {
65            synchronized(this) {
66                try {
67                    wait(100);
68                } catch (InterruptedException e) {
69                    // ignore
70                }
71            }
72        }
73
74        // sleep a little so that all threads are blocked before notified.
75        try {
76            Thread.sleep(100);
77        } catch (InterruptedException e) {
78            // ignore
79        }
80        go.signal();
81
82    }
83
84    void waitUntilDeadlock() {
85        barr.await();
86
87        for (int i=0; i < 100; i++) {
88            // sleep a little while to wait until threads are blocked.
89            try {
90                Thread.sleep(100);
91            } catch (InterruptedException e) {
92                // ignore
93            }
94            boolean retry = false;
95            for (Thread t: dThreads) {
96                if (t.getState() == Thread.State.RUNNABLE) {
97                    retry = true;
98                    break;
99                }
100            }
101            if (!retry) {
102                break;
103            }
104        }
105    }
106
107    private class DeadlockingThread extends Thread {
108        private final Object lock1;
109        private final Object lock2;
110
111        DeadlockingThread(String name, Object lock1, Object lock2) {
112            super(name);
113            this.lock1 = lock1;
114            this.lock2 = lock2;
115        }
116        public void run() {
117            f();
118        }
119        private void f() {
120            synchronized (lock1) {
121                barr.signal();
122                go.await();
123                g();
124            }
125        }
126        private void g() {
127            barr.signal();
128            synchronized (lock2) {
129                throw new RuntimeException("should not reach here.");
130            }
131        }
132    }
133
134    void checkResult(long[] threads) {
135        if (threads.length != EXPECTED_THREADS) {
136            throw new RuntimeException("Expected to have " +
137                EXPECTED_THREADS + " to be in the deadlock list");
138        }
139        boolean[] found = new boolean[EXPECTED_THREADS];
140        for (int i = 0; i < threads.length; i++) {
141            for (int j = 0; j < dThreads.length; j++) {
142                if (dThreads[j].getId() == threads[i]) {
143                    found[j] = true;
144                }
145            }
146        }
147        boolean ok = true;
148        for (int j = 0; j < found.length; j++) {
149            ok = ok && found[j];
150        }
151
152        if (!ok) {
153            System.out.print("Returned result is [");
154            for (int j = 0; j < threads.length; j++) {
155                System.out.print(threads[j] + " ");
156            }
157            System.out.println("]");
158
159            System.out.print("Expected result is [");
160            for (int j = 0; j < threads.length; j++) {
161                System.out.print(dThreads[j] + " ");
162            }
163            System.out.println("]");
164            throw new RuntimeException("Unexpected result returned " +
165                " by findMonitorDeadlockedThreads method.");
166        }
167    }
168}
169