This is an automated email from the ASF dual-hosted git repository. remm pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/9.0.x by this push: new 047daa0d0f Also add a lock for connectors 047daa0d0f is described below commit 047daa0d0fc1ac7a388d1ee672d22501dae76e85 Author: remm <r...@apache.org> AuthorDate: Wed Apr 3 16:49:11 2024 +0200 Also add a lock for connectors --- java/org/apache/catalina/core/StandardService.java | 107 +++++++++++---------- webapps/docs/changelog.xml | 6 +- 2 files changed, 63 insertions(+), 50 deletions(-) diff --git a/java/org/apache/catalina/core/StandardService.java b/java/org/apache/catalina/core/StandardService.java index a194c3dd6e..dbb32e55ce 100644 --- a/java/org/apache/catalina/core/StandardService.java +++ b/java/org/apache/catalina/core/StandardService.java @@ -20,6 +20,9 @@ package org.apache.catalina.core; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.util.ArrayList; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; import javax.management.ObjectName; @@ -76,7 +79,7 @@ public class StandardService extends LifecycleMBeanBase implements Service { * The set of Connectors associated with this Service. */ protected Connector connectors[] = new Connector[0]; - private final Object connectorsLock = new Object(); + private final ReadWriteLock connectorsLock = new ReentrantReadWriteLock(); /** * The list of executors held by the service. @@ -219,12 +222,16 @@ public class StandardService extends LifecycleMBeanBase implements Service { @Override public void addConnector(Connector connector) { - synchronized (connectorsLock) { + Lock writeLock = connectorsLock.writeLock(); + writeLock.lock(); + try { connector.setService(this); Connector results[] = new Connector[connectors.length + 1]; System.arraycopy(connectors, 0, results, 0, connectors.length); results[connectors.length] = connector; connectors = results; + } finally { + writeLock.unlock(); } try { @@ -241,12 +248,16 @@ public class StandardService extends LifecycleMBeanBase implements Service { public ObjectName[] getConnectorNames() { - synchronized (connectorsLock) { + Lock readLock = connectorsLock.readLock(); + readLock.lock(); + try { ObjectName results[] = new ObjectName[connectors.length]; for (int i = 0; i < results.length; i++) { results[i] = connectors[i].getObjectName(); } return results; + } finally { + readLock.unlock(); } } @@ -266,9 +277,13 @@ public class StandardService extends LifecycleMBeanBase implements Service { */ @Override public Connector[] findConnectors() { - synchronized (connectorsLock) { + Lock readLock = connectorsLock.readLock(); + readLock.lock(); + try { // shallow copy return connectors.clone(); + } finally { + readLock.unlock(); } } @@ -282,7 +297,9 @@ public class StandardService extends LifecycleMBeanBase implements Service { @Override public void removeConnector(Connector connector) { - synchronized (connectorsLock) { + Lock writeLock = connectorsLock.writeLock(); + writeLock.lock(); + try { int j = -1; for (int i = 0; i < connectors.length; i++) { if (connector == connectors[i]) { @@ -312,7 +329,10 @@ public class StandardService extends LifecycleMBeanBase implements Service { // Report this property change to interested listeners support.firePropertyChange("connector", connector, null); + } finally { + writeLock.unlock(); } + } @@ -443,12 +463,10 @@ public class StandardService extends LifecycleMBeanBase implements Service { mapperListener.start(); // Start our defined Connectors second - synchronized (connectorsLock) { - for (Connector connector : connectors) { - // If it has already failed, don't try and start it - if (connector.getState() != LifecycleState.FAILED) { - connector.start(); - } + for (Connector connector : findConnectors()) { + // If it has already failed, don't try and start it + if (connector.getState() != LifecycleState.FAILED) { + connector.start(); } } } @@ -463,28 +481,27 @@ public class StandardService extends LifecycleMBeanBase implements Service { @Override protected void stopInternal() throws LifecycleException { - synchronized (connectorsLock) { - // Initiate a graceful stop for each connector - // This will only work if the bindOnInit==false which is not the - // default. - for (Connector connector : connectors) { - connector.getProtocolHandler().closeServerSocketGraceful(); - } - - // Wait for the graceful shutdown to complete - long waitMillis = gracefulStopAwaitMillis; - if (waitMillis > 0) { - for (Connector connector : connectors) { - waitMillis = connector.getProtocolHandler().awaitConnectionsClose(waitMillis); - } - } + Connector[] connectors = findConnectors(); + // Initiate a graceful stop for each connector + // This will only work if the bindOnInit==false which is not the + // default. + for (Connector connector : connectors) { + connector.getProtocolHandler().closeServerSocketGraceful(); + } - // Pause the connectors + // Wait for the graceful shutdown to complete + long waitMillis = gracefulStopAwaitMillis; + if (waitMillis > 0) { for (Connector connector : connectors) { - connector.pause(); + waitMillis = connector.getProtocolHandler().awaitConnectionsClose(waitMillis); } } + // Pause the connectors + for (Connector connector : connectors) { + connector.pause(); + } + if (log.isInfoEnabled()) { log.info(sm.getString("standardService.stop.name", this.name)); } @@ -498,16 +515,14 @@ public class StandardService extends LifecycleMBeanBase implements Service { } // Now stop the connectors - synchronized (connectorsLock) { - for (Connector connector : connectors) { - if (!LifecycleState.STARTED.equals(connector.getState())) { - // Connectors only need stopping if they are currently - // started. They may have failed to start or may have been - // stopped (e.g. via a JMX call) - continue; - } - connector.stop(); + for (Connector connector : connectors) { + if (!LifecycleState.STARTED.equals(connector.getState())) { + // Connectors only need stopping if they are currently + // started. They may have failed to start or may have been + // stopped (e.g. via a JMX call) + continue; } + connector.stop(); } // If the Server failed to start, the mapperListener won't have been @@ -516,10 +531,8 @@ public class StandardService extends LifecycleMBeanBase implements Service { mapperListener.stop(); } - synchronized (executors) { - for (Executor executor : executors) { - executor.stop(); - } + for (Executor executor : findExecutors()) { + executor.stop(); } } @@ -549,10 +562,8 @@ public class StandardService extends LifecycleMBeanBase implements Service { mapperListener.init(); // Initialize our defined Connectors - synchronized (connectorsLock) { - for (Connector connector : connectors) { - connector.init(); - } + for (Connector connector : findConnectors()) { + connector.init(); } } @@ -562,10 +573,8 @@ public class StandardService extends LifecycleMBeanBase implements Service { mapperListener.destroy(); // Destroy our defined Connectors - synchronized (connectorsLock) { - for (Connector connector : connectors) { - connector.destroy(); - } + for (Connector connector : findConnectors()) { + connector.destroy(); } // Destroy any Executors diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml index 735429b85d..c7fbb6e342 100644 --- a/webapps/docs/changelog.xml +++ b/webapps/docs/changelog.xml @@ -128,7 +128,11 @@ Change the thread-safety mechanism for protecting StandardServer.services from a simple synchronized lock to a ReentrantReadWriteLock to allow multiple readers to operate simultaneously. Based upon a suggestion by - Markus Wolfe (schultz). + Markus Wolfe. (schultz) + </fix> + <fix> + Improve Service connectors access sync using a ReentrantReadWriteLock. + (remm) </fix> </changelog> </subsection> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org