Author: markt Date: Wed Sep 3 13:41:05 2014 New Revision: 1622253 URL: http://svn.apache.org/r1622253 Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=56905 Make destruction on web application stop of thread group used for WebSocket connections more robust. Patch by kkolinko with minor tweaks
Modified: tomcat/tc7.0.x/trunk/ (props changed) tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/server/LocalStrings.properties tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/server/WsServerContainer.java tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Propchange: tomcat/tc7.0.x/trunk/ ------------------------------------------------------------------------------ Merged /tomcat/trunk:r1622251 Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/server/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/server/LocalStrings.properties?rev=1622253&r1=1622252&r2=1622253&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/server/LocalStrings.properties (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/server/LocalStrings.properties Wed Sep 3 13:41:05 2014 @@ -24,7 +24,7 @@ serverContainer.missingEndpoint=An Endpo serverContainer.pojoDeploy=POJO class [{0}] deploying to path [{1}] in ServletContext [{2}] serverContainer.servletContextMismatch=Attempted to register a POJO annotated for WebSocket at path [{0}] in the ServletContext with context path [{1}] when the WebSocket ServerContainer is allocated to the ServletContext with context path [{2}] serverContainer.servletContextMissing=No ServletContext was specified -serverContainer.threadGroupNotDestroyed=Unable to destroy WebSocket thread group [{0}] as some threads were still running when the web application was stopped +serverContainer.threadGroupNotDestroyed=Unable to destroy WebSocket thread group [{0}] as [{1}] threads were still running when the web application was stopped. The thread group will be destroyed once the threads terminate. uriTemplate.duplicateParameter=The parameter [{0}] appears more than once in the path which is not permitted uriTemplate.emptySegment=The path [{0}] contains one or more empty segments which are is not permitted Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/server/WsServerContainer.java URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/server/WsServerContainer.java?rev=1622253&r1=1622252&r2=1622253&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/server/WsServerContainer.java (original) +++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/server/WsServerContainer.java Wed Sep 3 13:41:05 2014 @@ -276,14 +276,42 @@ public class WsServerContainer extends W public void destroy() { shutdownExecutor(); super.destroy(); + // If the executor hasn't fully shutdown it won't be possible to + // destroy this thread group as there will still be threads running. + // Mark the thread group as daemon one, so that it destroys itself + // when thread count reaches zero. + // Synchronization on threadGroup is needed, as there is a race between + // destroy() call from termination of the last thread in thread group + // marked as daemon versus the explicit destroy() call. + int threadCount = threadGroup.activeCount(); + boolean success = false; try { - threadGroup.destroy(); - } catch (IllegalThreadStateException itse) { - // If the executor hasn't fully shutdown it won't be possible to - // destroy this thread group as there will still be threads running - log.warn(sm.getString("serverContainer.threadGroupNotDestroyed", - threadGroup.getName())); + while (true) { + int oldThreadCount = threadCount; + synchronized (threadGroup) { + if (threadCount > 0) { + Thread.yield(); + threadCount = threadGroup.activeCount(); + } + if (threadCount > 0 && threadCount != oldThreadCount) { + // Value not stabilized. Retry. + continue; + } + if (threadCount > 0) { + threadGroup.setDaemon(true); + } else { + threadGroup.destroy(); + success = true; + } + break; + } + } + } catch (IllegalThreadStateException exception) { + // Fall-through } + if (!success) { + log.warn(sm.getString("serverContainer.threadGroupNotDestroyed", + threadGroup.getName(), Integer.valueOf(threadCount))); } } 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=1622253&r1=1622252&r2=1622253&view=diff ============================================================================== --- tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc7.0.x/trunk/webapps/docs/changelog.xml Wed Sep 3 13:41:05 2014 @@ -169,6 +169,10 @@ application. (markt) </fix> <fix> + <bug>56905</bug>: Make destruction on web application stop of thread + group used for WebSocket connections more robust. (kkolinko/markt) + </fix> + <fix> <bug>56907</bug>: Ensure that client IO threads are stopped if a secure WebSocket client connection fails. (markt) </fix> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org