41 /** 42 * This test is checking for a deadlock between 43 * LogManager$LoggerContext.findLogger() and 44 * LogManager.drainLoggerRefQueueBounded() (which could happen by calling 45 * Logger.getLogger() and LogManager.readConfiguration() in different threads) 46 */ 47 public class DrainFindDeadlockTest { 48 private LogManager mgr = LogManager.getLogManager(); 49 private final static int MAX_ITERATIONS = 100; 50 51 // Get a ThreadMXBean so we can check for deadlock. N.B. this may 52 // not be supported on all platforms, which means we will have to 53 // resort to the traditional test timeout method. However, if 54 // we have the support we'll get the deadlock details if one 55 // is detected. 56 private final static ThreadMXBean threadMXBean = 57 ManagementFactory.getThreadMXBean(); 58 private final boolean threadMXBeanDeadlockSupported = 59 threadMXBean.isSynchronizerUsageSupported(); 60 61 public static void main(String... args) throws IOException, Exception { 62 new DrainFindDeadlockTest().testForDeadlock(); 63 } 64 65 public static void randomDelay() { 66 int runs = (int) Math.random() * 1000000; 67 int c = 0; 68 69 for (int i=0; i<runs; ++i) { 70 c=c+i; 71 } 72 } 73 74 public void testForDeadlock() throws IOException, Exception { 75 System.out.println("Deadlock detection " 76 + (threadMXBeanDeadlockSupported ? "is" : "is not") + 77 " available."); 78 Thread setup = new Thread(new SetupLogger(), "SetupLogger"); 79 Thread readConfig = new Thread(new ReadConfig(), "ReadConfig"); 80 Thread check = new Thread(new DeadlockChecker(setup, readConfig), 81 "DeadlockChecker"); 82 83 // make the threads daemon threads so they will go away when the 84 // test exits 85 setup.setDaemon(true); 86 readConfig.setDaemon(true); 87 check.setDaemon(true); 88 89 check.start(); setup.start(); readConfig.start(); 90 try { 91 check.join(); 92 } catch (InterruptedException ex) { 93 ex.printStackTrace(); 94 } 95 try { 96 readConfig.join(); 97 setup.join(); 98 } catch (InterruptedException ex) { 99 ex.printStackTrace(); 100 } 101 System.out.println("Test passed"); 102 } 103 104 class SetupLogger implements Runnable { 105 Logger logger = null; 106 107 @Override 108 public void run() { 109 System.out.println("Running " + Thread.currentThread().getName()); 110 111 for (int i=0; i < MAX_ITERATIONS; i++) { 112 logger = Logger.getLogger("DrainFindDeadlockTest"+i); 113 DrainFindDeadlockTest.randomDelay(); 114 } 115 } 116 } 117 118 class ReadConfig implements Runnable { 119 @Override 120 public void run() { 121 System.out.println("Running " + Thread.currentThread().getName()); 122 for (int i=0; i < MAX_ITERATIONS; i++) { 123 try { 124 mgr.readConfiguration(); 125 } catch (IOException | SecurityException ex) { 126 throw new RuntimeException("FAILED: test setup problem", ex); 127 } 128 DrainFindDeadlockTest.randomDelay(); 129 } 130 } 131 } 132 133 class DeadlockChecker implements Runnable { 134 Thread t1, t2; 135 136 DeadlockChecker(Thread t1, Thread t2) { 137 this.t1 = t1; 138 this.t2 = t2; 139 } 140 141 void checkState(Thread x, Thread y) { 142 // System.out.println("checkstate"); 143 boolean isXblocked = x.getState().equals(State.BLOCKED); 144 boolean isYblocked = y.getState().equals(State.BLOCKED); 145 long[] deadlockedThreads = null; 146 147 if (isXblocked && isYblocked) { 148 System.out.println("threads blocked"); 149 // they are both blocked, but this doesn't necessarily mean 150 // they are deadlocked 151 if (threadMXBeanDeadlockSupported) { 152 System.out.println("checking for deadlock"); 153 deadlockedThreads = threadMXBean.findDeadlockedThreads(); 154 } else { 155 System.out.println("Can't check for deadlock"); 156 } 157 if (deadlockedThreads != null) { 158 System.out.println("We detected a deadlock! "); 159 ThreadInfo[] threadInfos = threadMXBean.getThreadInfo( 160 deadlockedThreads, true, true); 161 for (ThreadInfo threadInfo: threadInfos) { 162 System.out.println(threadInfo); 163 } 164 throw new RuntimeException("TEST FAILED: Deadlock detected"); 165 } 166 System.out.println("We may have a deadlock"); 167 Map<Thread, StackTraceElement[]> threadMap = 168 Thread.getAllStackTraces(); 169 dumpStack(threadMap.get(x), x); 170 dumpStack(threadMap.get(y), y); 171 } 172 } 173 174 private void dumpStack(StackTraceElement[] aStackElt, Thread aThread) { 175 if (aStackElt != null) { 176 System.out.println("Thread:" + aThread.getName() + ": " + 177 aThread.getState()); 178 for (StackTraceElement element: aStackElt) { 179 System.out.println(" " + element); 180 } 181 } 182 } 183 184 @Override 185 public void run() { 186 System.out.println("Running " + Thread.currentThread().getName()); 187 for (int i=0; i < MAX_ITERATIONS*2; i++) { 188 checkState(t1, t2); 189 try { 190 Thread.sleep(10); 191 } catch (InterruptedException ex) { 192 }; 193 } 194 } 195 } 196 } | 41 /** 42 * This test is checking for a deadlock between 43 * LogManager$LoggerContext.findLogger() and 44 * LogManager.drainLoggerRefQueueBounded() (which could happen by calling 45 * Logger.getLogger() and LogManager.readConfiguration() in different threads) 46 */ 47 public class DrainFindDeadlockTest { 48 private LogManager mgr = LogManager.getLogManager(); 49 private final static int MAX_ITERATIONS = 100; 50 51 // Get a ThreadMXBean so we can check for deadlock. N.B. this may 52 // not be supported on all platforms, which means we will have to 53 // resort to the traditional test timeout method. However, if 54 // we have the support we'll get the deadlock details if one 55 // is detected. 56 private final static ThreadMXBean threadMXBean = 57 ManagementFactory.getThreadMXBean(); 58 private final boolean threadMXBeanDeadlockSupported = 59 threadMXBean.isSynchronizerUsageSupported(); 60 61 private volatile boolean terminate = false; 62 private volatile Exception failed = null; 63 64 public static void main(String... args) throws IOException, Exception { 65 new DrainFindDeadlockTest().testForDeadlock(); 66 } 67 68 public static void randomDelay() { 69 int runs = (int) Math.random() * 1000000; 70 int c = 0; 71 72 for (int i=0; i<runs; ++i) { 73 c=c+i; 74 } 75 } 76 77 public void fail(Exception failure) { 78 if (failed == null) { 79 failed = failure; 80 } else { 81 failure.printStackTrace(); 82 } 83 terminate = true; 84 } 85 86 public void testForDeadlock() throws IOException, Exception { 87 System.out.println("Deadlock detection " 88 + (threadMXBeanDeadlockSupported ? "is" : "is not") + 89 " available."); 90 Thread setup = new Thread(new SetupLogger(), "SetupLogger"); 91 Thread readConfig = new Thread(new ReadConfig(), "ReadConfig"); 92 Thread check = new Thread(new DeadlockChecker(setup, readConfig), 93 "DeadlockChecker"); 94 95 // make the threads daemon threads so they will go away when the 96 // test exits 97 setup.setDaemon(true); 98 readConfig.setDaemon(true); 99 check.setDaemon(true); 100 101 check.start(); setup.start(); readConfig.start(); 102 try { 103 check.join(); 104 } catch (InterruptedException ex) { 105 ex.printStackTrace(); 106 } 107 108 if (failed == null) { 109 terminate = true; 110 try { 111 readConfig.join(); 112 setup.join(); 113 } catch (InterruptedException ex) { 114 ex.printStackTrace(); 115 } 116 System.out.println("Test passed"); 117 } else { 118 System.err.println("Test Failed: " + failed); 119 throw failed; 120 } 121 } 122 123 class SetupLogger implements Runnable { 124 Logger logger = null; 125 126 @Override 127 public void run() { 128 System.out.println("Running " + Thread.currentThread().getName()); 129 int i = 0; 130 while (!terminate) { 131 logger = Logger.getLogger("DrainFindDeadlockTest"+(i++)); 132 DrainFindDeadlockTest.randomDelay(); 133 } 134 } 135 } 136 137 class ReadConfig implements Runnable { 138 @Override 139 public void run() { 140 System.out.println("Running " + Thread.currentThread().getName()); 141 while (!terminate) { 142 try { 143 mgr.readConfiguration(); 144 } catch (IOException | SecurityException ex) { 145 fail(new RuntimeException("FAILED: test setup problem", ex)); 146 } 147 DrainFindDeadlockTest.randomDelay(); 148 } 149 } 150 } 151 152 class DeadlockChecker implements Runnable { 153 final Thread x, y; 154 final long[] threadIds; 155 DeadlockChecker(Thread t1, Thread t2) { 156 this.x = t1; 157 this.y = t2; 158 threadIds = new long[] { t1.getId(), t2.getId() }; 159 } 160 161 boolean threadsBlocked(ThreadInfo[] xyThreadInfos) { 162 for (ThreadInfo threadInfo : xyThreadInfos) { 163 switch (threadInfo.getThreadState()) { 164 case BLOCKED: 165 case WAITING: 166 case TIMED_WAITING: 167 continue; 168 default: 169 System.out.println("Thread " + threadInfo.getThreadName() + 170 " is not blocked: " + threadInfo.getThreadState()); 171 return false; 172 } 173 } 174 return xyThreadInfos.length > 0; 175 } 176 177 long[] findDeadlockedThreads() { 178 // It seems that calling ThreadMXBean.findDeadlockedThreads() 179 // is not always reliable. Until that is fixed we will only 180 // call it if we find that our two threads are simultaneously 181 // BLOCKED or WAITING. 182 System.out.println("checking thread infos"); 183 ThreadInfo[] xyThreadInfos = threadMXBean.getThreadInfo(threadIds, true, true); 184 if (!threadsBlocked(xyThreadInfos)) return null; 185 /* 186 if (xyThreadInfo != null && xyThreadInfos.length == 2) { 187 if (xyThreadInfo[0].getLockOwnerId() != xyThreadInfo[1].getThreadId()) { 188 return null; 189 } 190 if (xyThreadInfo[1].getLockOwnerId() != xyThreadInfo[0].getThreadId()) { 191 return null; 192 } 193 } 194 */ 195 System.out.println("checking for deadlock"); 196 long[] deadlockedThreads = threadMXBean.findDeadlockedThreads(); 197 if (deadlockedThreads != null) { 198 xyThreadInfos = threadMXBean.getThreadInfo(deadlockedThreads, true, true); 199 if (!threadsBlocked(xyThreadInfos)) return null; 200 } 201 return deadlockedThreads; 202 } 203 204 void checkState() { 205 // System.out.println("checkstate"); 206 boolean isXblocked = x.getState().equals(State.BLOCKED); 207 boolean isYblocked = y.getState().equals(State.BLOCKED); 208 long[] deadlockedThreads = null; 209 210 if (isXblocked && isYblocked) { 211 System.out.println("threads blocked"); 212 // they are both blocked, but this doesn't necessarily mean 213 // they are deadlocked 214 if (threadMXBeanDeadlockSupported) { 215 deadlockedThreads = findDeadlockedThreads(); 216 } else { 217 System.out.println("Can't check for deadlock"); 218 } 219 if (deadlockedThreads != null) { 220 System.out.println("We detected a deadlock! "); 221 ThreadInfo[] threadInfos = threadMXBean.getThreadInfo( 222 deadlockedThreads, true, true); 223 for (ThreadInfo threadInfo: threadInfos) { 224 System.out.println("Thread " + threadInfo.getThreadName() + " blocked on " + 225 threadInfo.getLockName() + " owned by " + threadInfo.getLockOwnerName()); 226 } 227 for (ThreadInfo threadInfo: threadInfos) { 228 System.out.println(threadInfo); 229 } 230 fail(new RuntimeException("TEST FAILED: Deadlock detected")); 231 } else if (!threadMXBeanDeadlockSupported) { 232 System.out.println("We may have a deadlock"); 233 Map<Thread, StackTraceElement[]> threadMap = 234 Thread.getAllStackTraces(); 235 dumpStack(threadMap.get(x), x); 236 dumpStack(threadMap.get(y), y); 237 } 238 } 239 } 240 241 private void dumpStack(StackTraceElement[] aStackElt, Thread aThread) { 242 if (aStackElt != null) { 243 System.out.println("Thread:" + aThread.getName() + ": " + 244 aThread.getState()); 245 for (StackTraceElement element: aStackElt) { 246 System.out.println(" " + element); 247 } 248 } 249 } 250 251 @Override 252 public void run() { 253 System.out.println("Running " + Thread.currentThread().getName()); 254 for (int i=0; i < MAX_ITERATIONS*2; i++) { 255 if (terminate) return; 256 checkState(); 257 try { 258 Thread.sleep(10); 259 } catch (InterruptedException ex) { 260 }; 261 } 262 } 263 } 264 } |