0N/A/*
2362N/A * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A/*
0N/A * @summary SynchronizerDeadlock creates threads that are deadlocked
0N/A * waiting for JSR-166 synchronizers.
0N/A * @author Mandy Chung
0N/A * @build Barrier
0N/A */
0N/A
0N/Aimport java.lang.management.*;
0N/Aimport java.util.*;
0N/Aimport java.util.concurrent.locks.*;
0N/A
0N/Apublic class SynchronizerDeadlock {
0N/A
0N/A private Lock a = new ReentrantLock();
0N/A private Lock b = new ReentrantLock();
0N/A private Lock c = new ReentrantLock();
0N/A private final int EXPECTED_THREADS = 3;
0N/A private Thread[] dThreads = new Thread[EXPECTED_THREADS];
0N/A private Barrier go = new Barrier(1);
0N/A private Barrier barr = new Barrier(EXPECTED_THREADS);
0N/A
0N/A public SynchronizerDeadlock() {
0N/A dThreads[0] = new DeadlockingThread("Deadlock-Thread-1", a, b);
0N/A dThreads[1] = new DeadlockingThread("Deadlock-Thread-2", b, c);
0N/A dThreads[2] = new DeadlockingThread("Deadlock-Thread-3", c, a);
0N/A
0N/A // make them daemon threads so that the test will exit
0N/A for (int i = 0; i < EXPECTED_THREADS; i++) {
0N/A dThreads[i].setDaemon(true);
0N/A dThreads[i].start();
0N/A }
0N/A }
0N/A
0N/A void goDeadlock() {
0N/A // Wait until all threads have started
0N/A barr.await();
0N/A
0N/A // reset for later signals
0N/A barr.set(EXPECTED_THREADS);
0N/A
0N/A while (go.getWaiterCount() != EXPECTED_THREADS) {
0N/A synchronized(this) {
0N/A try {
0N/A wait(100);
0N/A } catch (InterruptedException e) {
0N/A // ignore
0N/A }
0N/A }
0N/A }
0N/A
0N/A // sleep a little so that all threads are blocked before notified.
0N/A try {
0N/A Thread.sleep(100);
0N/A } catch (InterruptedException e) {
0N/A // ignore
0N/A }
0N/A go.signal();
0N/A
0N/A }
0N/A
0N/A void waitUntilDeadlock() {
0N/A barr.await();
1258N/A
1258N/A for (int i=0; i < 100; i++) {
1258N/A // sleep a little while to wait until threads are blocked.
1258N/A try {
1258N/A Thread.sleep(100);
1258N/A } catch (InterruptedException e) {
1258N/A // ignore
1258N/A }
1258N/A boolean retry = false;
1258N/A for (Thread t: dThreads) {
1258N/A if (t.getState() == Thread.State.RUNNABLE) {
1258N/A retry = true;
1258N/A break;
1258N/A }
1258N/A }
1258N/A if (!retry) {
1258N/A break;
1258N/A }
0N/A }
0N/A }
0N/A
0N/A private class DeadlockingThread extends Thread {
0N/A private final Lock lock1;
0N/A private final Lock lock2;
0N/A
0N/A DeadlockingThread(String name, Lock lock1, Lock lock2) {
0N/A super(name);
0N/A this.lock1 = lock1;
0N/A this.lock2 = lock2;
0N/A }
0N/A public void run() {
0N/A f();
0N/A }
0N/A private void f() {
0N/A lock1.lock();
0N/A try {
0N/A barr.signal();
0N/A go.await();
0N/A g();
0N/A } finally {
0N/A lock1.unlock();
0N/A }
0N/A }
0N/A private void g() {
0N/A barr.signal();
0N/A lock2.lock();
0N/A throw new RuntimeException("should not reach here.");
0N/A }
0N/A }
0N/A
0N/A void checkResult(long[] threads) {
0N/A if (threads.length != EXPECTED_THREADS) {
0N/A ThreadDump.threadDump();
0N/A throw new RuntimeException("Expected to have " +
0N/A EXPECTED_THREADS + " to be in the deadlock list");
0N/A }
0N/A boolean[] found = new boolean[EXPECTED_THREADS];
0N/A for (int i = 0; i < threads.length; i++) {
0N/A for (int j = 0; j < dThreads.length; j++) {
0N/A if (dThreads[j].getId() == threads[i]) {
0N/A found[j] = true;
0N/A }
0N/A }
0N/A }
0N/A boolean ok = true;
0N/A for (int j = 0; j < found.length; j++) {
0N/A ok = ok && found[j];
0N/A }
0N/A
0N/A if (!ok) {
0N/A System.out.print("Returned result is [");
0N/A for (int j = 0; j < threads.length; j++) {
0N/A System.out.print(threads[j] + " ");
0N/A }
0N/A System.out.println("]");
0N/A
0N/A System.out.print("Expected result is [");
0N/A for (int j = 0; j < threads.length; j++) {
0N/A System.out.print(dThreads[j] + " ");
0N/A }
0N/A System.out.println("]");
0N/A throw new RuntimeException("Unexpected result returned " +
0N/A " by findMonitorDeadlockedThreads method.");
0N/A }
0N/A }
0N/A}