< prev index next >

src/java.logging/share/classes/java/util/logging/LogManager.java

Print this page

        

*** 31,42 **** import java.security.*; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import sun.misc.JavaAWTAccess; - import sun.misc.ManagedLocalsThread; import sun.misc.SharedSecrets; /** * There is a single global LogManager object that is used to * maintain a set of shared state about Loggers and log services. --- 31,42 ---- import java.security.*; import java.lang.ref.ReferenceQueue; import java.lang.ref.WeakReference; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; + import java.util.concurrent.locks.ReentrantLock; import sun.misc.JavaAWTAccess; import sun.misc.SharedSecrets; /** * There is a single global LogManager object that is used to * maintain a set of shared state about Loggers and log services.
*** 178,191 **** // 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) private volatile boolean readPrimordialConfiguration; // Have we initialized global (root) handlers yet? ! // This gets set to false in readConfiguration ! private boolean initializedGlobalHandlers = true; ! // True if JVM death is imminent and the exit hook has been called. ! private boolean deathImminent; // This list contains the loggers for which some handlers have been // explicitly configured in the configuration file. // It prevents these loggers from being arbitrarily garbage collected. private static final class CloseOnReset { --- 178,196 ---- // 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) private volatile boolean readPrimordialConfiguration; // Have we initialized global (root) handlers yet? ! // This gets set to STATE_UNINITIALIZED in readConfiguration ! private static final int ! STATE_INITIALIZED = 0, // initial state ! STATE_INITIALIZING = 1, ! STATE_UNINITIALIZED = 2, ! STATE_SHUTDOWN = 3; // terminal state ! private volatile int globalHandlersState; // = STATE_INITIALIZED; ! // A concurrency lock for reset(), readConfiguration() and Cleaner. ! private final ReentrantLock configurationLock = new ReentrantLock(); // This list contains the loggers for which some handlers have been // explicitly configured in the configuration file. // It prevents these loggers from being arbitrarily garbage collected. private static final class CloseOnReset {
*** 247,257 **** }); } // This private class is used as a shutdown hook. // It does a "reset" to close all open handlers. ! private class Cleaner extends ManagedLocalsThread { private Cleaner() { /* Set context class loader to null in order to avoid * keeping a strong reference to an application classloader. */ --- 252,262 ---- }); } // This private class is used as a shutdown hook. // It does a "reset" to close all open handlers. ! private class Cleaner extends Thread { private Cleaner() { /* Set context class loader to null in order to avoid * keeping a strong reference to an application classloader. */
*** 262,281 **** public void run() { // This is to ensure the LogManager.<clinit> is completed // before synchronized block. Otherwise deadlocks are possible. LogManager mgr = manager; ! // If the global handlers haven't been initialized yet, we ! // don't want to initialize them just so we can close them! ! synchronized (LogManager.this) { ! // Note that death is imminent. ! deathImminent = true; ! initializedGlobalHandlers = true; ! } ! ! // Do a reset to close all active handlers. reset(); } } /** --- 267,290 ---- public void run() { // This is to ensure the LogManager.<clinit> is completed // before synchronized block. Otherwise deadlocks are possible. LogManager mgr = manager; ! configurationLock.lock(); ! // temporarily block any ongoing logging requests until reset finishes ! // by setting globalHandlersState to STATE_INITIALIZING ! globalHandlersState = STATE_INITIALIZING; ! try { ! // Do a reset to close all active handlers which leaves state at ! // STATE_INITIALIZING... reset(); + } finally { + // set globalHandlersState to a final STATE_SHUTDOWN so + // that no attempts will be made to initialize them again. + globalHandlersState = STATE_SHUTDOWN; + configurationLock.unlock(); + } } } /**
*** 1312,1359 **** * the caller does not have LoggingPermission("control"). */ public void reset() throws SecurityException { checkPermission(); List<CloseOnReset> persistent; ! synchronized (this) { props = new Properties(); // make sure we keep the loggers persistent until reset is done. // Those are the loggers for which we previously created a // handler from the configuration, and we need to prevent them // from being gc'ed until those handlers are closed. persistent = new ArrayList<>(closeOnResetLoggers); closeOnResetLoggers.clear(); // Since we are doing a reset we no longer want to initialize // the global handlers, if they haven't been initialized yet. ! initializedGlobalHandlers = true; } for (LoggerContext cx : contexts()) { Enumeration<String> enum_ = cx.getLoggerNames(); while (enum_.hasMoreElements()) { String name = enum_.nextElement(); Logger logger = cx.findLogger(name); if (logger != null) { resetLogger(logger); } } } - persistent.clear(); - } ! // Private method to reset an individual target logger. ! private void resetLogger(Logger logger) { ! // Close all the Logger's handlers. Handler[] targets = logger.getHandlers(); for (Handler h : targets) { logger.removeHandler(h); try { h.close(); } catch (Exception ex) { // Problems closing a handler? Keep going... } } String name = logger.getName(); if (name != null && name.equals("")) { // This is the root logger. logger.setLevel(defaultLevel); } else { --- 1321,1398 ---- * the caller does not have LoggingPermission("control"). */ public void reset() throws SecurityException { checkPermission(); + List<CloseOnReset> persistent; ! ! // We don't want reset() and readConfiguration() ! // to run in parallel ! configurationLock.lock(); ! try { ! if (globalHandlersState == STATE_SHUTDOWN) { ! // already in terminal state ! return; ! } ! // install new empty properties props = new Properties(); // make sure we keep the loggers persistent until reset is done. // Those are the loggers for which we previously created a // handler from the configuration, and we need to prevent them // from being gc'ed until those handlers are closed. persistent = new ArrayList<>(closeOnResetLoggers); closeOnResetLoggers.clear(); + // Since we are doing a reset we no longer want to initialize // the global handlers, if they haven't been initialized yet. ! // When globalHandlersState == STATE_INITIALIZING it means ! // we have been called from readConfiguration that is going to set ! // final state itself. Otherwise we set is to STATE_INITIALIZED. ! if (globalHandlersState != STATE_INITIALIZING) { ! globalHandlersState = STATE_INITIALIZED; } + for (LoggerContext cx : contexts()) { + resetLoggerContext(cx); + } + + persistent.clear(); + } finally { + configurationLock.unlock(); + } + } + + private void resetLoggerContext(LoggerContext cx) { Enumeration<String> enum_ = cx.getLoggerNames(); while (enum_.hasMoreElements()) { String name = enum_.nextElement(); Logger logger = cx.findLogger(name); if (logger != null) { resetLogger(logger); } } } ! private void closeHandlers(Logger logger) { Handler[] targets = logger.getHandlers(); for (Handler h : targets) { logger.removeHandler(h); try { h.close(); } catch (Exception ex) { // Problems closing a handler? Keep going... } } + } + + // Private method to reset an individual target logger. + private void resetLogger(Logger logger) { + // Close all the Logger handlers. + closeHandlers(logger); + + // Reset Logger level String name = logger.getName(); if (name != null && name.equals("")) { // This is the root logger. logger.setLevel(defaultLevel); } else {
*** 1406,1419 **** * the caller does not have LoggingPermission("control"). * @exception IOException if there are problems reading from the stream. */ public void readConfiguration(InputStream ins) throws IOException, SecurityException { checkPermission(); reset(); - // Load the properties try { props.load(ins); } catch (IllegalArgumentException x) { // props.load may throw an IllegalArgumentException if the stream // contains malformed Unicode escape sequences. // We wrap that in an IOException as readConfiguration is --- 1445,1476 ---- * the caller does not have LoggingPermission("control"). * @exception IOException if there are problems reading from the stream. */ public void readConfiguration(InputStream ins) throws IOException, SecurityException { checkPermission(); + + // We don't want reset() and readConfiguration() to run + // in parallel. + configurationLock.lock(); + try { + if (globalHandlersState == STATE_SHUTDOWN) { + // already in terminal state: don't even bother to read the + // configuration + return; + } + + // change state to STATE_INITIALIZING so that reset() doesn't change it to + // STATE_INITIALIZED just yet... + globalHandlersState = STATE_INITIALIZING; + try { + // reset configuration which leaves globalHandlersState at STATE_INITIALIZING + // so that while reading configuration, any ongoing logging requests block and + // wait for the outcome (see the end of this try statement) reset(); try { + // Load the properties props.load(ins); } catch (IllegalArgumentException x) { // props.load may throw an IllegalArgumentException if the stream // contains malformed Unicode escape sequences. // We wrap that in an IOException as readConfiguration is
*** 1439,1457 **** } // Set levels on any pre-existing loggers, based on the new properties. setLevelsOnExistingLoggers(); - try { - invokeConfigurationListeners(); - } finally { // Note that we need to reinitialize global handles when // they are first referenced. ! synchronized (this) { ! initializedGlobalHandlers = false; } } } /** * Get the value of a logging property. * The method returns null if the property is not found. --- 1496,1526 ---- } // Set levels on any pre-existing loggers, based on the new properties. setLevelsOnExistingLoggers(); // Note that we need to reinitialize global handles when // they are first referenced. ! // Note: Marking global handlers as not initialized must be done ! // before unlocking. ! globalHandlersState = STATE_UNINITIALIZED; ! } catch (Throwable t) { ! // If there were any trouble, then set state to STATE_INITIALIZED ! // so that no global handlers reinitialization is performed on not fully ! // initialized configuration. ! globalHandlersState = STATE_INITIALIZED; ! // re-throw ! throw t; } + + } finally { + configurationLock.unlock(); } + + // should be called out of lock to avoid dead-lock situations + // when user code is involved + invokeConfigurationListeners(); } /** * Get the value of a logging property. * The method returns null if the property is not found.
*** 1574,1597 **** } // Private method to load the global handlers. // We do the real work lazily, when the global handlers // are first used. ! private synchronized void initializeGlobalHandlers() { ! if (initializedGlobalHandlers) { return; } ! initializedGlobalHandlers = true; ! ! if (deathImminent) { ! // Aaargh... ! // The VM is shutting down and our exit hook has been called. ! // Avoid allocating global handlers. ! return; } loadLoggerHandlers(rootLogger, null, "handlers"); } static final Permission controlPermission = new LoggingPermission("control", null); void checkPermission() { --- 1643,1683 ---- } // Private method to load the global handlers. // We do the real work lazily, when the global handlers // are first used. ! private void initializeGlobalHandlers() { ! int state = globalHandlersState; ! if (state == STATE_INITIALIZED || state == STATE_SHUTDOWN) { ! // Nothing to do: return. return; } ! // If we have not initialized global handlers yet (or need to ! // reinitialize them), lets do it now (this case is indicated by ! // globalHandlersState == STATE_UNINITIALIZED). ! // If we are in the process of initializing global handlers we ! // also need to lock & wait (this case is indicated by ! // globalHandlersState == STATE_INITIALIZING). ! // So in either case we need to acquire the lock. ! configurationLock.lock(); ! try { ! if (globalHandlersState != STATE_UNINITIALIZED) { ! return; // recursive call or nothing to do } + // set globalHandlersState to STATE_INITIALIZING first to avoid + // getting an infinite recursion when loadLoggerHandlers(...) + // is going to call addHandler(...) + globalHandlersState = STATE_INITIALIZING; + try { loadLoggerHandlers(rootLogger, null, "handlers"); + } finally { + globalHandlersState = STATE_INITIALIZED; + } + } finally { + configurationLock.unlock(); + } } static final Permission controlPermission = new LoggingPermission("control", null); void checkPermission() {
*** 1682,1692 **** } // Private method to be called when the configuration has // changed to apply any level settings to any pre-existing loggers. ! synchronized private void setLevelsOnExistingLoggers() { Enumeration<?> enum_ = props.propertyNames(); while (enum_.hasMoreElements()) { String key = (String)enum_.nextElement(); if (!key.endsWith(".level")) { // Not a level definition. --- 1768,1778 ---- } // Private method to be called when the configuration has // changed to apply any level settings to any pre-existing loggers. ! private void setLevelsOnExistingLoggers() { Enumeration<?> enum_ = props.propertyNames(); while (enum_.hasMoreElements()) { String key = (String)enum_.nextElement(); if (!key.endsWith(".level")) { // Not a level definition.
< prev index next >