1 /* 2 * Copyright (c) 2013, 2016, 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 */ 23 import java.lang.management.ManagementFactory; 24 import java.lang.management.ThreadInfo; 25 import java.security.Permission; 26 import java.security.Policy; 27 import java.security.ProtectionDomain; 28 import java.util.ArrayList; 29 import java.util.List; 30 import java.util.concurrent.atomic.AtomicLong; 31 import java.util.logging.LogManager; 32 import java.util.logging.Logger; 33 34 35 /** 36 * @test 37 * @bug 8029281 8027670 38 * @summary Synchronization issues in Logger and LogManager. This test 39 * focusses more particularly on potential deadlock in 40 * drainLoggerRefQueueBounded / readConfiguration 41 * @modules java.logging 42 * java.management 43 * @run main/othervm TestLogConfigurationDeadLock 44 * @author danielfuchs 45 */ 46 // This test is a best effort to try & detect issues. The test itself will run 47 // for 8secs. This is usually unsufficient to detect issues. 48 // To get a greater confidence it is recommended to run this test in a loop: 49 // e.g. use something like: 50 // $ while jtreg -jdk:$JDK -verbose:all \ 51 // test/java/util/logging/TestLogConfigurationDeadLock.java ; \ 52 // do echo Running test again ; done 53 // and let it run for a few hours... 54 // 55 public class TestLogConfigurationDeadLock { 56 57 static volatile Exception thrown = null; 58 static volatile boolean goOn = true; 59 60 static final int READERS = 2; 61 static final int LOGGERS = 2; 62 static final long TIME = 4 * 1000; // 4 sec. 63 static final long STEP = 1 * 1000; // message every 1 sec. 64 static final int LCOUNT = 50; // 50 loggers created in a row... 65 static final AtomicLong nextLogger = new AtomicLong(0); 66 static final AtomicLong readCount = new AtomicLong(0); 67 static final AtomicLong checkCount = new AtomicLong(0); 68 69 /** 70 * This test will run both with and without a security manager. 71 * 72 * The test starts a number of threads that will call 73 * LogManager.readConfiguration() concurrently (ReadConf), then starts 74 * a number of threads that will create new loggers concurrently 75 * (AddLogger), and then two additional threads: one (Stopper) that 76 * will stop the test after 4secs (TIME ms), and one DeadlockDetector 77 * that will attempt to detect deadlocks. 78 * If after 4secs no deadlock was detected and no exception was thrown 79 * then the test is considered a success and passes. 80 * 81 * This procedure is done twice: once without a security manager and once 82 * again with a security manager - which means the test takes ~8secs to 83 * run. 84 * 85 * Note that 8sec may not be enough to detect issues if there are some. 86 * This is a best effort test. 87 * 88 * @param args the command line arguments 89 */ main(String[] args)90 public static void main(String[] args) throws Exception { 91 92 // test without security 93 System.out.println("No security"); 94 test(); 95 96 // test with security 97 System.out.println("\nWith security"); 98 Policy.setPolicy(new Policy() { 99 @Override 100 public boolean implies(ProtectionDomain domain, Permission permission) { 101 if (super.implies(domain, permission)) return true; 102 // System.out.println("Granting " + permission); 103 return true; // all permissions 104 } 105 }); 106 System.setSecurityManager(new SecurityManager()); 107 test(); 108 } 109 110 /** 111 * Starts all threads, wait 4secs, then stops all threads. 112 * @throws Exception if a deadlock was detected or an error occurred. 113 */ test()114 public static void test() throws Exception { 115 goOn = true; 116 thrown = null; 117 long sNextLogger = nextLogger.get(); 118 long sReadCount = readCount.get(); 119 long sCheckCount = checkCount.get(); 120 List<Thread> threads = new ArrayList<>(); 121 for (int i = 0; i<READERS; i++) { 122 threads.add(new ReadConf()); 123 } 124 for (int i = 0; i<LOGGERS; i++) { 125 threads.add(new AddLogger()); 126 } 127 threads.add(new DeadlockDetector()); 128 threads.add(0, new Stopper(TIME)); 129 for (Thread t : threads) { 130 t.start(); 131 } 132 for (Thread t : threads) { 133 try { 134 t.join(); 135 } catch (Exception x) { 136 fail(x); 137 } 138 } 139 if (thrown != null) { 140 throw thrown; 141 } 142 System.out.println("Passed: " + (nextLogger.get() - sNextLogger) 143 + " loggers created by " + LOGGERS + " Thread(s),"); 144 System.out.println("\t LogManager.readConfiguration() called " 145 + (readCount.get() - sReadCount) + " times by " + READERS 146 + " Thread(s)."); 147 System.out.println("\t ThreadMXBean.findDeadlockedThreads called " 148 + (checkCount.get() -sCheckCount) + " times by 1 Thread."); 149 150 } 151 152 153 static final class ReadConf extends Thread { 154 @Override run()155 public void run() { 156 while (goOn) { 157 try { 158 LogManager.getLogManager().readConfiguration(); 159 readCount.incrementAndGet(); 160 Thread.sleep(1); 161 } catch (Exception x) { 162 fail(x); 163 } 164 } 165 } 166 } 167 168 static final class AddLogger extends Thread { 169 @Override run()170 public void run() { 171 try { 172 while (goOn) { 173 Logger l; 174 Logger foo = Logger.getLogger("foo"); 175 Logger bar = Logger.getLogger("foo.bar"); 176 for (int i=0; i < LCOUNT ; i++) { 177 l = Logger.getLogger("foo.bar.l"+nextLogger.incrementAndGet()); 178 l.fine("I'm fine"); 179 if (!goOn) break; 180 Thread.sleep(1); 181 } 182 } 183 } catch (InterruptedException | RuntimeException x ) { 184 fail(x); 185 } 186 } 187 } 188 189 static final class DeadlockDetector extends Thread { 190 191 @Override run()192 public void run() { 193 while(goOn) { 194 try { 195 long[] ids = ManagementFactory.getThreadMXBean().findDeadlockedThreads(); 196 checkCount.incrementAndGet(); 197 ids = ids == null ? new long[0] : ids; 198 if (ids.length == 1) { 199 throw new RuntimeException("Found 1 deadlocked thread: "+ids[0]); 200 } else if (ids.length > 0) { 201 ThreadInfo[] infos = ManagementFactory.getThreadMXBean() 202 .getThreadInfo(ids, Integer.MAX_VALUE); 203 System.err.println("Found "+ids.length+" deadlocked threads: "); 204 for (ThreadInfo inf : infos) { 205 System.err.println(inf.toString()); 206 } 207 throw new RuntimeException("Found "+ids.length+" deadlocked threads"); 208 } 209 Thread.sleep(100); 210 } catch(InterruptedException | RuntimeException x) { 211 fail(x); 212 } 213 } 214 } 215 216 } 217 218 static final class Stopper extends Thread { 219 long start; 220 long time; 221 Stopper(long time)222 Stopper(long time) { 223 start = System.currentTimeMillis(); 224 this.time = time; 225 } 226 227 @Override run()228 public void run() { 229 try { 230 long rest, previous; 231 previous = time; 232 while (goOn && (rest = start - System.currentTimeMillis() + time) > 0) { 233 if (previous == time || previous - rest >= STEP) { 234 Logger.getLogger("remaining").info(String.valueOf(rest)+"ms remaining..."); 235 previous = rest == time ? rest -1 : rest; 236 System.gc(); 237 } 238 if (goOn == false) break; 239 Thread.sleep(Math.min(rest, 100)); 240 } 241 System.out.println(System.currentTimeMillis() - start 242 + " ms elapsed ("+time+ " requested)"); 243 goOn = false; 244 } catch(InterruptedException | RuntimeException x) { 245 fail(x); 246 } 247 } 248 249 } 250 fail(Exception x)251 static void fail(Exception x) { 252 x.printStackTrace(); 253 if (thrown == null) { 254 thrown = x; 255 } 256 goOn = false; 257 } 258 } 259