DrainFindDeadlockTest.java revision 12745:f068a4ffddd2
1/*
2 * Copyright (c) 2013, 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 */
23import java.lang.management.ThreadInfo;
24import java.lang.management.ThreadMXBean;
25import java.lang.Thread.State;
26import java.io.IOException;
27import java.lang.management.ManagementFactory;
28import java.util.logging.LogManager;
29import java.util.logging.Logger;
30import java.util.Map;
31
32/**
33 * @test
34 * @bug 8010939
35 * @summary check for deadlock between findLogger() and drainLoggerRefQueueBounded()
36 * @author jim.gish@oracle.com
37 * @build DrainFindDeadlockTest
38 * @run main/othervm/timeout=10 DrainFindDeadlockTest
39 * @key randomness
40 */
41
42/**
43 * This test is checking for a deadlock between
44 * LogManager$LoggerContext.findLogger() and
45 * LogManager.drainLoggerRefQueueBounded() (which could happen by calling
46 * Logger.getLogger() and LogManager.readConfiguration() in different threads)
47 */
48public class DrainFindDeadlockTest {
49    private LogManager mgr = LogManager.getLogManager();
50    private static final int MAX_ITERATIONS = 100;
51
52    // Get a ThreadMXBean so we can check for deadlock.  N.B. this may
53    // not be supported on all platforms, which means we will have to
54    // resort to the traditional test timeout method. However, if
55    // we have the support we'll get the deadlock details if one
56    // is detected.
57    private static final ThreadMXBean threadMXBean =
58            ManagementFactory.getThreadMXBean();
59    private final boolean threadMXBeanDeadlockSupported =
60            threadMXBean.isSynchronizerUsageSupported();
61
62    public static void main(String... args) throws IOException, Exception {
63        new DrainFindDeadlockTest().testForDeadlock();
64    }
65
66    public static void randomDelay() {
67        int runs = (int) Math.random() * 1000000;
68        int c = 0;
69
70        for (int i=0; i<runs; ++i) {
71            c=c+i;
72        }
73    }
74
75    public void testForDeadlock() throws IOException, Exception {
76        System.out.println("Deadlock detection "
77                + (threadMXBeanDeadlockSupported ? "is" : "is not") +
78                            " available.");
79        Thread setup = new Thread(new SetupLogger(), "SetupLogger");
80        Thread readConfig = new Thread(new ReadConfig(), "ReadConfig");
81        Thread check = new Thread(new DeadlockChecker(setup, readConfig),
82                                   "DeadlockChecker");
83
84        // make the threads daemon threads so they will go away when the
85        // test exits
86        setup.setDaemon(true);
87        readConfig.setDaemon(true);
88        check.setDaemon(true);
89
90        check.start(); setup.start(); readConfig.start();
91        try {
92            check.join();
93        } catch (InterruptedException ex) {
94            ex.printStackTrace();
95        }
96        try {
97            readConfig.join();
98            setup.join();
99        } catch (InterruptedException ex) {
100            ex.printStackTrace();
101        }
102        System.out.println("Test passed");
103    }
104
105    class SetupLogger implements Runnable {
106        Logger logger = null;
107
108        @Override
109        public void run() {
110            System.out.println("Running " + Thread.currentThread().getName());
111
112            for (int i=0; i < MAX_ITERATIONS; i++) {
113                logger = Logger.getLogger("DrainFindDeadlockTest"+i);
114                DrainFindDeadlockTest.randomDelay();
115            }
116        }
117    }
118
119    class ReadConfig implements Runnable {
120        @Override
121        public void run() {
122            System.out.println("Running " + Thread.currentThread().getName());
123            for (int i=0; i < MAX_ITERATIONS; i++) {
124                try {
125                    mgr.readConfiguration();
126                } catch (IOException | SecurityException ex) {
127                    throw new RuntimeException("FAILED: test setup problem", ex);
128                }
129                DrainFindDeadlockTest.randomDelay();
130            }
131        }
132    }
133
134    class DeadlockChecker implements Runnable {
135        Thread t1, t2;
136
137        DeadlockChecker(Thread t1, Thread t2) {
138            this.t1 = t1;
139            this.t2 = t2;
140        }
141
142        void checkState(Thread x, Thread y) {
143            //            System.out.println("checkstate");
144            boolean isXblocked = x.getState().equals(State.BLOCKED);
145            boolean isYblocked = y.getState().equals(State.BLOCKED);
146            long[] deadlockedThreads = null;
147
148            if (isXblocked && isYblocked) {
149                System.out.println("threads blocked");
150                // they are both blocked, but this doesn't necessarily mean
151                // they are deadlocked
152                if (threadMXBeanDeadlockSupported) {
153                    System.out.println("checking for deadlock");
154                    deadlockedThreads = threadMXBean.findDeadlockedThreads();
155                } else {
156                    System.out.println("Can't check for deadlock");
157                }
158                if (deadlockedThreads != null) {
159                    System.out.println("We detected a deadlock! ");
160                    ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(
161                            deadlockedThreads, true, true);
162                    for (ThreadInfo threadInfo: threadInfos) {
163                        System.out.println(threadInfo);
164                    }
165                    throw new RuntimeException("TEST FAILED: Deadlock detected");
166                }
167                System.out.println("We may have a deadlock");
168                Map<Thread, StackTraceElement[]> threadMap =
169                        Thread.getAllStackTraces();
170                dumpStack(threadMap.get(x), x);
171                dumpStack(threadMap.get(y), y);
172            }
173        }
174
175        private void dumpStack(StackTraceElement[] aStackElt, Thread aThread) {
176            if (aStackElt != null) {
177                 System.out.println("Thread:" + aThread.getName() + ": " +
178                                    aThread.getState());
179                 for (StackTraceElement element: aStackElt) {
180                    System.out.println("   " + element);
181                 }
182            }
183        }
184
185        @Override
186        public void run() {
187            System.out.println("Running " + Thread.currentThread().getName());
188            for (int i=0; i < MAX_ITERATIONS*2; i++) {
189                checkState(t1, t2);
190                try {
191                    Thread.sleep(10);
192                } catch (InterruptedException ex) {
193                };
194            }
195        }
196    }
197}
198