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

Reply via email to