# HG changeset patch # User sla # Date 1371486944 -7200 # Node ID ef748153ee8f88226b38fb8d44bd11791da95e00 # Parent cd2118b62475025daa2cda79fa21718dc166a9fd 8016304: ThreadMXBean.getDeadlockedThreads reports bogus deadlocks on JDK 8 Reviewed-by: dcubed, mgronlun diff -r cd2118b62475 -r ef748153ee8f src/share/vm/services/threadService.cpp --- a/src/share/vm/services/threadService.cpp Mon Jun 10 10:45:19 2013 -0400 +++ b/src/share/vm/services/threadService.cpp Mon Jun 17 18:35:44 2013 +0200 @@ -327,27 +327,30 @@ while (waitingToLockMonitor != NULL || waitingToLockBlocker != NULL) { cycle->add_thread(currentThread); if (waitingToLockMonitor != NULL) { - currentThread = Threads::owning_thread_from_monitor_owner( - (address)waitingToLockMonitor->owner(), - false /* no locking needed */); - if (currentThread == NULL) { - // This function is called at a safepoint so the JavaThread - // that owns waitingToLockMonitor should be findable, but - // if it is not findable, then the previous currentThread is - // blocked permanently. We record this as a deadlock. - num_deadlocks++; + address currentOwner = (address)waitingToLockMonitor->owner(); + if (currentOwner != NULL) { + currentThread = Threads::owning_thread_from_monitor_owner( + currentOwner, + false /* no locking needed */); + if (currentThread == NULL) { + // This function is called at a safepoint so the JavaThread + // that owns waitingToLockMonitor should be findable, but + // if it is not findable, then the previous currentThread is + // blocked permanently. We record this as a deadlock. + num_deadlocks++; - cycle->set_deadlock(true); + cycle->set_deadlock(true); - // add this cycle to the deadlocks list - if (deadlocks == NULL) { - deadlocks = cycle; - } else { - last->set_next(cycle); + // add this cycle to the deadlocks list + if (deadlocks == NULL) { + deadlocks = cycle; + } else { + last->set_next(cycle); + } + last = cycle; + cycle = new DeadlockCycle(); + break; } - last = cycle; - cycle = new DeadlockCycle(); - break; } } else { if (concurrent_locks) { diff -r cd2118b62475 -r ef748153ee8f test/serviceability/threads/TestFalseDeadLock.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/serviceability/threads/TestFalseDeadLock.java Mon Jun 17 18:35:44 2013 +0200 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.ThreadMXBean; +import java.util.Random; + +/* + * @test + * @bug 8016304 + * @summary Make sure no deadlock is reported for this program which has no deadlocks. + * @run main/othervm TestFalseDeadLock + */ + +/* + * This test will not provoke the bug every time it is run since the bug is intermittent. + * The test has a fixed running time of 5 seconds. + */ + +public class TestFalseDeadLock { + private static ThreadMXBean bean; + private static volatile boolean running = true; + private static volatile boolean found = false; + + public static void main(String[] args) throws Exception { + bean = ManagementFactory.getThreadMXBean(); + Thread[] threads = new Thread[500]; + for (int i = 0; i < threads.length; i++) { + Test t = new Test(); + threads[i] = new Thread(t); + threads[i].start(); + } + try { + Thread.sleep(5000); + } catch (InterruptedException ex) { + } + running = false; + for (Thread t : threads) { + t.join(); + } + if (found) { + throw new Exception("Deadlock reported, but there is no deadlock."); + } + } + + public static class Test implements Runnable { + public void run() { + Random r = new Random(); + while (running) { + try { + synchronized (this) { + wait(r.nextInt(1000) + 1); + } + } catch (InterruptedException ex) { + } + recurse(2000); + } + if (bean.findDeadlockedThreads() != null) { + System.out.println("FOUND!"); + found = true; + } + } + + private void recurse(int i) { + if (!running) { + // It is important for the test to call println here + // since there are locks inside that path. + System.out.println("Hullo"); + } + else if (i > 0) { + recurse(i - 1); + } + } + } +}