Author: markt Date: Mon Sep 30 07:45:09 2013 New Revision: 1527472 URL: http://svn.apache.org/r1527472 Log: Removal of a socket from the poller needs to happen on the poller thread as removal, like addition, is not thread safe. Removal of a socket from the poller needs to remove the socket from the addListif it is present otherwise the closed socket could end up in the poller.
Modified: tomcat/tc7.0.x/trunk/ (props changed) tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Propchange: tomcat/tc7.0.x/trunk/ ------------------------------------------------------------------------------ Merged /tomcat/trunk:r1526052 Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java?rev=1527472&r1=1527471&r2=1527472&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/util/net/AprEndpoint.java Mon Sep 30 07:45:09 2013 @@ -899,7 +899,7 @@ public class AprEndpoint extends Abstrac // countDownConnection() in that case Poller poller = this.poller; if (poller != null) { - poller.removeFromPoller(socket); + poller.remove(socket); } connections.remove(Long.valueOf(socket)); destroySocket(socket, running); @@ -1212,6 +1212,19 @@ public class AprEndpoint extends Abstrac } } + public boolean remove(long socket) { + for (int i = 0; i < size; i++) { + if (sockets[i] == socket) { + sockets[i] = sockets[size - 1]; + timeouts[i] = timeouts[size - 1]; + flags[size] = flags[size -1]; + size--; + return true; + } + } + return false; + } + public void duplicate(SocketList copy) { copy.size = size; copy.pos = pos; @@ -1268,6 +1281,12 @@ public class AprEndpoint extends Abstrac /** + * List of sockets to be removed from the poller. + */ + private SocketList removeList = null; + + + /** * Structure used for storing timeouts. */ protected SocketTimeouts timeouts = null; @@ -1341,6 +1360,7 @@ public class AprEndpoint extends Abstrac desc = new long[actualPollerSize * 2]; connectionCount = 0; addList = new SocketList(defaultPollerSize); + removeList = new SocketList(defaultPollerSize); } @@ -1456,8 +1476,10 @@ public class AprEndpoint extends Abstrac } } + /** - * Add specified socket to one of the pollers. + * Add specified socket to one of the pollers. Must only be called from + * {@link Poller#run()}. */ protected boolean addToPoller(long socket, int events) { int rv = -1; @@ -1474,10 +1496,19 @@ public class AprEndpoint extends Abstrac return false; } + + protected void remove(long socket) { + synchronized (this) { + removeList.add(socket, 0, 0); + } + } + + /** - * Remove specified socket from the pollers. + * Remove specified socket from the pollers. Must only be called from + * {@link Poller#run()}. */ - protected boolean removeFromPoller(long socket) { + private boolean removeFromPoller(long socket) { int rv = -1; for (int i = 0; i < pollers.length; i++) { if (pollerSpace[i] < actualPollerSize) { @@ -1552,7 +1583,7 @@ public class AprEndpoint extends Abstrac int maintain = 0; SocketList localAddList = new SocketList(getMaxConnections()); - + SocketList localRemoveList = new SocketList(getMaxConnections()); // Loop until we receive a shutdown command while (pollerRunning) { @@ -1590,7 +1621,18 @@ public class AprEndpoint extends Abstrac } try { - // Add sockets which are waiting to the poller + // Duplicate the add and remove lists so that the syncs are + // minimised + if (removeList.size() > 0) { + synchronized (this) { + // Duplicate to another list, so that the syncing is + // minimal + removeList.duplicate(localRemoveList); + removeList.clear(); + } + } else { + localAddList.clear(); + } if (addList.size() > 0) { synchronized (this) { // Duplicate to another list, so that the syncing is @@ -1598,6 +1640,22 @@ public class AprEndpoint extends Abstrac addList.duplicate(localAddList); addList.clear(); } + } else { + localAddList.clear(); + } + + // Remove sockets + if (localRemoveList.size() > 0) { + SocketInfo info = localRemoveList.get(); + while (info != null) { + localAddList.remove(info.socket); + removeFromPoller(info.socket); + info = localRemoveList.get(); + } + } + + // Add sockets which are waiting to the poller + if (localAddList.size() > 0) { SocketInfo info = localAddList.get(); while (info != null) { if (log.isDebugEnabled()) { Modified: tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml?rev=1527472&r1=1527471&r2=1527472&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Mon Sep 30 07:45:09 2013 @@ -59,9 +59,13 @@ <subsection name="Coyote"> <changelog> <scode> - Refactor APR endpoint to reduce scope of <code>localAddList</code>. - (markt) + Refactor APR/native connector to reduce the scope of + <code>localAddList</code>. (markt) </scode> + <fix> + Ensure that sockets removed from the Poller in the APR/native connector + are removed in a thread-safe manner. (markt) + </fix> </changelog> </subsection> <subsection name="Cluster"> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org