test/java/util/logging/DrainFindDeadlockTest.java

Print this page

        

*** 56,65 **** --- 56,68 ---- private final static ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean(); private final boolean threadMXBeanDeadlockSupported = threadMXBean.isSynchronizerUsageSupported(); + private volatile boolean terminate = false; + private volatile Exception failed = null; + public static void main(String... args) throws IOException, Exception { new DrainFindDeadlockTest().testForDeadlock(); } public static void randomDelay() {
*** 69,78 **** --- 72,90 ---- for (int i=0; i<runs; ++i) { c=c+i; } } + public void fail(Exception failure) { + if (failed == null) { + failed = failure; + } else { + failure.printStackTrace(); + } + terminate = true; + } + public void testForDeadlock() throws IOException, Exception { System.out.println("Deadlock detection " + (threadMXBeanDeadlockSupported ? "is" : "is not") + " available."); Thread setup = new Thread(new SetupLogger(), "SetupLogger");
*** 90,177 **** try { check.join(); } catch (InterruptedException ex) { ex.printStackTrace(); } try { readConfig.join(); setup.join(); } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println("Test passed"); } class SetupLogger implements Runnable { Logger logger = null; @Override public void run() { System.out.println("Running " + Thread.currentThread().getName()); ! ! for (int i=0; i < MAX_ITERATIONS; i++) { ! logger = Logger.getLogger("DrainFindDeadlockTest"+i); DrainFindDeadlockTest.randomDelay(); } } } class ReadConfig implements Runnable { @Override public void run() { System.out.println("Running " + Thread.currentThread().getName()); ! for (int i=0; i < MAX_ITERATIONS; i++) { try { mgr.readConfiguration(); } catch (IOException | SecurityException ex) { ! throw new RuntimeException("FAILED: test setup problem", ex); } DrainFindDeadlockTest.randomDelay(); } } } class DeadlockChecker implements Runnable { ! Thread t1, t2; ! DeadlockChecker(Thread t1, Thread t2) { ! this.t1 = t1; ! this.t2 = t2; } ! void checkState(Thread x, Thread y) { // System.out.println("checkstate"); boolean isXblocked = x.getState().equals(State.BLOCKED); boolean isYblocked = y.getState().equals(State.BLOCKED); long[] deadlockedThreads = null; if (isXblocked && isYblocked) { System.out.println("threads blocked"); // they are both blocked, but this doesn't necessarily mean // they are deadlocked if (threadMXBeanDeadlockSupported) { ! System.out.println("checking for deadlock"); ! deadlockedThreads = threadMXBean.findDeadlockedThreads(); } else { System.out.println("Can't check for deadlock"); } if (deadlockedThreads != null) { System.out.println("We detected a deadlock! "); ThreadInfo[] threadInfos = threadMXBean.getThreadInfo( deadlockedThreads, true, true); for (ThreadInfo threadInfo: threadInfos) { ! System.out.println(threadInfo); } ! throw new RuntimeException("TEST FAILED: Deadlock detected"); } System.out.println("We may have a deadlock"); Map<Thread, StackTraceElement[]> threadMap = Thread.getAllStackTraces(); dumpStack(threadMap.get(x), x); dumpStack(threadMap.get(y), y); } } private void dumpStack(StackTraceElement[] aStackElt, Thread aThread) { if (aStackElt != null) { System.out.println("Thread:" + aThread.getName() + ": " + aThread.getState()); --- 102,244 ---- try { check.join(); } catch (InterruptedException ex) { ex.printStackTrace(); } + + if (failed == null) { + terminate = true; try { readConfig.join(); setup.join(); } catch (InterruptedException ex) { ex.printStackTrace(); } System.out.println("Test passed"); + } else { + System.err.println("Test Failed: " + failed); + throw failed; + } } class SetupLogger implements Runnable { Logger logger = null; @Override public void run() { System.out.println("Running " + Thread.currentThread().getName()); ! int i = 0; ! while (!terminate) { ! logger = Logger.getLogger("DrainFindDeadlockTest"+(i++)); DrainFindDeadlockTest.randomDelay(); } } } class ReadConfig implements Runnable { @Override public void run() { System.out.println("Running " + Thread.currentThread().getName()); ! while (!terminate) { try { mgr.readConfiguration(); } catch (IOException | SecurityException ex) { ! fail(new RuntimeException("FAILED: test setup problem", ex)); } DrainFindDeadlockTest.randomDelay(); } } } class DeadlockChecker implements Runnable { ! final Thread x, y; ! final long[] threadIds; DeadlockChecker(Thread t1, Thread t2) { ! this.x = t1; ! this.y = t2; ! threadIds = new long[] { t1.getId(), t2.getId() }; ! } ! ! boolean threadsBlocked(ThreadInfo[] xyThreadInfos) { ! for (ThreadInfo threadInfo : xyThreadInfos) { ! switch (threadInfo.getThreadState()) { ! case BLOCKED: ! case WAITING: ! case TIMED_WAITING: ! continue; ! default: ! System.out.println("Thread " + threadInfo.getThreadName() + ! " is not blocked: " + threadInfo.getThreadState()); ! return false; ! } ! } ! return xyThreadInfos.length > 0; ! } ! ! long[] findDeadlockedThreads() { ! // It seems that calling ThreadMXBean.findDeadlockedThreads() ! // is not always reliable. Until that is fixed we will only ! // call it if we find that our two threads are simultaneously ! // BLOCKED or WAITING. ! System.out.println("checking thread infos"); ! ThreadInfo[] xyThreadInfos = threadMXBean.getThreadInfo(threadIds, true, true); ! if (!threadsBlocked(xyThreadInfos)) return null; ! /* ! if (xyThreadInfo != null && xyThreadInfos.length == 2) { ! if (xyThreadInfo[0].getLockOwnerId() != xyThreadInfo[1].getThreadId()) { ! return null; ! } ! if (xyThreadInfo[1].getLockOwnerId() != xyThreadInfo[0].getThreadId()) { ! return null; ! } ! } ! */ ! System.out.println("checking for deadlock"); ! long[] deadlockedThreads = threadMXBean.findDeadlockedThreads(); ! if (deadlockedThreads != null) { ! xyThreadInfos = threadMXBean.getThreadInfo(deadlockedThreads, true, true); ! if (!threadsBlocked(xyThreadInfos)) return null; ! } ! return deadlockedThreads; } ! void checkState() { // System.out.println("checkstate"); boolean isXblocked = x.getState().equals(State.BLOCKED); boolean isYblocked = y.getState().equals(State.BLOCKED); long[] deadlockedThreads = null; if (isXblocked && isYblocked) { System.out.println("threads blocked"); // they are both blocked, but this doesn't necessarily mean // they are deadlocked if (threadMXBeanDeadlockSupported) { ! deadlockedThreads = findDeadlockedThreads(); } else { System.out.println("Can't check for deadlock"); } if (deadlockedThreads != null) { System.out.println("We detected a deadlock! "); ThreadInfo[] threadInfos = threadMXBean.getThreadInfo( deadlockedThreads, true, true); for (ThreadInfo threadInfo: threadInfos) { ! System.out.println("Thread " + threadInfo.getThreadName() + " blocked on " + ! threadInfo.getLockName() + " owned by " + threadInfo.getLockOwnerName()); } ! for (ThreadInfo threadInfo: threadInfos) { ! System.out.println(threadInfo); } + fail(new RuntimeException("TEST FAILED: Deadlock detected")); + } else if (!threadMXBeanDeadlockSupported) { System.out.println("We may have a deadlock"); Map<Thread, StackTraceElement[]> threadMap = Thread.getAllStackTraces(); dumpStack(threadMap.get(x), x); dumpStack(threadMap.get(y), y); } } + } private void dumpStack(StackTraceElement[] aStackElt, Thread aThread) { if (aStackElt != null) { System.out.println("Thread:" + aThread.getName() + ": " + aThread.getState());
*** 183,193 **** @Override public void run() { System.out.println("Running " + Thread.currentThread().getName()); for (int i=0; i < MAX_ITERATIONS*2; i++) { ! checkState(t1, t2); try { Thread.sleep(10); } catch (InterruptedException ex) { }; } --- 250,261 ---- @Override public void run() { System.out.println("Running " + Thread.currentThread().getName()); for (int i=0; i < MAX_ITERATIONS*2; i++) { ! if (terminate) return; ! checkState(); try { Thread.sleep(10); } catch (InterruptedException ex) { }; }