8023168: Cleanup LogManager class initialization and LogManager/LoggerContext relationship
authordfuchs
Mon, 09 Sep 2013 13:59:51 +0200
changeset 19825 a7e79bc2e437
parent 19824 d0406202be67
child 19826 460110102fd4
8023168: Cleanup LogManager class initialization and LogManager/LoggerContext relationship 8021003: java/util/logging/Logger/getGlobal/TestGetGlobalConcurrent.java fails intermittently 8019945: test/java/util/logging/LogManagerInstanceTest.java failing intermittently Summary: This fix untangles the class initialization of Logger and LogManager, and also cleans up the relationship between LogManager, LoggerContext, and Logger, which were at the root cause of some intermittent test failures. Reviewed-by: mchung, martin, plevart
jdk/src/share/classes/java/util/logging/LogManager.java
jdk/src/share/classes/java/util/logging/Logger.java
jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobal.java
jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobalConcurrent.java
jdk/test/java/util/logging/Logger/getGlobal/policy
jdk/test/java/util/logging/ParentLoggersTest.java
jdk/test/java/util/logging/TestAppletLoggerContext.java
--- a/jdk/src/share/classes/java/util/logging/LogManager.java	Mon Sep 09 11:08:20 2013 +0800
+++ b/jdk/src/share/classes/java/util/logging/LogManager.java	Mon Sep 09 13:59:51 2013 +0200
@@ -144,7 +144,7 @@
 
 public class LogManager {
     // The global LogManager object
-    private static LogManager manager;
+    private static final LogManager manager;
 
     private Properties props = new Properties();
     private final static Level defaultLevel = Level.INFO;
@@ -156,8 +156,10 @@
     // LoggerContext for system loggers and user loggers
     private final LoggerContext systemContext = new SystemLoggerContext();
     private final LoggerContext userContext = new LoggerContext();
-    private Logger rootLogger;
-
+    // non final field - make it volatile to make sure that other threads
+    // will see the new value once ensureLogManagerInitialized() has finished
+    // executing.
+    private volatile Logger rootLogger;
     // Have we done the primordial reading of the configuration file?
     // (Must be done after a suitable amount of java.lang.System
     // initialization has been done)
@@ -169,58 +171,35 @@
     private boolean deathImminent;
 
     static {
-        AccessController.doPrivileged(new PrivilegedAction<Object>() {
-                public Object run() {
-                    String cname = null;
-                    try {
-                        cname = System.getProperty("java.util.logging.manager");
-                        if (cname != null) {
-                            try {
-                                Class<?> clz = ClassLoader.getSystemClassLoader().loadClass(cname);
-                                manager = (LogManager) clz.newInstance();
-                            } catch (ClassNotFoundException ex) {
-                                Class<?> clz = Thread.currentThread().getContextClassLoader().loadClass(cname);
-                                manager = (LogManager) clz.newInstance();
-                            }
+        manager = AccessController.doPrivileged(new PrivilegedAction<LogManager>() {
+            @Override
+            public LogManager run() {
+                LogManager mgr = null;
+                String cname = null;
+                try {
+                    cname = System.getProperty("java.util.logging.manager");
+                    if (cname != null) {
+                        try {
+                            Class<?> clz = ClassLoader.getSystemClassLoader()
+                                    .loadClass(cname);
+                            mgr = (LogManager) clz.newInstance();
+                        } catch (ClassNotFoundException ex) {
+                            Class<?> clz = Thread.currentThread()
+                                    .getContextClassLoader().loadClass(cname);
+                            mgr = (LogManager) clz.newInstance();
                         }
-                    } catch (Exception ex) {
-                        System.err.println("Could not load Logmanager \"" + cname + "\"");
-                        ex.printStackTrace();
                     }
-                    if (manager == null) {
-                        manager = new LogManager();
-                    }
+                } catch (Exception ex) {
+                    System.err.println("Could not load Logmanager \"" + cname + "\"");
+                    ex.printStackTrace();
+                }
+                if (mgr == null) {
+                    mgr = new LogManager();
+                }
+                return mgr;
 
-                    // Create and retain Logger for the root of the namespace.
-                    manager.rootLogger = manager.new RootLogger();
-                    // since by design the global manager's userContext and
-                    // systemContext don't have their requiresDefaultLoggers
-                    // flag set - we make sure to add the root logger to
-                    // the global manager's default contexts here.
-                    manager.addLogger(manager.rootLogger);
-                    manager.systemContext.addLocalLogger(manager.rootLogger, false);
-                    manager.userContext.addLocalLogger(manager.rootLogger, false);
-
-                    // Adding the global Logger. Doing so in the Logger.<clinit>
-                    // would deadlock with the LogManager.<clinit>.
-                    // Do not call Logger.getGlobal() here as this might trigger
-                    // the deadlock too.
-                    @SuppressWarnings("deprecation")
-                    final Logger global = Logger.global;
-                    global.setLogManager(manager);
-
-                    // Make sure the global logger will be registered in the
-                    // global manager's default contexts.
-                    manager.addLogger(global);
-                    manager.systemContext.addLocalLogger(global, false);
-                    manager.userContext.addLocalLogger(global, false);
-
-                    // We don't call readConfiguration() here, as we may be running
-                    // very early in the JVM startup sequence.  Instead readConfiguration
-                    // will be called lazily in getLogManager().
-                    return null;
-                }
-            });
+            }
+        });
     }
 
 
@@ -235,6 +214,7 @@
             this.setContextClassLoader(null);
         }
 
+        @Override
         public void run() {
             // This is to ensure the LogManager.<clinit> is completed
             // before synchronized block. Otherwise deadlocks are possible.
@@ -271,12 +251,103 @@
     }
 
     /**
+     * Lazy initialization: if this instance of manager is the global
+     * manager then this method will read the initial configuration and
+     * add the root logger and global logger by calling addLogger().
+     *
+     * Note that it is subtly different from what we do in LoggerContext.
+     * In LoggerContext we're patching up the logger context tree in order to add
+     * the root and global logger *to the context tree*.
+     *
+     * For this to work, addLogger() must have already have been called
+     * once on the LogManager instance for the default logger being
+     * added.
+     *
+     * This is why ensureLogManagerInitialized() needs to be called before
+     * any logger is added to any logger context.
+     *
+     */
+    private boolean initializedCalled = false;
+    private volatile boolean initializationDone = false;
+    final void ensureLogManagerInitialized() {
+        final LogManager owner = this;
+        if (initializationDone || owner != manager) {
+            // we don't want to do this twice, and we don't want to do
+            // this on private manager instances.
+            return;
+        }
+
+        // Maybe another thread has called ensureLogManagerInitialized()
+        // before us and is still executing it. If so we will block until
+        // the log manager has finished initialized, then acquire the monitor,
+        // notice that initializationDone is now true and return.
+        // Otherwise - we have come here first! We will acquire the monitor,
+        // see that initializationDone is still false, and perform the
+        // initialization.
+        //
+        synchronized(this) {
+            // If initializedCalled is true it means that we're already in
+            // the process of initializing the LogManager in this thread.
+            // There has been a recursive call to ensureLogManagerInitialized().
+            final boolean isRecursiveInitialization = (initializedCalled == true);
+
+            assert initializedCalled || !initializationDone
+                    : "Initialization can't be done if initialized has not been called!";
+
+            if (isRecursiveInitialization || initializationDone) {
+                // If isRecursiveInitialization is true it means that we're
+                // already in the process of initializing the LogManager in
+                // this thread. There has been a recursive call to
+                // ensureLogManagerInitialized(). We should not proceed as
+                // it would lead to infinite recursion.
+                //
+                // If initializationDone is true then it means the manager
+                // has finished initializing; just return: we're done.
+                return;
+            }
+            // Calling addLogger below will in turn call requiresDefaultLogger()
+            // which will call ensureLogManagerInitialized().
+            // We use initializedCalled to break the recursion.
+            initializedCalled = true;
+            try {
+                AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                    @Override
+                    public Object run() {
+                        assert rootLogger == null;
+                        assert initializedCalled && !initializationDone;
+
+                        // Read configuration.
+                        owner.readPrimordialConfiguration();
+
+                        // Create and retain Logger for the root of the namespace.
+                        owner.rootLogger = owner.new RootLogger();
+                        owner.addLogger(owner.rootLogger);
+
+                        // Adding the global Logger.
+                        // Do not call Logger.getGlobal() here as this might trigger
+                        // subtle inter-dependency issues.
+                        @SuppressWarnings("deprecation")
+                        final Logger global = Logger.global;
+
+                        // Make sure the global logger will be registered in the
+                        // global manager
+                        owner.addLogger(global);
+                        return null;
+                    }
+                });
+            } finally {
+                initializationDone = true;
+            }
+        }
+    }
+
+    /**
      * Returns the global LogManager object.
      * @return the global LogManager object
      */
     public static LogManager getLogManager() {
         if (manager != null) {
-            manager.readPrimordialConfiguration();
+            manager.ensureLogManagerInitialized();
         }
         return manager;
     }
@@ -295,6 +366,7 @@
 
                     try {
                         AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
+                                @Override
                                 public Void run() throws Exception {
                                     readConfiguration();
 
@@ -304,8 +376,7 @@
                                 }
                             });
                     } catch (Exception ex) {
-                        // System.err.println("Can't read logging configuration:");
-                        // ex.printStackTrace();
+                        assert false : "Exception raised while reading logging configuration: " + ex;
                     }
                 }
             }
@@ -392,7 +463,7 @@
     }
 
     // LoggerContext maps from AppContext
-    private static WeakHashMap<Object, LoggerContext> contextsMap = null;
+    private WeakHashMap<Object, LoggerContext> contextsMap = null;
 
     // Returns the LoggerContext for the user code (i.e. application or AppContext).
     // Loggers are isolated from each AppContext.
@@ -414,10 +485,7 @@
                     context = contextsMap.get(ecx);
                     if (context == null) {
                         // Create a new LoggerContext for the applet.
-                        // The new logger context has its requiresDefaultLoggers
-                        // flag set to true - so that these loggers will be
-                        // lazily added when the context is firt accessed.
-                        context = new LoggerContext(true);
+                        context = new LoggerContext();
                         contextsMap.put(ecx, context);
                     }
                 }
@@ -427,9 +495,14 @@
         return context != null ? context : userContext;
     }
 
+    // The system context.
+    final LoggerContext getSystemContext() {
+        return systemContext;
+    }
+
     private List<LoggerContext> contexts() {
         List<LoggerContext> cxs = new ArrayList<>();
-        cxs.add(systemContext);
+        cxs.add(getSystemContext());
         cxs.add(getUserContext());
         return cxs;
     }
@@ -450,7 +523,7 @@
         Logger result = getLogger(name);
         if (result == null) {
             // only allocate the new logger once
-            Logger newLogger = new Logger(name, resourceBundleName, caller);
+            Logger newLogger = new Logger(name, resourceBundleName, caller, this);
             do {
                 if (addLogger(newLogger)) {
                     // We successfully added the new Logger that we
@@ -477,7 +550,7 @@
 
     Logger demandSystemLogger(String name, String resourceBundleName) {
         // Add a system logger in the system context's namespace
-        final Logger sysLogger = systemContext.demandLogger(name, resourceBundleName);
+        final Logger sysLogger = getSystemContext().demandLogger(name, resourceBundleName);
 
         // Add the system logger to the LogManager's namespace if not exist
         // so that there is only one single logger of the given name.
@@ -501,6 +574,7 @@
             // if logger already exists but handlers not set
             final Logger l = logger;
             AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                @Override
                 public Void run() {
                     for (Handler hdl : l.getHandlers()) {
                         sysLogger.addHandler(hdl);
@@ -519,24 +593,52 @@
     // doesn't exist in the user context, it'll also be added to the user context.
     // The user context is queried by the user code and all other loggers are
     // added in the user context.
-    static class LoggerContext {
+    class LoggerContext {
         // Table of named Loggers that maps names to Loggers.
         private final Hashtable<String,LoggerWeakRef> namedLoggers = new Hashtable<>();
         // Tree of named Loggers
         private final LogNode root;
-        private final boolean requiresDefaultLoggers;
         private LoggerContext() {
-            this(false);
+            this.root = new LogNode(null, this);
+        }
+
+
+        // Tells whether default loggers are required in this context.
+        // If true, the default loggers will be lazily added.
+        final boolean requiresDefaultLoggers() {
+            final boolean requiresDefaultLoggers = (getOwner() == manager);
+            if (requiresDefaultLoggers) {
+                getOwner().ensureLogManagerInitialized();
+            }
+            return requiresDefaultLoggers;
         }
-        private LoggerContext(boolean requiresDefaultLoggers) {
-            this.root = new LogNode(null, this);
-            this.requiresDefaultLoggers = requiresDefaultLoggers;
+
+        // This context's LogManager.
+        final LogManager getOwner() {
+            return LogManager.this;
+        }
+
+        // This context owner's root logger, which if not null, and if
+        // the context requires default loggers, will be added to the context
+        // logger's tree.
+        final Logger getRootLogger() {
+            return getOwner().rootLogger;
+        }
+
+        // The global logger, which if not null, and if
+        // the context requires default loggers, will be added to the context
+        // logger's tree.
+        final Logger getGlobalLogger() {
+            @SuppressWarnings("deprecated") // avoids initialization cycles.
+            final Logger global = Logger.global;
+            return global;
         }
 
         Logger demandLogger(String name, String resourceBundleName) {
             // a LogManager subclass may have its own implementation to add and
             // get a Logger.  So delegate to the LogManager to do the work.
-            return manager.demandLogger(name, resourceBundleName, null);
+            final LogManager owner = getOwner();
+            return owner.demandLogger(name, resourceBundleName, null);
         }
 
 
@@ -548,10 +650,10 @@
         // or getLoggerNames()
         //
         private void ensureInitialized() {
-            if (requiresDefaultLoggers) {
+            if (requiresDefaultLoggers()) {
                 // Ensure that the root and global loggers are set.
-                ensureDefaultLogger(manager.rootLogger);
-                ensureDefaultLogger(Logger.global);
+                ensureDefaultLogger(getRootLogger());
+                ensureDefaultLogger(getGlobalLogger());
             }
         }
 
@@ -580,13 +682,13 @@
         // before adding 'logger'.
         //
         private void ensureAllDefaultLoggers(Logger logger) {
-            if (requiresDefaultLoggers) {
+            if (requiresDefaultLoggers()) {
                 final String name = logger.getName();
                 if (!name.isEmpty()) {
-                    ensureDefaultLogger(manager.rootLogger);
-                }
-                if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
-                    ensureDefaultLogger(Logger.global);
+                    ensureDefaultLogger(getRootLogger());
+                    if (!Logger.GLOBAL_LOGGER_NAME.equals(name)) {
+                        ensureDefaultLogger(getGlobalLogger());
+                    }
                 }
             }
         }
@@ -598,8 +700,8 @@
             // This check is simple sanity: we do not want that this
             // method be called for anything else than Logger.global
             // or owner.rootLogger.
-            if (!requiresDefaultLoggers || logger == null
-                    || logger != Logger.global && logger != manager.rootLogger) {
+            if (!requiresDefaultLoggers() || logger == null
+                    || logger != Logger.global && logger != LogManager.this.rootLogger) {
 
                 // the case where we have a non null logger which is neither
                 // Logger.global nor manager.rootLogger indicates a serious
@@ -625,7 +727,7 @@
 
         boolean addLocalLogger(Logger logger) {
             // no need to add default loggers if it's not required
-            return addLocalLogger(logger, requiresDefaultLoggers);
+            return addLocalLogger(logger, requiresDefaultLoggers());
         }
 
         // Add a logger to this context.  This method will only set its level
@@ -663,11 +765,13 @@
 
             // We're adding a new logger.
             // Note that we are creating a weak reference here.
-            ref = manager.new LoggerWeakRef(logger);
+            final LogManager owner = getOwner();
+            logger.setLogManager(owner);
+            ref = owner.new LoggerWeakRef(logger);
             namedLoggers.put(name, ref);
 
             // Apply any initial level defined for the new logger.
-            Level level = manager.getLevelProperty(name + ".level", null);
+            Level level = owner.getLevelProperty(name + ".level", null);
             if (level != null) {
                 doSetLevel(logger, level);
             }
@@ -719,10 +823,12 @@
         // If logger.getUseParentHandlers() returns 'true' and any of the logger's
         // parents have levels or handlers defined, make sure they are instantiated.
         private void processParentHandlers(final Logger logger, final String name) {
+            final LogManager owner = getOwner();
             AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                @Override
                 public Void run() {
-                    if (logger != manager.rootLogger) {
-                        boolean useParent = manager.getBooleanProperty(name + ".useParentHandlers", true);
+                    if (logger != owner.rootLogger) {
+                        boolean useParent = owner.getBooleanProperty(name + ".useParentHandlers", true);
                         if (!useParent) {
                             logger.setUseParentHandlers(false);
                         }
@@ -738,8 +844,8 @@
                     break;
                 }
                 String pname = name.substring(0, ix2);
-                if (manager.getProperty(pname + ".level") != null ||
-                    manager.getProperty(pname + ".handlers") != null) {
+                if (owner.getProperty(pname + ".level") != null ||
+                    owner.getProperty(pname + ".handlers") != null) {
                     // This pname has a level/handlers definition.
                     // Make sure it exists.
                     demandLogger(pname, null);
@@ -779,16 +885,17 @@
         }
     }
 
-    static class SystemLoggerContext extends LoggerContext {
+    final class SystemLoggerContext extends LoggerContext {
         // Add a system logger in the system context's namespace as well as
         // in the LogManager's namespace if not exist so that there is only
         // one single logger of the given name.  System loggers are visible
         // to applications unless a logger of the same name has been added.
+        @Override
         Logger demandLogger(String name, String resourceBundleName) {
             Logger result = findLogger(name);
             if (result == null) {
                 // only allocate the new system logger once
-                Logger newLogger = new Logger(name, resourceBundleName);
+                Logger newLogger = new Logger(name, resourceBundleName, null, getOwner());
                 do {
                     if (addLocalLogger(newLogger)) {
                         // We successfully added the new Logger that we
@@ -822,6 +929,7 @@
                                     final String handlersPropertyName)
     {
         AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
             public Object run() {
                 String names[] = parseClassNames(handlersPropertyName);
                 for (int i = 0; i < names.length; i++) {
@@ -1014,6 +1122,7 @@
         // There is a security manager.  Raise privilege before
         // calling setLevel.
         AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
             public Object run() {
                 logger.setLevel(level);
                 return null;
@@ -1032,6 +1141,7 @@
         // There is a security manager.  Raise privilege before
         // calling setParent.
         AccessController.doPrivileged(new PrivilegedAction<Object>() {
+            @Override
             public Object run() {
                 logger.setParent(parent);
                 return null;
@@ -1129,14 +1239,9 @@
             f = new File(f, "logging.properties");
             fname = f.getCanonicalPath();
         }
-        InputStream in = new FileInputStream(fname);
-        BufferedInputStream bin = new BufferedInputStream(in);
-        try {
+        try (final InputStream in = new FileInputStream(fname)) {
+            final BufferedInputStream bin = new BufferedInputStream(in);
             readConfiguration(bin);
-        } finally {
-            if (in != null) {
-                in.close();
-            }
         }
     }
 
@@ -1201,7 +1306,7 @@
         }
         hands = hands.trim();
         int ix = 0;
-        Vector<String> result = new Vector<>();
+        final List<String> result = new ArrayList<>();
         while (ix < hands.length()) {
             int end = ix;
             while (end < hands.length()) {
@@ -1471,28 +1576,35 @@
     // We use a subclass of Logger for the root logger, so
     // that we only instantiate the global handlers when they
     // are first needed.
-    private class RootLogger extends Logger {
+    private final class RootLogger extends Logger {
         private RootLogger() {
-            super("", null);
+            // We do not call the protected Logger two args constructor here,
+            // to avoid calling LogManager.getLogManager() from within the
+            // RootLogger constructor.
+            super("", null, null, LogManager.this);
             setLevel(defaultLevel);
         }
 
+        @Override
         public void log(LogRecord record) {
             // Make sure that the global handlers have been instantiated.
             initializeGlobalHandlers();
             super.log(record);
         }
 
+        @Override
         public void addHandler(Handler h) {
             initializeGlobalHandlers();
             super.addHandler(h);
         }
 
+        @Override
         public void removeHandler(Handler h) {
             initializeGlobalHandlers();
             super.removeHandler(h);
         }
 
+        @Override
         public Handler[] getHandlers() {
             initializeGlobalHandlers();
             return super.getHandlers();
--- a/jdk/src/share/classes/java/util/logging/Logger.java	Mon Sep 09 11:08:20 2013 +0800
+++ b/jdk/src/share/classes/java/util/logging/Logger.java	Mon Sep 09 13:59:51 2013 +0200
@@ -245,14 +245,26 @@
         // In order to finish the initialization of the global logger, we
         // will therefore call LogManager.getLogManager() here.
         //
-        // Care must be taken *not* to call Logger.getGlobal() in
-        // LogManager static initializers in order to avoid such
-        // deadlocks.
-        //
-        if (global != null && global.manager == null) {
-            // Complete initialization of the global Logger.
-            global.manager = LogManager.getLogManager();
-        }
+        // To prevent race conditions we also need to call
+        // LogManager.getLogManager() unconditionally here.
+        // Indeed we cannot rely on the observed value of global.manager,
+        // because global.manager will become not null somewhere during
+        // the initialization of LogManager.
+        // If two threads are calling getGlobal() concurrently, one thread
+        // will see global.manager null and call LogManager.getLogManager(),
+        // but the other thread could come in at a time when global.manager
+        // is already set although ensureLogManagerInitialized is not finished
+        // yet...
+        // Calling LogManager.getLogManager() unconditionally will fix that.
+
+        LogManager.getLogManager();
+
+        // Now the global LogManager should be initialized,
+        // and the global logger should have been added to
+        // it, unless we were called within the constructor of a LogManager
+        // subclass installed as LogManager, in which case global.manager
+        // would still be null, and global will be lazily initialized later on.
+
         return global;
     }
 
@@ -298,11 +310,11 @@
      *             no corresponding resource can be found.
      */
     protected Logger(String name, String resourceBundleName) {
-        this(name, resourceBundleName, null);
+        this(name, resourceBundleName, null, LogManager.getLogManager());
     }
 
-    Logger(String name, String resourceBundleName, Class<?> caller) {
-        this.manager = LogManager.getLogManager();
+    Logger(String name, String resourceBundleName, Class<?> caller, LogManager manager) {
+        this.manager = manager;
         setupResourceInfo(resourceBundleName, caller);
         this.name = name;
         levelValue = Level.INFO.intValue();
@@ -332,8 +344,8 @@
         levelValue = Level.INFO.intValue();
     }
 
-    // It is called from the LogManager.<clinit> to complete
-    // initialization of the global Logger.
+    // It is called from LoggerContext.addLocalLogger() when the logger
+    // is actually added to a LogManager.
     void setLogManager(LogManager manager) {
         this.manager = manager;
     }
@@ -558,7 +570,7 @@
         // cleanup some Loggers that have been GC'ed
         manager.drainLoggerRefQueueBounded();
         Logger result = new Logger(null, resourceBundleName,
-                                   Reflection.getCallerClass());
+                                   Reflection.getCallerClass(), manager);
         result.anonymous = true;
         Logger root = manager.getLogger("");
         result.doSetParent(root);
@@ -1798,7 +1810,7 @@
         if (parent == null) {
             throw new NullPointerException();
         }
-        manager.checkPermission();
+        checkPermission();
         doSetParent(parent);
     }
 
--- a/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobal.java	Mon Sep 09 11:08:20 2013 +0800
+++ b/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobal.java	Mon Sep 09 13:59:51 2013 +0200
@@ -57,6 +57,12 @@
     }
 
     public static void main(String... args) {
+        final String manager = System.getProperty("java.util.logging.manager", null);
+
+        final String description = "TestGetGlobal"
+            + (System.getSecurityManager() == null ? " " :
+               " -Djava.security.manager ")
+            + (manager == null ? "" : "-Djava.util.logging.manager=" + manager);
 
         Logger.global.info(messages[0]); // at this point LogManager is not
              // initialized yet, so this message should not appear.
@@ -67,7 +73,9 @@
 
         final List<String> expected = Arrays.asList(Arrays.copyOfRange(messages, 1, messages.length));
         if (!testgetglobal.HandlerImpl.received.equals(expected)) {
-            throw new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected);
+            System.err.println("Test case failed: " + description);
+            throw new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected
+                            + "\n\t"+description);
         }
     }
 }
--- a/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobalConcurrent.java	Mon Sep 09 11:08:20 2013 +0800
+++ b/jdk/test/java/util/logging/Logger/getGlobal/TestGetGlobalConcurrent.java	Mon Sep 09 13:59:51 2013 +0200
@@ -22,17 +22,18 @@
  */
 import java.util.Arrays;
 import java.util.List;
+import java.util.logging.Level;
 import java.util.logging.Logger;
 
 /**
  * @test
- * @bug 7184195
- * @summary checks that java.util.logging.Logger.getGlobal().info() logs without configuration
+ * @bug 7184195 8021003
+ * @summary Test that the global logger can log with no configuration when accessed from multiple threads.
  * @build TestGetGlobalConcurrent testgetglobal.HandlerImpl testgetglobal.LogManagerImpl1 testgetglobal.LogManagerImpl2 testgetglobal.LogManagerImpl3 testgetglobal.BadLogManagerImpl testgetglobal.DummyLogManagerImpl
  * @run main/othervm/timeout=10 TestGetGlobalConcurrent
  * @run main/othervm/timeout=10/policy=policy -Djava.security.manager TestGetGlobalConcurrent
- * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl TestGetGlobalConcurrent
- * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl TestGetGlobalConcurrent
+ * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl1 TestGetGlobalConcurrent
+ * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl1 TestGetGlobalConcurrent
  * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl2 TestGetGlobalConcurrent
  * @run main/othervm/timeout=10/policy=policy -Djava.security.manager -Djava.util.logging.manager=testgetglobal.LogManagerImpl2 TestGetGlobalConcurrent
  * @run main/othervm/timeout=10 -Djava.util.logging.manager=testgetglobal.LogManagerImpl3 TestGetGlobalConcurrent
@@ -69,7 +70,6 @@
              // initialize the LogManager - and thus this message should appear.
         Logger.global.info(messages[i+1]); // Now that the LogManager is
              // initialized, this message should appear too.
-
         final List<String> expected = Arrays.asList(Arrays.copyOfRange(messages, i, i+2));
         if (!testgetglobal.HandlerImpl.received.containsAll(expected)) {
             fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected));
@@ -82,7 +82,6 @@
              // initialize the LogManager - and thus this message should appear.
         Logger.global.info(messages[i+1]); // Now that the LogManager is
              // initialized, this message should appear too.
-
         final List<String> expected = Arrays.asList(Arrays.copyOfRange(messages, i, i+2));
         if (!testgetglobal.HandlerImpl.received.containsAll(expected)) {
             fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected));
@@ -96,7 +95,6 @@
              // initialize the LogManager - and thus this message should appear.
         Logger.global.info(messages[i+1]); // Now that the LogManager is
              // initialized, this message should appear too.
-
         final List<String> expected = Arrays.asList(Arrays.copyOfRange(messages, i, i+2));
         if (!testgetglobal.HandlerImpl.received.containsAll(expected)) {
             fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected));
@@ -150,8 +148,17 @@
         public void run() { test4(); }
     }
 
+    static String description = "Unknown";
+
     public static void main(String... args) throws Exception {
 
+        final String manager = System.getProperty("java.util.logging.manager", null);
+
+        description = "TestGetGlobalConcurrent"
+            + (System.getSecurityManager() == null ? " " :
+               " -Djava.security.manager ")
+            + (manager == null ? "" : "-Djava.util.logging.manager=" + manager);
+
         final Thread t1 = new Thread(new WaitAndRun(new Run1()), "test1");
         final Thread t2 = new Thread(new WaitAndRun(new Run2()), "test2");
         final Thread t3 = new Thread(new WaitAndRun(new Run3()), "test3");
@@ -169,14 +176,13 @@
 
         final List<String> expected = Arrays.asList(Arrays.copyOfRange(messages, 1, 3));
         if (!testgetglobal.HandlerImpl.received.containsAll(expected)) {
-            throw new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected);
+            fail(new Error("Unexpected message list: "+testgetglobal.HandlerImpl.received+" vs "+ expected));
         }
 
-
         t1.join(); t2.join(); t3.join(); t4.join();
 
         if (failed != null) {
-             throw new Error("Test failed.", failed);
+             throw new Error("Test failed: "+description, failed);
         }
 
         System.out.println("Test passed");
--- a/jdk/test/java/util/logging/Logger/getGlobal/policy	Mon Sep 09 11:08:20 2013 +0800
+++ b/jdk/test/java/util/logging/Logger/getGlobal/policy	Mon Sep 09 13:59:51 2013 +0200
@@ -1,6 +1,7 @@
 grant {
     permission java.util.PropertyPermission "java.util.logging.config.file", "write";
     permission java.util.PropertyPermission "test.src", "read";
+    permission java.util.PropertyPermission "java.util.logging.manager", "read";
     permission java.lang.RuntimePermission "setContextClassLoader";
     permission java.lang.RuntimePermission "shutdownHooks";
     permission java.util.logging.LoggingPermission "control";
--- a/jdk/test/java/util/logging/ParentLoggersTest.java	Mon Sep 09 11:08:20 2013 +0800
+++ b/jdk/test/java/util/logging/ParentLoggersTest.java	Mon Sep 09 13:59:51 2013 +0200
@@ -29,7 +29,7 @@
  * @author  ss45998
  *
  * @build ParentLoggersTest
- * @run main/othervm ParentLoggersTest
+ * @run main ParentLoggersTest
  */
 
 /*
--- a/jdk/test/java/util/logging/TestAppletLoggerContext.java	Mon Sep 09 11:08:20 2013 +0800
+++ b/jdk/test/java/util/logging/TestAppletLoggerContext.java	Mon Sep 09 13:59:51 2013 +0200
@@ -38,7 +38,7 @@
 
 /*
  * @test
- * @bug 8017174 8010727
+ * @bug 8017174 8010727 8019945
  * @summary  NPE when using Logger.getAnonymousLogger or
  *           LogManager.getLogManager().getLogger
  *
@@ -432,45 +432,36 @@
             assertNull(manager.getLogger(""));
             assertNull(manager.getLogger(""));
 
-            Bridge.changeContext();
+            for (int j = 0; j<3; j++) {
+                Bridge.changeContext();
 
-            // this is not a supported configuration:
-            // We are in an applet context with several log managers.
-            // We however need to check our assumptions...
+                // this is not a supported configuration:
+                // We are in an applet context with several log managers.
+                // We however need to check our assumptions...
 
-            // Applet context => root logger and global logger are not null.
-            //   root == LogManager.getLogManager().rootLogger
-            //   global == Logger.global
+                // Applet context => root logger and global logger should also be null.
 
-            Logger logger3 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
-            Logger logger3b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
-            assertNotNull(logger3);
-            assertNotNull(logger3b);
-            Logger expected = (System.getSecurityManager() != null
-                  ? Logger.getGlobal()
-                  : global);
-            assertEquals(logger3, expected); // in applet context, we will not see
-                  // the LogManager's custom global logger added above...
-            assertEquals(logger3b, expected); // in applet context, we will not see
-                  // the LogManager's custom global logger added above...
-            Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
-            manager.addLogger(global2); // adding a global logger will not work in applet context
-               // we will always get back the global logger.
-               // this could be considered as a bug...
-            Logger logger4 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
-            Logger logger4b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
-            assertNotNull(logger4);
-            assertNotNull(logger4b);
-            assertEquals(logger4,  expected); // adding a global logger will not work in applet context
-            assertEquals(logger4b, expected); // adding a global logger will not work in applet context
+                Logger expected = (System.getSecurityManager() == null ? global : null);
+                Logger logger3 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+                Logger logger3b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+                assertEquals(expected, logger3);
+                assertEquals(expected, logger3b);
+                Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
+                manager.addLogger(global2);
+                Logger logger4 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+                Logger logger4b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+                assertNotNull(logger4);
+                assertNotNull(logger4b);
+                expected = (System.getSecurityManager() == null ? global : global2);;
+                assertEquals(logger4,  expected);
+                assertEquals(logger4b, expected);
 
-            Logger logger5 = manager.getLogger("");
-            Logger logger5b = manager.getLogger("");
-            Logger expectedRoot = (System.getSecurityManager() != null
-                  ? LogManager.getLogManager().getLogger("")
-                  : null);
-            assertEquals(logger5, expectedRoot);
-            assertEquals(logger5b, expectedRoot);
+                Logger logger5 = manager.getLogger("");
+                Logger logger5b = manager.getLogger("");
+                Logger expectedRoot = null;
+                assertEquals(logger5, expectedRoot);
+                assertEquals(logger5b, expectedRoot);
+            }
 
         }
     }
@@ -511,57 +502,53 @@
             assertEquals(logger4, root);
             assertEquals(logger4b, root);
 
-            Bridge.changeContext();
+            for (int j = 0 ; j < 3 ; j++) {
+                Bridge.changeContext();
 
-            // this is not a supported configuration:
-            // We are in an applet context with several log managers.
-            // We haowever need to check our assumptions...
+                // this is not a supported configuration:
+                // We are in an applet context with several log managers.
+                // We however need to check our assumptions...
 
-            // Applet context => root logger and global logger are not null.
-            //   root == LogManager.getLogManager().rootLogger
-            //   global == Logger.global
+                // Applet context => root logger and global logger should also be null.
 
-            Logger logger5 = manager.getLogger("");
-            Logger logger5b = manager.getLogger("");
-            Logger expectedRoot = (System.getSecurityManager() != null
-                  ? LogManager.getLogManager().getLogger("")
-                  : root);
+                Logger logger5 = manager.getLogger("");
+                Logger logger5b = manager.getLogger("");
+                Logger expectedRoot = (System.getSecurityManager() == null ? root : null);
+                assertEquals(logger5, expectedRoot);
+                assertEquals(logger5b, expectedRoot);
 
-            assertNotNull(logger5);
-            assertNotNull(logger5b);
-            assertEquals(logger5, expectedRoot);
-            assertEquals(logger5b, expectedRoot);
-            if (System.getSecurityManager() != null) {
-                assertNotEquals(logger5, root);
-                assertNotEquals(logger5b, root);
-            }
+                if (System.getSecurityManager() != null) {
+                    assertNull(manager.getLogger(Logger.GLOBAL_LOGGER_NAME));
+                } else {
+                    assertEquals(global, manager.getLogger(Logger.GLOBAL_LOGGER_NAME));
+                }
 
-            Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
-            manager.addLogger(global2); // adding a global logger will not work in applet context
-               // we will always get back the global logger.
-               // this could be considered as a bug...
-            Logger logger6 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
-            Logger logger6b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
-            Logger expectedGlobal = (System.getSecurityManager() != null
-                  ? Logger.getGlobal()
-                  : global);
-            assertNotNull(logger6);
-            assertNotNull(logger6b);
-            assertEquals(logger6, expectedGlobal); // adding a global logger will not work in applet context
-            assertEquals(logger6b, expectedGlobal); // adding a global logger will not work in applet context
+                Logger global2 = new Bridge.CustomLogger(Logger.GLOBAL_LOGGER_NAME);
+                manager.addLogger(global2);
+                Logger logger6 = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+                Logger logger6b = manager.getLogger(Logger.GLOBAL_LOGGER_NAME);
+                Logger expectedGlobal = (System.getSecurityManager() == null ? global : global2);
 
-            Logger root2 = new Bridge.CustomLogger("");
-            manager.addLogger(root2); // adding a root logger will not work in applet context
-               // we will always get back the default manager's root logger.
-               // this could be considered as a bug...
-            Logger logger7 = manager.getLogger("");
-            Logger logger7b = manager.getLogger("");
-            assertNotNull(logger7);
-            assertNotNull(logger7b);
-            assertEquals(logger7, expectedRoot); // adding a global logger will not work in applet context
-            assertEquals(logger7b, expectedRoot); // adding a global logger will not work in applet context
-            assertNotEquals(logger7, root2);
-            assertNotEquals(logger7b, root2);
+                assertNotNull(logger6);
+                assertNotNull(logger6b);
+                assertEquals(logger6, expectedGlobal);
+                assertEquals(logger6b, expectedGlobal);
+                if (System.getSecurityManager() != null) {
+                    assertNull(manager.getLogger(""));
+                } else {
+                    assertEquals(root, manager.getLogger(""));
+                }
+
+                Logger root2 = new Bridge.CustomLogger("");
+                manager.addLogger(root2);
+                expectedRoot = (System.getSecurityManager() == null ? root : root2);
+                Logger logger7 = manager.getLogger("");
+                Logger logger7b = manager.getLogger("");
+                assertNotNull(logger7);
+                assertNotNull(logger7b);
+                assertEquals(logger7, expectedRoot);
+                assertEquals(logger7b, expectedRoot);
+            }
         }
     }