Author: markt
Date: Tue May 13 22:51:19 2014
New Revision: 1594411

URL: http://svn.apache.org/r1594411
Log:
Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=56518
Refactor NIO's SocketProcessor to use KeyAtrtachment rather than Socket to 
align it with the other implementations. This enables a number of 
attachment->socket->attachment transitions to be skipped which appears to 
resolve the root cause of BZ 56518. Since the wrapper is available and can be 
processed, it becomes possible to reduce the connection count when the socket 
is closed by the interrupt.

Modified:
    tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java
    tomcat/trunk/webapps/docs/changelog.xml

Modified: tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java?rev=1594411&r1=1594410&r2=1594411&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/util/net/NioEndpoint.java Tue May 13 
22:51:19 2014
@@ -605,23 +605,22 @@ public class NioEndpoint extends Abstrac
     public void processSocket(SocketWrapper<NioChannel> socketWrapper,
             SocketStatus socketStatus, boolean dispatch) {
         NioChannel socket = socketWrapper.getSocket();
-        if (dispatch && socketStatus == SocketStatus.OPEN_READ) {
+        if (socket.isOpen() && dispatch && socketStatus == 
SocketStatus.OPEN_READ) {
             socket.getPoller().add(socket, OP_CALLBACK);
         } else {
-            processSocket(socket, socketStatus, dispatch);
+            processSocket((KeyAttachment) socketWrapper, socketStatus, 
dispatch);
         }
     }
 
-    protected boolean processSocket(NioChannel socket, SocketStatus status, 
boolean dispatch) {
+    protected boolean processSocket(KeyAttachment attachment, SocketStatus 
status, boolean dispatch) {
         try {
-            KeyAttachment attachment = 
(KeyAttachment)socket.getAttachment(false);
             if (attachment == null) {
                 return false;
             }
             attachment.setCometNotify(false); //will get reset upon next reg
             SocketProcessor sc = processorCache.pop();
-            if ( sc == null ) sc = new SocketProcessor(socket,status);
-            else sc.reset(socket,status);
+            if ( sc == null ) sc = new SocketProcessor(attachment, status);
+            else sc.reset(attachment, status);
             Executor executor = getExecutor();
             if (dispatch && executor != null) {
                 executor.execute(sc);
@@ -629,7 +628,7 @@ public class NioEndpoint extends Abstrac
                 sc.run();
             }
         } catch (RejectedExecutionException ree) {
-            log.warn(sm.getString("endpoint.executor.fail", socket), ree);
+            log.warn(sm.getString("endpoint.executor.fail", 
attachment.getSocket()), ree);
             return false;
         } catch (Throwable t) {
             ExceptionUtils.handleThrowable(t);
@@ -900,7 +899,8 @@ public class NioEndpoint extends Abstrac
             }
             addEvent(r);
             if (close) {
-                processSocket(socket, SocketStatus.STOP, false);
+                NioEndpoint.KeyAttachment ka = 
(NioEndpoint.KeyAttachment)socket.getAttachment(false);
+                processSocket(ka, SocketStatus.STOP, false);
             }
         }
 
@@ -956,12 +956,12 @@ public class NioEndpoint extends Abstrac
                 if (ka != null && ka.isComet() && status != null) {
                     ka.setComet(false);//to avoid a loop
                     if (status == SocketStatus.TIMEOUT ) {
-                        if (processSocket(ka.getSocket(), status, true)) {
+                        if (processSocket(ka, status, true)) {
                             return; // don't close on comet timeout
                         }
                     } else {
                         // Don't dispatch if the lines below are canceling the 
key
-                        processSocket(ka.getSocket(), status, false);
+                        processSocket(ka, status, false);
                     }
                 }
                 key.attach(null);
@@ -1126,7 +1126,6 @@ public class NioEndpoint extends Abstrac
                     cancelledKey(sk, SocketStatus.STOP);
                 } else if ( sk.isValid() && attachment != null ) {
                     attachment.access();//make sure we don't time out valid 
sockets
-                    NioChannel channel = attachment.getSocket();
                     if (sk.isReadable() || sk.isWritable() ) {
                         if ( attachment.getSendfileData() != null ) {
                             processSendfile(sk,attachment, false);
@@ -1136,12 +1135,12 @@ public class NioEndpoint extends Abstrac
                                 boolean closeSocket = false;
                                 // Read goes before write
                                 if (sk.isReadable()) {
-                                    if (!processSocket(channel, 
SocketStatus.OPEN_READ, true)) {
+                                    if (!processSocket(attachment, 
SocketStatus.OPEN_READ, true)) {
                                         closeSocket = true;
                                     }
                                 }
                                 if (!closeSocket && sk.isWritable()) {
-                                    if (!processSocket(channel, 
SocketStatus.OPEN_WRITE, true)) {
+                                    if (!processSocket(attachment, 
SocketStatus.OPEN_WRITE, true)) {
                                         closeSocket = true;
                                     }
                                 }
@@ -1302,7 +1301,7 @@ public class NioEndpoint extends Abstrac
                         int ops = ka.interestOps() & ~OP_CALLBACK;
                         reg(key,ka,0);//avoid multiple calls, this gets 
re-registered after invocation
                         ka.interestOps(ops);
-                        if (!processSocket(ka.getSocket(), 
SocketStatus.OPEN_READ, true)) processSocket(ka.getSocket(), 
SocketStatus.DISCONNECT, true);
+                        if (!processSocket(ka, SocketStatus.OPEN_READ, true)) 
processSocket(ka, SocketStatus.DISCONNECT, true);
                     } else if ((ka.interestOps()&SelectionKey.OP_READ) == 
SelectionKey.OP_READ ||
                               (ka.interestOps()&SelectionKey.OP_WRITE) == 
SelectionKey.OP_WRITE) {
                         //only timeout sockets that we are waiting for a read 
from
@@ -1331,7 +1330,7 @@ public class NioEndpoint extends Abstrac
                             if (isTimedout) {
                                 // Prevent subsequent timeouts if the timeout 
event takes a while to process
                                 ka.access(Long.MAX_VALUE);
-                                processSocket(ka.getSocket(), 
SocketStatus.TIMEOUT, true);
+                                processSocket(ka, SocketStatus.TIMEOUT, true);
                             }
                         }
                     }//end if
@@ -1493,27 +1492,23 @@ public class NioEndpoint extends Abstrac
      */
     protected class SocketProcessor implements Runnable {
 
-        private NioChannel socket = null;
+        private KeyAttachment ka = null;
         private SocketStatus status = null;
 
-        public SocketProcessor(NioChannel socket, SocketStatus status) {
-            reset(socket,status);
+        public SocketProcessor(KeyAttachment ka, SocketStatus status) {
+            reset(ka, status);
         }
 
-        public void reset(NioChannel socket, SocketStatus status) {
-            this.socket = socket;
+        public void reset(KeyAttachment ka, SocketStatus status) {
+            this.ka = ka;
             this.status = status;
         }
 
         @Override
         public void run() {
+            NioChannel socket = ka.getSocket();
             SelectionKey key = socket.getIOChannel().keyFor(
                     socket.getPoller().getSelector());
-            KeyAttachment ka = null;
-
-            if (key != null) {
-                ka = (KeyAttachment)key.attachment();
-            }
 
             // Upgraded connections need to allow multiple threads to access 
the
             // connection at the same time to enable blocking IO to be used 
when
@@ -1531,6 +1526,8 @@ public class NioEndpoint extends Abstrac
         }
 
         private void doRun(SelectionKey key, KeyAttachment ka) {
+            NioChannel socket = ka.getSocket();
+
             try {
                 int handshake = -1;
 
@@ -1571,20 +1568,20 @@ public class NioEndpoint extends Abstrac
                     if (state == SocketState.CLOSED) {
                         // Close socket and pool
                         try {
-                            if (ka!=null) ka.setComet(false);
+                            ka.setComet(false);
                             socket.getPoller().cancelledKey(key, 
SocketStatus.ERROR);
                             if (running && !paused) {
                                 nioChannels.push(socket);
                             }
                             socket = null;
-                            if (running && !paused && ka != null) {
+                            if (running && !paused) {
                                 keyCache.push(ka);
                             }
                             ka = null;
                         } catch (Exception x) {
                             log.error("",x);
                         }
-                    } else if (state == SocketState.LONG && ka != null && 
ka.isAsync() && ka.interestOps() > 0) {
+                    } else if (state == SocketState.LONG && ka.isAsync() && 
ka.interestOps() > 0) {
                         //we are async, and we are interested in operations
                         ka.getPoller().add(socket, ka.interestOps());
                     }
@@ -1596,7 +1593,7 @@ public class NioEndpoint extends Abstrac
                         nioChannels.push(socket);
                     }
                     socket = null;
-                    if (running && !paused && ka != null) {
+                    if (running && !paused) {
                         keyCache.push(ka);
                     }
                     ka = null;
@@ -1604,7 +1601,9 @@ public class NioEndpoint extends Abstrac
                     ka.getPoller().add(socket,handshake);
                 }
             } catch (CancelledKeyException cx) {
-                socket.getPoller().cancelledKey(key, null);
+                if (socket != null) {
+                    socket.getPoller().cancelledKey(key, null);
+                }
             } catch (OutOfMemoryError oom) {
                 try {
                     oomParachuteData = null;

Modified: tomcat/trunk/webapps/docs/changelog.xml
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/changelog.xml?rev=1594411&r1=1594410&r2=1594411&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/changelog.xml (original)
+++ tomcat/trunk/webapps/docs/changelog.xml Tue May 13 22:51:19 2014
@@ -232,6 +232,10 @@
       <fix>
         Fix possible corruption if doing keepalive after a comet request. 
(remm)
       </fix>
+      <fix>
+        <bug>56518</bug>: Fix connection limit latch leak when a non-container
+        thread is interrupted during asynchronous processing. (markt) 
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Jasper">



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

Reply via email to