This is an automated email from the ASF dual-hosted git repository.

cziegeler pushed a commit to branch SLING-11824
in repository 
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-engine.git


The following commit(s) were added to refs/heads/SLING-11824 by this push:
     new e3eb182  SLING-11824 : Deadlock during repository restart
e3eb182 is described below

commit e3eb182770ab99fa49204fd80d8d78de4a3e1937
Author: Carsten Ziegeler <[email protected]>
AuthorDate: Tue Apr 11 17:58:21 2023 +0200

    SLING-11824 : Deadlock during repository restart
---
 .../engine/impl/helper/SlingServletContext.java    | 92 ++++++++++++++++------
 1 file changed, 68 insertions(+), 24 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/engine/impl/helper/SlingServletContext.java 
b/src/main/java/org/apache/sling/engine/impl/helper/SlingServletContext.java
index 3b60d35..d8bcb43 100644
--- a/src/main/java/org/apache/sling/engine/impl/helper/SlingServletContext.java
+++ b/src/main/java/org/apache/sling/engine/impl/helper/SlingServletContext.java
@@ -116,6 +116,9 @@ public class SlingServletContext implements ServletContext, 
ServletContextListen
 
     private volatile String configuredServerInfo;
 
+    // counter to synchronize the init and destroy methods
+    private volatile long initCounter;
+
     private volatile ServletContext servletContext;
 
     private volatile ServiceRegistration<ServletContext> registration;
@@ -199,37 +202,78 @@ public class SlingServletContext implements 
ServletContext, ServletContextListen
         }
     }
 
-    @Override
-    public void contextDestroyed(final ServletContextEvent sce) {
-        synchronized ( this ) {
-            this.servletContext = null;
-            this.setServerInfo();
-            if ( this.registration != null ) {
-                this.registration.unregister();
-                this.registration = null;    
-            }
+    private void runAsync(final Runnable r) {
+        final Thread thread = new Thread(r, "SlingServletContext 
registration");
+        thread.setDaemon(true);
+        thread.start();
+    }
+
+    private ServiceRegistration<ServletContext> registerServletContext() {
+        final Dictionary<String, Object> props = new Hashtable<String, 
Object>();
+        props.put("name", SlingHttpContext.SERVLET_CONTEXT_NAME); // property 
to identify this context
+        return bundleContext.registerService(ServletContext.class, 
SlingServletContext.this, props);
+    }
+
+    private void unregisterServletContext(final 
ServiceRegistration<ServletContext> reg) {
+        try {
+            reg.unregister();
+        } catch (final IllegalStateException ise) {
+            // ignore
         }
     }
 
     @Override
     public void contextInitialized(final ServletContextEvent sce) {
-        this.servletContext = sce.getServletContext();
-        this.setServerInfo();
-        // async registreation
-        final Thread thread = new Thread("SlingServletContext registration") {
-            @Override
-            public void run() {
-                synchronized (SlingServletContext.this) {
-                    if ( servletContext != null ) {
-                        final Dictionary<String, Object> props = new 
Hashtable<String, Object>();
-                        props.put("name", 
SlingHttpContext.SERVLET_CONTEXT_NAME); // property to identify this context
-                        registration = 
bundleContext.registerService(ServletContext.class, SlingServletContext.this, 
props);        
+        final ServletContext delegatee;
+        final long counter;
+        synchronized ( this ) {
+            this.servletContext = sce.getServletContext();
+            this.setServerInfo();
+            delegatee = this.servletContext;
+            this.initCounter++;
+            counter = this.initCounter;
+        }
+        if ( delegatee != null ) {
+            // async registration
+            this.runAsync(() -> {
+                final boolean register;
+                synchronized ( SlingServletContext.this ) {
+                    register = SlingServletContext.this.servletContext == 
delegatee;
+                }
+                if ( register ) {
+                    final ServiceRegistration<ServletContext> reg = 
registerServletContext();
+                    boolean immediatelyUnregister = false;
+                    synchronized ( SlingServletContext.this ) {
+                        if ( SlingServletContext.this.initCounter == counter ) 
{
+                            SlingServletContext.this.registration = reg;
+                        } else {
+                            immediatelyUnregister = true;
+                        }
+                    }
+                    if ( immediatelyUnregister ) {
+                        unregisterServletContext(reg);
                     }
                 }
-            }
-        };
-        thread.setDaemon(true);
-        thread.start();
+            });
+        }
+    }
+
+    @Override
+    public void contextDestroyed(final ServletContextEvent sce) {
+        final ServiceRegistration<ServletContext> reg;
+        synchronized ( this ) {
+            this.initCounter++;
+            reg = this.registration;
+            this.registration = null;
+            this.servletContext = null;
+            this.setServerInfo();
+        }
+        if ( reg != null ) {
+            // async unregistration
+            this.runAsync(() -> {
+                unregisterServletContext(reg);
+            });
+        }
     }
 
     /**

Reply via email to