< 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,280 ----
public void run() {
// This is to ensure the LogManager.<clinit> is completed
// before synchronized block. Otherwise deadlocks are possible.
LogManager mgr = manager;
! // Do a reset to close all active handlers and set
! // globalHandlersState to a final STATE_SHUTDOWN so
! // that no attempts will be made to initialize them again.
! reset(STATE_SHUTDOWN);
}
}
/**
*** 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 {
--- 1311,1386 ----
* the caller does not have LoggingPermission("control").
*/
public void reset() throws SecurityException {
checkPermission();
+ // Since we are doing a reset we no longer want to initialize
+ // the global handlers, if they haven't been initialized yet.
+ reset(STATE_INITIALIZED);
+ }
+
+ private void reset(int newGlobalHandlersState) {
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();
!
! globalHandlersState = newGlobalHandlersState;
!
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
--- 1433,1460 ----
* 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;
! }
!
! // reset configuration to STATE_INITIALIZING temporarily so that any
! // ongoing logging requests block in initializeGlobalHandlers()
! // and don't get processed while configuration is still changing
! reset(STATE_INITIALIZING);
try {
+ 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.
--- 1480,1510 ----
}
// 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() {
--- 1627,1667 ----
}
// 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.
--- 1752,1762 ----
}
// 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 >