diff options
Diffstat (limited to 'java/openjdk6/files/icedtea/openjdk/8010939-logmanager_deadlock.patch')
-rw-r--r-- | java/openjdk6/files/icedtea/openjdk/8010939-logmanager_deadlock.patch | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/java/openjdk6/files/icedtea/openjdk/8010939-logmanager_deadlock.patch b/java/openjdk6/files/icedtea/openjdk/8010939-logmanager_deadlock.patch new file mode 100644 index 000000000000..5bf8a341ebf8 --- /dev/null +++ b/java/openjdk6/files/icedtea/openjdk/8010939-logmanager_deadlock.patch @@ -0,0 +1,266 @@ +# HG changeset patch +# User jgish +# Date 1366415410 25200 +# Fri Apr 19 16:50:10 2013 -0700 +# Node ID ed410e3d08fe7792e6c08e411580564d2562c03e +# Parent e3eae7996a478cd07125110456836a42c8a504c6 +8010939: Deadlock in LogManager +Summary: re-order locks to avoid deadlock +Reviewed-by: mchung, alanb + +diff -r e3eae7996a47 -r ed410e3d08fe src/share/classes/java/util/logging/LogManager.java +--- jdk/src/share/classes/java/util/logging/LogManager.java Tue May 14 08:07:08 2013 -0700 ++++ jdk/src/share/classes/java/util/logging/LogManager.java Fri Apr 19 16:50:10 2013 -0700 +@@ -33,10 +33,8 @@ + import java.lang.ref.WeakReference; + import java.beans.PropertyChangeListener; + import java.beans.PropertyChangeSupport; +-import java.net.URL; + import sun.misc.JavaAWTAccess; + import sun.misc.SharedSecrets; +-import sun.security.action.GetPropertyAction; + + /** + * There is a single global LogManager object that is used to +@@ -151,7 +149,6 @@ + // The global LogManager object + private static LogManager manager; + +- private final static Handler[] emptyHandlers = { }; + private Properties props = new Properties(); + private PropertyChangeSupport changes + = new PropertyChangeSupport(LogManager.class); +@@ -506,14 +503,11 @@ + throw new NullPointerException(); + } + +- // cleanup some Loggers that have been GC'ed +- manager.drainLoggerRefQueueBounded(); +- + LoggerWeakRef ref = namedLoggers.get(name); + if (ref != null) { + if (ref.get() == null) { +- // It's possible that the Logger was GC'ed after the +- // drainLoggerRefQueueBounded() call above so allow ++ // It's possible that the Logger was GC'ed after a ++ // drainLoggerRefQueueBounded() call so allow + // a new one to be registered. + removeLogger(name); + } else { +@@ -561,6 +555,8 @@ + return true; + } + ++ // note: all calls to removeLogger are synchronized on LogManager's ++ // intrinsic lock + void removeLogger(String name) { + namedLoggers.remove(name); + } +@@ -845,6 +841,7 @@ + if (name == null) { + throw new NullPointerException(); + } ++ drainLoggerRefQueueBounded(); + LoggerContext cx = getUserContext(); + if (cx.addLocalLogger(logger)) { + // Do we have a per logger handler too? +diff -r e3eae7996a47 -r ed410e3d08fe test/java/util/logging/DrainFindDeadlockTest.java +--- /dev/null Thu Jan 01 00:00:00 1970 +0000 ++++ jdk/test/java/util/logging/DrainFindDeadlockTest.java Fri Apr 19 16:50:10 2013 -0700 +@@ -0,0 +1,196 @@ ++/* ++ * 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.ThreadInfo; ++import java.lang.management.ThreadMXBean; ++import java.lang.Thread.State; ++import java.io.IOException; ++import java.lang.management.ManagementFactory; ++import java.util.logging.LogManager; ++import java.util.logging.Logger; ++import java.util.Map; ++ ++/** ++ * @test ++ * @bug 8010939 ++ * @summary check for deadlock between findLogger() and drainLoggerRefQueueBounded() ++ * @author jim.gish@oracle.com ++ * @build DrainFindDeadlockTest ++ * @run main/othervm/timeout=10 DrainFindDeadlockTest ++ */ ++ ++/** ++ * This test is checking for a deadlock between ++ * LogManager$LoggerContext.findLogger() and ++ * LogManager.drainLoggerRefQueueBounded() (which could happen by calling ++ * Logger.getLogger() and LogManager.readConfiguration() in different threads) ++ */ ++public class DrainFindDeadlockTest { ++ private LogManager mgr = LogManager.getLogManager(); ++ private final static int MAX_ITERATIONS = 100; ++ ++ // Get a ThreadMXBean so we can check for deadlock. N.B. this may ++ // not be supported on all platforms, which means we will have to ++ // resort to the traditional test timeout method. However, if ++ // we have the support we'll get the deadlock details if one ++ // is detected. ++ private final static ThreadMXBean threadMXBean = ++ ManagementFactory.getThreadMXBean(); ++ private final boolean threadMXBeanDeadlockSupported = ++ threadMXBean.isSynchronizerUsageSupported(); ++ ++ public static void main(String... args) throws IOException, Exception { ++ new DrainFindDeadlockTest().testForDeadlock(); ++ } ++ ++ public static void randomDelay() { ++ int runs = (int) Math.random() * 1000000; ++ int c = 0; ++ ++ for (int i=0; i<runs; ++i) { ++ c=c+i; ++ } ++ } ++ ++ public void testForDeadlock() throws IOException, Exception { ++ System.out.println("Deadlock detection " ++ + (threadMXBeanDeadlockSupported ? "is" : "is not") + ++ " available."); ++ Thread setup = new Thread(new SetupLogger(), "SetupLogger"); ++ Thread readConfig = new Thread(new ReadConfig(), "ReadConfig"); ++ Thread check = new Thread(new DeadlockChecker(setup, readConfig), ++ "DeadlockChecker"); ++ ++ // make the threads daemon threads so they will go away when the ++ // test exits ++ setup.setDaemon(true); ++ readConfig.setDaemon(true); ++ check.setDaemon(true); ++ ++ check.start(); setup.start(); readConfig.start(); ++ 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()); ++ for (StackTraceElement element: aStackElt) { ++ System.out.println(" " + element); ++ } ++ } ++ } ++ ++ @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) { ++ }; ++ } ++ } ++ } ++} |