Author: kkolinko
Date: Tue Feb  1 08:07:46 2011
New Revision: 1065945

URL: http://svn.apache.org/viewvc?rev=1065945&view=rev
Log:
Backport AprEndpoint shutdown patch (BZ 49795 and similar).

Modified:
    tomcat/tc6.0.x/trunk/STATUS.txt
    tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java
    tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml

Modified: tomcat/tc6.0.x/trunk/STATUS.txt
URL: 
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/STATUS.txt?rev=1065945&r1=1065944&r2=1065945&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/STATUS.txt (original)
+++ tomcat/tc6.0.x/trunk/STATUS.txt Tue Feb  1 08:07:46 2011
@@ -89,11 +89,6 @@ PATCHES PROPOSED TO BACKPORT:
               We can stall this item until we get some feedback about 7.0.5.
   -1:
 
-* Backport AprEndpoint shutdown patch (BZ49795 and similar).
-  http://people.apache.org/~kkolinko/patches/2011-01-24_tc6_aprshutdown.patch
-  +1: mturk, kkolinko, markt
-  -1:
-
 * Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=50642
   Better memory leak protection for HttpClient keep-alive thread
   http://svn.apache.org/viewvc?rev=1064652&view=rev

Modified: tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java
URL: 
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java?rev=1065945&r1=1065944&r2=1065945&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java 
(original)
+++ tomcat/tc6.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java Tue 
Feb  1 08:07:46 2011
@@ -157,6 +157,8 @@ public class AprEndpoint {
      */
     protected long sslContext = 0;
 
+    /* Acceptor thread array */
+    private Acceptor acceptors[] = null;
 
     // ------------------------------------------------------------- Properties
 
@@ -767,10 +769,10 @@ public class AprEndpoint {
             for (int i = 0; i < pollerThreadCount; i++) {
                 pollers[i] = new Poller(false);
                 pollers[i].init();
-                Thread pollerThread = new Thread(pollers[i], getName() + 
"-Poller-" + i);
-                pollerThread.setPriority(threadPriority);
-                pollerThread.setDaemon(true);
-                pollerThread.start();
+                pollers[i].setName(getName() + "-Poller-" + i);
+                pollers[i].setPriority(threadPriority);
+                pollers[i].setDaemon(true);
+                pollers[i].start();
             }
 
             // Start comet poller threads
@@ -778,10 +780,10 @@ public class AprEndpoint {
             for (int i = 0; i < pollerThreadCount; i++) {
                 cometPollers[i] = new Poller(true);
                 cometPollers[i].init();
-                Thread pollerThread = new Thread(cometPollers[i], getName() + 
"-CometPoller-" + i);
-                pollerThread.setPriority(threadPriority);
-                pollerThread.setDaemon(true);
-                pollerThread.start();
+                cometPollers[i].setName(getName() + "-CometPoller-" + i);
+                cometPollers[i].setPriority(threadPriority);
+                cometPollers[i].setDaemon(true);
+                cometPollers[i].start();
             }
 
             // Start sendfile threads
@@ -790,19 +792,21 @@ public class AprEndpoint {
                 for (int i = 0; i < sendfileThreadCount; i++) {
                     sendfiles[i] = new Sendfile();
                     sendfiles[i].init();
-                    Thread sendfileThread = new Thread(sendfiles[i], getName() 
+ "-Sendfile-" + i);
-                    sendfileThread.setPriority(threadPriority);
-                    sendfileThread.setDaemon(true);
-                    sendfileThread.start();
+                    sendfiles[i].setName(getName() + "-Sendfile-" + i);
+                    sendfiles[i].setPriority(threadPriority);
+                    sendfiles[i].setDaemon(true);
+                    sendfiles[i].start();
                 }
             }
 
             // Start acceptor threads
+            acceptors = new Acceptor[acceptorThreadCount];
             for (int i = 0; i < acceptorThreadCount; i++) {
-                Thread acceptorThread = new Thread(new Acceptor(), getName() + 
"-Acceptor-" + i);
-                acceptorThread.setPriority(threadPriority);
-                acceptorThread.setDaemon(daemon);
-                acceptorThread.start();
+                acceptors[i] = new Acceptor();
+                acceptors[i].setName(getName() + "-Acceptor-" + i);
+                acceptors[i].setPriority(threadPriority);
+                acceptors[i].setDaemon(getDaemon());
+                acceptors[i].start();
             }
 
         }
@@ -835,20 +839,56 @@ public class AprEndpoint {
      * Stop the endpoint. This will cause all processing threads to stop.
      */
     public void stop() {
+        if (!paused) {
+            pause();
+        }
         if (running) {
             running = false;
             unlockAccept();
+            for (int i = 0; i < acceptors.length; i++) {
+                long s = System.currentTimeMillis() + 30000;
+                while (acceptors[i].isAlive()) {
+                    try {
+                        acceptors[i].interrupt();
+                        acceptors[i].join(1000);
+                    } catch (InterruptedException e) {
+                        // Ignore
+                    }
+                    if (System.currentTimeMillis() >= s) {
+                        
log.warn(sm.getString("endpoint.warn.unlockAcceptorFailed",
+                                 acceptors[i].getName()));
+                        // If the Acceptor is still running force
+                        // the hard socket close.
+                        if (serverSock != 0) {
+                            Socket.shutdown(serverSock, 
Socket.APR_SHUTDOWN_READ);
+                            serverSock = 0;
+                        }
+                    }
+                }
+            }
             for (int i = 0; i < pollers.length; i++) {
-                pollers[i].destroy();
+                try {
+                    pollers[i].destroy();
+                } catch (Exception e) {
+                    // Ignore
+                }
             }
             pollers = null;
             for (int i = 0; i < cometPollers.length; i++) {
-                cometPollers[i].destroy();
+                try {
+                    cometPollers[i].destroy();
+                } catch (Exception e) {
+                    // Ignore
+                }
             }
             cometPollers = null;
             if (useSendfile) {
                 for (int i = 0; i < sendfiles.length; i++) {
-                    sendfiles[i].destroy();
+                    try {
+                        sendfiles[i].destroy();
+                    } catch (Exception e) {
+                        // Ignore
+                    }
                 }
                 sendfiles = null;
             }
@@ -863,15 +903,26 @@ public class AprEndpoint {
         if (running) {
             stop();
         }
-        Pool.destroy(serverSockPool);
-        serverSockPool = 0;
-        // Close server socket
-        Socket.close(serverSock);
-        serverSock = 0;
+        // Destroy pool if it was initialised
+        if (serverSockPool != 0) {
+            Pool.destroy(serverSockPool);
+            serverSockPool = 0;
+        }
+
+        // Close server socket if it was initialised
+        if (serverSock != 0) {
+            Socket.close(serverSock);
+            serverSock = 0;
+        }
+
         sslContext = 0;
-        // Close all APR memory pools and resources
-        Pool.destroy(rootPool);
-        rootPool = 0;
+
+        // Close all APR memory pools and resources if initialised
+        if (rootPool != 0) {
+            Pool.destroy(rootPool);
+            rootPool = 0;
+        }
+
         initialized = false;
     }
 
@@ -1136,6 +1187,15 @@ public class AprEndpoint {
         return true;
     }
 
+    private void destroySocket(long socket) {
+        if (running && socket != 0) {
+            // If not running the socket will be destroyed by
+            // parent pool or acceptor socket.
+            // In any case disable double free which would cause JVM core.
+            Socket.destroy(socket);
+        }
+    }
+
 
     // --------------------------------------------------- Acceptor Inner Class
 
@@ -1143,7 +1203,7 @@ public class AprEndpoint {
     /**
      * Server socket acceptor thread.
      */
-    protected class Acceptor implements Runnable {
+    protected class Acceptor extends Thread {
 
         private final Log log = LogFactory.getLog(AprEndpoint.Acceptor.class);
 
@@ -1157,7 +1217,7 @@ public class AprEndpoint {
             while (running) {
 
                 // Loop if endpoint is paused
-                while (paused) {
+                while (paused && running) {
                     try {
                         Thread.sleep(1000);
                     } catch (InterruptedException e) {
@@ -1165,6 +1225,9 @@ public class AprEndpoint {
                     }
                 }
 
+                if (!running) {
+                    break;
+                }
                 try {
                     // Accept the next incoming connection from the server 
socket
                     long socket = Socket.accept(serverSock);
@@ -1174,13 +1237,13 @@ public class AprEndpoint {
                      * socket and don't process it.
                      */
                     if (deferAccept && (paused || !running)) {
-                        Socket.destroy(socket);
+                        destroySocket(socket);
                         continue;
                     }
                     // Hand this socket off to an appropriate processor
                     if (!processSocketWithOptions(socket)) {
                         // Close socket and pool right away
-                        Socket.destroy(socket);
+                        destroySocket(socket);
                     }
                 } catch (Throwable t) {
                     if (running) {
@@ -1216,7 +1279,7 @@ public class AprEndpoint {
     /**
      * Poller class.
      */
-    public class Poller implements Runnable {
+    public class Poller extends Thread {
 
         protected long serverPollset = 0;
         protected long pool = 0;
@@ -1263,23 +1326,13 @@ public class AprEndpoint {
         /**
          * Destroy the poller.
          */
-        protected void destroy() {
-            // Wait for polltime before doing anything, so that the poller 
threads
-            // exit, otherwise parallel descturction of sockets which are still
-            // in the poller can cause problems
-            try {
-                synchronized (this) {
-                    this.wait(pollTime / 1000);
-                }
-            } catch (InterruptedException e) {
-                // Ignore
-            }
+        public void destroy() {
             // Close all sockets in the add queue
             for (int i = 0; i < addCount; i++) {
                 if (comet) {
                     processSocket(addS[i], SocketStatus.STOP);
                 } else {
-                    Socket.destroy(addS[i]);
+                    destroySocket(addS[i]);
                 }
             }
             // Close all sockets still in the poller
@@ -1289,13 +1342,21 @@ public class AprEndpoint {
                     if (comet) {
                         processSocket(desc[n*2+1], SocketStatus.STOP);
                     } else {
-                        Socket.destroy(desc[n*2+1]);
+                        destroySocket(desc[n*2+1]);
                     }
                 }
             }
             Pool.destroy(pool);
             keepAliveCount = 0;
             addCount = 0;
+            try {
+                while (this.isAlive()) {
+                    this.interrupt();
+                    this.join(1000);
+                }
+            } catch (InterruptedException e) {
+                // Ignore
+            }
         }
 
         /**
@@ -1315,7 +1376,7 @@ public class AprEndpoint {
                     if (comet) {
                         processSocket(socket, SocketStatus.ERROR);
                     } else {
-                        Socket.destroy(socket);
+                        destroySocket(socket);
                     }
                     return;
                 }
@@ -1335,7 +1396,7 @@ public class AprEndpoint {
             // Loop until we receive a shutdown command
             while (running) {
                 // Loop if endpoint is paused
-                while (paused) {
+                while (paused && running) {
                     try {
                         Thread.sleep(1000);
                     } catch (InterruptedException e) {
@@ -1343,9 +1404,12 @@ public class AprEndpoint {
                     }
                 }
 
+                if (!running) {
+                    break;
+                }
                 if (keepAliveCount < 1 && addCount < 1) {
                     synchronized (this) {
-                        while (keepAliveCount < 1 && addCount < 1) {
+                        while (keepAliveCount < 1 && addCount < 1 && running) {
                             // Reset maintain time.
                             maintainTime = 0;
                             try {
@@ -1357,6 +1421,9 @@ public class AprEndpoint {
                     }
                 }
 
+                if (!running) {
+                    break;
+                }
                 try {
                     // Add sockets which are waiting to the poller
                     if (addCount > 0) {
@@ -1373,7 +1440,7 @@ public class AprEndpoint {
                                         if (comet) {
                                             processSocket(addS[i], 
SocketStatus.ERROR);
                                         } else {
-                                            Socket.destroy(addS[i]);
+                                            destroySocket(addS[i]);
                                         }
                                     }
                                 }
@@ -1399,7 +1466,7 @@ public class AprEndpoint {
                                 if (comet) {
                                     processSocket(desc[n*2+1], 
SocketStatus.DISCONNECT);
                                 } else {
-                                    Socket.destroy(desc[n*2+1]);
+                                    destroySocket(desc[n*2+1]);
                                 }
                                 continue;
                             }
@@ -1430,7 +1497,7 @@ public class AprEndpoint {
                                 if (comet) {
                                     processSocket(desc[n], 
SocketStatus.TIMEOUT);
                                 } else {
-                                    Socket.destroy(desc[n]);
+                                    destroySocket(desc[n]);
                                 }
                             }
                         }
@@ -1444,9 +1511,7 @@ public class AprEndpoint {
             synchronized (this) {
                 this.notifyAll();
             }
-
         }
-
     }
 
 
@@ -1587,7 +1652,7 @@ public class AprEndpoint {
                         getPoller().add(socket);
                     } else {
                         // Close socket and pool
-                        Socket.destroy(socket);
+                        destroySocket(socket);
                         socket = 0;
                     }
                 } else {
@@ -1595,12 +1660,12 @@ public class AprEndpoint {
                     // Process the request from this socket
                     if ((status != null) && (handler.event(socket, status) == 
Handler.SocketState.CLOSED)) {
                         // Close socket and pool
-                        Socket.destroy(socket);
+                        destroySocket(socket);
                         socket = 0;
                     } else if ((status == null) && ((options && 
!setSocketOptions(socket))
                             || handler.process(socket) == 
Handler.SocketState.CLOSED)) {
                         // Close socket and pool
-                        Socket.destroy(socket);
+                        destroySocket(socket);
                         socket = 0;
                     }
                 }
@@ -1656,7 +1721,7 @@ public class AprEndpoint {
     /**
      * Sendfile class.
      */
-    public class Sendfile implements Runnable {
+    public class Sendfile extends Thread {
 
         protected long sendfilePollset = 0;
         protected long pool = 0;
@@ -1694,32 +1759,31 @@ public class AprEndpoint {
         /**
          * Destroy the poller.
          */
-        protected void destroy() {
-            // Wait for polltime before doing anything, so that the poller 
threads
-            // exit, otherwise parallel descturction of sockets which are still
-            // in the poller can cause problems
-            try {
-                synchronized (this) {
-                    this.wait(pollTime / 1000);
-                }
-            } catch (InterruptedException e) {
-                // Ignore
-            }
+        public void destroy() {
             // Close any socket remaining in the add queue
             addCount = 0;
             for (int i = (addS.size() - 1); i >= 0; i--) {
                 SendfileData data = addS.get(i);
-                Socket.destroy(data.socket);
+                destroySocket(data.socket);
             }
+            addS.clear();
             // Close all sockets still in the poller
             int rv = Poll.pollset(sendfilePollset, desc);
             if (rv > 0) {
                 for (int n = 0; n < rv; n++) {
-                    Socket.destroy(desc[n*2+1]);
+                    destroySocket(desc[n*2+1]);
                 }
             }
             Pool.destroy(pool);
             sendfileData.clear();
+            try {
+                while (this.isAlive()) {
+                    this.interrupt();
+                    this.join(1000);
+                }
+            } catch (InterruptedException e) {
+                // Ignore
+            }
         }
 
         /**
@@ -1748,7 +1812,7 @@ public class AprEndpoint {
                                                data.pos, data.end - data.pos, 
0);
                     if (nw < 0) {
                         if (!(-nw == Status.EAGAIN)) {
-                            Socket.destroy(data.socket);
+                            destroySocket(data.socket);
                             data.socket = 0;
                             return false;
                         } else {
@@ -1804,7 +1868,7 @@ public class AprEndpoint {
             while (running) {
 
                 // Loop if endpoint is paused
-                while (paused) {
+                while (paused && running) {
                     try {
                         Thread.sleep(1000);
                     } catch (InterruptedException e) {
@@ -1812,9 +1876,12 @@ public class AprEndpoint {
                     }
                 }
 
+                if (!running) {
+                    break;
+                }
                 if (sendfileCount < 1 && addCount < 1) {
                     synchronized (this) {
-                        while (sendfileCount < 1 && addS.size() < 1) {
+                        while (sendfileCount < 1 && addS.size() < 1 && 
running) {
                             // Reset maintain time.
                             maintainTime = 0;
                             try {
@@ -1826,6 +1893,9 @@ public class AprEndpoint {
                     }
                 }
 
+                if (!running) {
+                    break;
+                }
                 try {
                     // Add socket to the poller
                     if (addCount > 0) {
@@ -1841,7 +1911,7 @@ public class AprEndpoint {
                                     } else {
                                         
log.warn(sm.getString("endpoint.sendfile.addfail", "" + rv, 
Error.strerror(rv)));
                                         // Can't do anything: close the socket 
right away
-                                        Socket.destroy(data.socket);
+                                        destroySocket(data.socket);
                                     }
                                 }
                             } finally {
@@ -1867,7 +1937,7 @@ public class AprEndpoint {
                                 remove(state);
                                 // Destroy file descriptor pool, which should 
close the file
                                 // Close the socket, as the reponse would be 
incomplete
-                                Socket.destroy(state.socket);
+                                destroySocket(state.socket);
                                 continue;
                             }
                             // Write some data using sendfile
@@ -1879,7 +1949,7 @@ public class AprEndpoint {
                                 remove(state);
                                 // Close the socket, as the reponse would be 
incomplete
                                 // This will close the file too.
-                                Socket.destroy(state.socket);
+                                destroySocket(state.socket);
                                 continue;
                             }
 
@@ -1896,7 +1966,7 @@ public class AprEndpoint {
                                 } else {
                                     // Close the socket since this is
                                     // the end of not keep-alive request.
-                                    Socket.destroy(state.socket);
+                                    destroySocket(state.socket);
                                 }
                             }
                         }
@@ -1928,7 +1998,7 @@ public class AprEndpoint {
                                 remove(state);
                                 // Destroy file descriptor pool, which should 
close the file
                                 // Close the socket, as the response would be 
incomplete
-                                Socket.destroy(state.socket);
+                                destroySocket(state.socket);
                             }
                         }
                     }
@@ -2064,7 +2134,7 @@ public class AprEndpoint {
                     getPoller().add(socket);
                 } else {
                     // Close socket and pool
-                    Socket.destroy(socket);
+                    destroySocket(socket);
                     socket = 0;
                 }
             } else {
@@ -2072,7 +2142,7 @@ public class AprEndpoint {
                 if (!setSocketOptions(socket)
                         || handler.process(socket) == 
Handler.SocketState.CLOSED) {
                     // Close socket and pool
-                    Socket.destroy(socket);
+                    destroySocket(socket);
                     socket = 0;
                 }
             }
@@ -2102,7 +2172,7 @@ public class AprEndpoint {
             // Process the request from this socket
             if (handler.process(socket) == Handler.SocketState.CLOSED) {
                 // Close socket and pool
-                Socket.destroy(socket);
+                destroySocket(socket);
                 socket = 0;
             }
 
@@ -2133,7 +2203,7 @@ public class AprEndpoint {
             // Process the request from this socket
             if (handler.event(socket, status) == Handler.SocketState.CLOSED) {
                 // Close socket and pool
-                Socket.destroy(socket);
+                destroySocket(socket);
                 socket = 0;
             }
 

Modified: tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml?rev=1065945&r1=1065944&r2=1065945&view=diff
==============================================================================
--- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Tue Feb  1 08:07:46 2011
@@ -55,6 +55,10 @@
   <subsection name="Coyote">
     <changelog>
       <fix>
+        <bug>49795</bug>: Backport AprEndpoint shutdown improvements, to make
+        it more robust. (mturk/kkolinko)
+      </fix>
+      <fix>
         <bug>50651</bug>: Fix NPE in InternalNioOutputBuffer.recycle().
         (kkolinko)
       </fix>



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to