8307535: java.util.logging.Handlers should be more VirtualThread friendly

Reviewed-by: jpai
This commit is contained in:
Daniel Fuchs 2023-05-12 15:24:11 +00:00
parent 9fa8b9a4a6
commit 3c68c352fc
6 changed files with 307 additions and 33 deletions

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -85,13 +85,15 @@ public class ErrorManager {
* @param ex an exception (may be null) * @param ex an exception (may be null)
* @param code an error code defined in ErrorManager * @param code an error code defined in ErrorManager
*/ */
public synchronized void error(String msg, Exception ex, int code) { public void error(String msg, Exception ex, int code) {
if (reported) { synchronized (this) {
// We only report the first error, to avoid clogging if (reported) {
// the screen. // We only report the first error, to avoid clogging
return; // the screen.
return;
}
reported = true;
} }
reported = true;
String text = "java.util.logging.ErrorManager: " + code; String text = "java.util.logging.ErrorManager: " + code;
if (msg != null) { if (msg != null) {
text = text + ": " + msg; text = text + ": " + msg;

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -728,7 +728,21 @@ public class FileHandler extends StreamHandler {
/** /**
* Rotate the set of output files * Rotate the set of output files
*/ */
private synchronized void rotate() { private void rotate() {
if (tryUseLock()) {
try {
rotate0();
} finally {
unlock();
}
} else {
synchronized (this) {
rotate0();
}
}
}
private void rotate0() {
Level oldLevel = getLevel(); Level oldLevel = getLevel();
setLevel(Level.OFF); setLevel(Level.OFF);
@ -760,9 +774,23 @@ public class FileHandler extends StreamHandler {
* @param record description of the log event. A null record is * @param record description of the log event. A null record is
* silently ignored and is not published * silently ignored and is not published
*/ */
@SuppressWarnings("removal")
@Override @Override
public synchronized void publish(LogRecord record) { public void publish(LogRecord record) {
if (tryUseLock()) {
try {
publish0(record);
} finally {
unlock();
}
} else {
synchronized (this) {
publish0(record);
}
}
}
@SuppressWarnings("removal")
private void publish0(LogRecord record) {
if (!isLoggable(record)) { if (!isLoggable(record)) {
return; return;
} }
@ -791,7 +819,21 @@ public class FileHandler extends StreamHandler {
* the caller does not have {@code LoggingPermission("control")}. * the caller does not have {@code LoggingPermission("control")}.
*/ */
@Override @Override
public synchronized void close() throws SecurityException { public void close() throws SecurityException {
if (tryUseLock()) {
try {
close0();
} finally {
unlock();
}
} else {
synchronized (this) {
close0();
}
}
}
private void close0() throws SecurityException {
super.close(); super.close();
// Unlock any lock file. // Unlock any lock file.
if (lockFileName == null) { if (lockFileName == null) {

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -30,6 +30,7 @@ import java.util.Objects;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
import java.security.AccessController; import java.security.AccessController;
import java.security.PrivilegedAction; import java.security.PrivilegedAction;
import java.util.concurrent.locks.ReentrantLock;
/** /**
* A {@code Handler} object takes log messages from a {@code Logger} and * A {@code Handler} object takes log messages from a {@code Logger} and
@ -65,6 +66,7 @@ public abstract class Handler {
private volatile Level logLevel = Level.ALL; private volatile Level logLevel = Level.ALL;
private volatile ErrorManager errorManager = new ErrorManager(); private volatile ErrorManager errorManager = new ErrorManager();
private volatile String encoding; private volatile String encoding;
private final ReentrantLock lock;
/** /**
* Default constructor. The resulting {@code Handler} has a log * Default constructor. The resulting {@code Handler} has a log
@ -73,6 +75,17 @@ public abstract class Handler {
* as the {@code ErrorManager}. * as the {@code ErrorManager}.
*/ */
protected Handler() { protected Handler() {
lock = initLocking();
}
private ReentrantLock initLocking() {
Class<?> clazz = this.getClass();
ClassLoader loader = clazz.getClassLoader();
if (loader != null && loader != ClassLoader.getPlatformClassLoader()) {
return null;
} else {
return new ReentrantLock();
}
} }
/** /**
@ -90,6 +103,7 @@ public abstract class Handler {
@SuppressWarnings("removal") @SuppressWarnings("removal")
Handler(Level defaultLevel, Formatter defaultFormatter, Handler(Level defaultLevel, Formatter defaultFormatter,
Formatter specifiedFormatter) { Formatter specifiedFormatter) {
this();
LogManager manager = LogManager.getLogManager(); LogManager manager = LogManager.getLogManager();
String cname = getClass().getName(); String cname = getClass().getName();
@ -122,6 +136,15 @@ public abstract class Handler {
}, null, LogManager.controlPermission); }, null, LogManager.controlPermission);
} }
boolean tryUseLock() {
if (lock == null) return false;
lock.lock();
return true;
}
void unlock() {
lock.unlock();
}
/** /**
* Publish a {@code LogRecord}. * Publish a {@code LogRecord}.
* <p> * <p>
@ -165,7 +188,21 @@ public abstract class Handler {
* @throws SecurityException if a security manager exists and if * @throws SecurityException if a security manager exists and if
* the caller does not have {@code LoggingPermission("control")}. * the caller does not have {@code LoggingPermission("control")}.
*/ */
public synchronized void setFormatter(Formatter newFormatter) throws SecurityException { public void setFormatter(Formatter newFormatter) throws SecurityException {
if (tryUseLock()) {
try {
setFormatter0(newFormatter);
} finally {
unlock();
}
} else {
synchronized (this) {
setFormatter0(newFormatter);
}
}
}
private void setFormatter0(Formatter newFormatter) throws SecurityException {
checkPermission(); checkPermission();
formatter = Objects.requireNonNull(newFormatter); formatter = Objects.requireNonNull(newFormatter);
} }
@ -191,7 +228,22 @@ public abstract class Handler {
* @throws UnsupportedEncodingException if the named encoding is * @throws UnsupportedEncodingException if the named encoding is
* not supported. * not supported.
*/ */
public synchronized void setEncoding(String encoding) public void setEncoding(String encoding)
throws SecurityException, java.io.UnsupportedEncodingException {
if (tryUseLock()) {
try {
setEncoding0(encoding);
} finally {
unlock();
}
} else {
synchronized (this) {
setEncoding0(encoding);
}
}
}
private void setEncoding0(String encoding)
throws SecurityException, java.io.UnsupportedEncodingException { throws SecurityException, java.io.UnsupportedEncodingException {
checkPermission(); checkPermission();
if (encoding != null) { if (encoding != null) {
@ -227,7 +279,21 @@ public abstract class Handler {
* @throws SecurityException if a security manager exists and if * @throws SecurityException if a security manager exists and if
* the caller does not have {@code LoggingPermission("control")}. * the caller does not have {@code LoggingPermission("control")}.
*/ */
public synchronized void setFilter(Filter newFilter) throws SecurityException { public void setFilter(Filter newFilter) throws SecurityException {
if (tryUseLock()) {
try {
setFilter0(newFilter);
} finally {
unlock();
}
} else {
synchronized (this) {
setFilter0(newFilter);
}
}
}
private void setFilter0(Filter newFilter) throws SecurityException {
checkPermission(); checkPermission();
filter = newFilter; filter = newFilter;
} }
@ -251,7 +317,21 @@ public abstract class Handler {
* @throws SecurityException if a security manager exists and if * @throws SecurityException if a security manager exists and if
* the caller does not have {@code LoggingPermission("control")}. * the caller does not have {@code LoggingPermission("control")}.
*/ */
public synchronized void setErrorManager(ErrorManager em) { public void setErrorManager(ErrorManager em) {
if (tryUseLock()) {
try {
setErrorManager0(em);
} finally {
unlock();
}
} else {
synchronized (this) {
setErrorManager0(em);
}
}
}
private void setErrorManager0(ErrorManager em) {
checkPermission(); checkPermission();
if (em == null) { if (em == null) {
throw new NullPointerException(); throw new NullPointerException();
@ -303,7 +383,21 @@ public abstract class Handler {
* @throws SecurityException if a security manager exists and if * @throws SecurityException if a security manager exists and if
* the caller does not have {@code LoggingPermission("control")}. * the caller does not have {@code LoggingPermission("control")}.
*/ */
public synchronized void setLevel(Level newLevel) throws SecurityException { public void setLevel(Level newLevel) throws SecurityException {
if (tryUseLock()) {
try {
setLevel0(newLevel);
} finally {
unlock();
}
} else {
synchronized (this) {
setLevel0(newLevel);
}
}
}
private void setLevel0(Level newLevel) throws SecurityException {
if (newLevel == null) { if (newLevel == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
@ -311,6 +405,8 @@ public abstract class Handler {
logLevel = newLevel; logLevel = newLevel;
} }
/** /**
* Get the log level specifying which messages will be * Get the log level specifying which messages will be
* logged by this {@code Handler}. Message levels lower * logged by this {@code Handler}. Message levels lower

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -178,7 +178,21 @@ public class MemoryHandler extends Handler {
* silently ignored and is not published * silently ignored and is not published
*/ */
@Override @Override
public synchronized void publish(LogRecord record) { public void publish(LogRecord record) {
if (tryUseLock()) {
try {
publish0(record);
} finally {
unlock();
}
} else {
synchronized (this) {
publish0(record);
}
}
}
private void publish0(LogRecord record) {
if (!isLoggable(record)) { if (!isLoggable(record)) {
return; return;
} }
@ -200,7 +214,21 @@ public class MemoryHandler extends Handler {
* <p> * <p>
* The buffer is then cleared. * The buffer is then cleared.
*/ */
public synchronized void push() { public void push() {
if (tryUseLock()) {
try {
push0();
} finally {
unlock();
}
} else {
synchronized (this) {
push0();
}
}
}
private void push0() {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
int ix = (start+i)%buffer.length; int ix = (start+i)%buffer.length;
LogRecord record = buffer[ix]; LogRecord record = buffer[ix];
@ -244,7 +272,21 @@ public class MemoryHandler extends Handler {
* @throws SecurityException if a security manager exists and if * @throws SecurityException if a security manager exists and if
* the caller does not have {@code LoggingPermission("control")}. * the caller does not have {@code LoggingPermission("control")}.
*/ */
public synchronized void setPushLevel(Level newLevel) throws SecurityException { public void setPushLevel(Level newLevel) throws SecurityException {
if (tryUseLock()) {
try {
setPushLevel0(newLevel);
} finally {
unlock();
}
} else {
synchronized (this) {
setPushLevel0(newLevel);
}
}
}
private void setPushLevel0(Level newLevel) throws SecurityException {
if (newLevel == null) { if (newLevel == null) {
throw new NullPointerException(); throw new NullPointerException();
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -156,7 +156,21 @@ public class SocketHandler extends StreamHandler {
* the caller does not have {@code LoggingPermission("control")}. * the caller does not have {@code LoggingPermission("control")}.
*/ */
@Override @Override
public synchronized void close() throws SecurityException { public void close() throws SecurityException {
if (tryUseLock()) {
try {
close0();
} finally {
unlock();
}
} else {
synchronized (this) {
close0();
}
}
}
private void close0() throws SecurityException {
super.close(); super.close();
if (sock != null) { if (sock != null) {
try { try {
@ -175,7 +189,21 @@ public class SocketHandler extends StreamHandler {
* silently ignored and is not published * silently ignored and is not published
*/ */
@Override @Override
public synchronized void publish(LogRecord record) { public void publish(LogRecord record) {
if (tryUseLock()) {
try {
publish0(record);
} finally {
unlock();
}
} else {
synchronized (this) {
publish0(record);
}
}
}
private void publish0(LogRecord record) {
if (!isLoggable(record)) { if (!isLoggable(record)) {
return; return;
} }

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -122,7 +122,21 @@ public class StreamHandler extends Handler {
* @throws SecurityException if a security manager exists and if * @throws SecurityException if a security manager exists and if
* the caller does not have {@code LoggingPermission("control")}. * the caller does not have {@code LoggingPermission("control")}.
*/ */
protected synchronized void setOutputStream(OutputStream out) throws SecurityException { protected void setOutputStream(OutputStream out) throws SecurityException {
if (tryUseLock()) {
try {
setOutputStream0(out);
} finally {
unlock();
}
} else {
synchronized (this) {
setOutputStream0(out);
}
}
}
private void setOutputStream0(OutputStream out) throws SecurityException {
if (out == null) { if (out == null) {
throw new NullPointerException(); throw new NullPointerException();
} }
@ -157,7 +171,21 @@ public class StreamHandler extends Handler {
* not supported. * not supported.
*/ */
@Override @Override
public synchronized void setEncoding(String encoding) public void setEncoding(String encoding)
throws SecurityException, java.io.UnsupportedEncodingException {
if (tryUseLock()) {
try {
setEncoding0(encoding);
} finally {
unlock();
}
} else {
synchronized (this) {
setEncoding0(encoding);
}
}
}
private void setEncoding0(String encoding)
throws SecurityException, java.io.UnsupportedEncodingException { throws SecurityException, java.io.UnsupportedEncodingException {
super.setEncoding(encoding); super.setEncoding(encoding);
if (output == null) { if (output == null) {
@ -190,7 +218,20 @@ public class StreamHandler extends Handler {
* silently ignored and is not published * silently ignored and is not published
*/ */
@Override @Override
public synchronized void publish(LogRecord record) { public void publish(LogRecord record) {
if (tryUseLock()) {
try {
publish0(record);
} finally {
unlock();
}
} else {
synchronized (this) {
publish0(record);
}
}
}
private void publish0(LogRecord record) {
if (!isLoggable(record)) { if (!isLoggable(record)) {
return; return;
} }
@ -241,7 +282,20 @@ public class StreamHandler extends Handler {
* Flush any buffered messages. * Flush any buffered messages.
*/ */
@Override @Override
public synchronized void flush() { public void flush() {
if (tryUseLock()) {
try {
flush0();
} finally {
unlock();
}
} else {
synchronized (this) {
flush0();
}
}
}
private void flush0() {
if (writer != null) { if (writer != null) {
try { try {
writer.flush(); writer.flush();
@ -253,7 +307,7 @@ public class StreamHandler extends Handler {
} }
} }
private synchronized void flushAndClose() throws SecurityException { private void flushAndClose() throws SecurityException {
checkPermission(); checkPermission();
if (writer != null) { if (writer != null) {
try { try {
@ -286,8 +340,18 @@ public class StreamHandler extends Handler {
* the caller does not have LoggingPermission("control"). * the caller does not have LoggingPermission("control").
*/ */
@Override @Override
public synchronized void close() throws SecurityException { public void close() throws SecurityException {
flushAndClose(); if (tryUseLock()) {
try {
flushAndClose();
} finally {
unlock();
}
} else {
synchronized (this) {
flushAndClose();
}
}
} }
// Package-private support for setting OutputStream // Package-private support for setting OutputStream