Return-Path: Delivered-To: apmail-tomcat-dev-archive@www.apache.org Received: (qmail 7570 invoked from network); 2 Feb 2011 15:03:17 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 2 Feb 2011 15:03:17 -0000 Received: (qmail 41277 invoked by uid 500); 2 Feb 2011 15:03:16 -0000 Delivered-To: apmail-tomcat-dev-archive@tomcat.apache.org Received: (qmail 40896 invoked by uid 500); 2 Feb 2011 15:03:13 -0000 Mailing-List: contact dev-help@tomcat.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: "Tomcat Developers List" Delivered-To: mailing list dev@tomcat.apache.org Received: (qmail 40886 invoked by uid 99); 2 Feb 2011 15:03:11 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 02 Feb 2011 15:03:11 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=5.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Wed, 02 Feb 2011 15:03:10 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id 67D112388AA0; Wed, 2 Feb 2011 15:02:50 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r1066492 - in /tomcat/tc6.0.x/trunk: STATUS.txt java/org/apache/catalina/core/StandardServer.java java/org/apache/catalina/startup/Catalina.java webapps/docs/changelog.xml Date: Wed, 02 Feb 2011 15:02:50 -0000 To: dev@tomcat.apache.org From: kkolinko@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20110202150250.67D112388AA0@eris.apache.org> Author: kkolinko Date: Wed Feb 2 15:02:49 2011 New Revision: 1066492 URL: http://svn.apache.org/viewvc?rev=1066492&view=rev Log: Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=50673 Improve Catalina shutdown when running as a service. Do not call System.exit(). Modified: tomcat/tc6.0.x/trunk/STATUS.txt tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/StandardServer.java tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/Catalina.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=1066492&r1=1066491&r2=1066492&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/STATUS.txt (original) +++ tomcat/tc6.0.x/trunk/STATUS.txt Wed Feb 2 15:02:49 2011 @@ -100,10 +100,3 @@ PATCHES PROPOSED TO BACKPORT: defaultProtocol, defaultKeystoreType, though I do not see much concerns against it. markt: Happy to exclude those changes - -* Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=50673 - Improve Catalina shutdown when running as a service. Do not call - System.exit(). - https://issues.apache.org/bugzilla/attachment.cgi?id=26591 - +1: kkolinko, mturk, markt - -1: Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/StandardServer.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/StandardServer.java?rev=1066492&r1=1066491&r2=1066492&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/StandardServer.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/core/StandardServer.java Wed Feb 2 15:02:49 2011 @@ -181,7 +181,17 @@ public final class StandardServer */ protected PropertyChangeSupport support = new PropertyChangeSupport(this); - private boolean stopAwait = false; + private volatile boolean stopAwait = false; + + /** + * Thread that currently is inside our await() method. + */ + private volatile Thread awaitThread = null; + + /** + * Server socket that is used to wait for the shutdown command. + */ + private volatile ServerSocket awaitSocket = null; // ------------------------------------------------------------- Properties @@ -344,6 +354,24 @@ public final class StandardServer public void stopAwait() { stopAwait=true; + Thread t = awaitThread; + if (t != null) { + ServerSocket s = awaitSocket; + if (s != null) { + awaitSocket = null; + try { + s.close(); + } catch (IOException e) { + // Ignored + } + } + t.interrupt(); + try { + t.join(1000); + } catch (InterruptedException e) { + // Ignored + } + } } /** @@ -358,92 +386,117 @@ public final class StandardServer return; } if( port==-1 ) { - while( true ) { - try { - Thread.sleep( 10000 ); - } catch( InterruptedException ex ) { + try { + awaitThread = Thread.currentThread(); + while(!stopAwait) { + try { + Thread.sleep( 10000 ); + } catch( InterruptedException ex ) { + // continue and check the flag + } } - if( stopAwait ) return; + } finally { + awaitThread = null; } + return; } - + // Set up a server socket to wait on - ServerSocket serverSocket = null; try { - serverSocket = + awaitSocket = new ServerSocket(port, 1, InetAddress.getByName("localhost")); } catch (IOException e) { log.error("StandardServer.await: create[" + port + "]: ", e); - System.exit(1); + return; } - // Loop waiting for a connection and a valid command - while (true) { + try { + awaitThread = Thread.currentThread(); - // Wait for the next connection - Socket socket = null; - InputStream stream = null; - try { - socket = serverSocket.accept(); - socket.setSoTimeout(10 * 1000); // Ten seconds - stream = socket.getInputStream(); - } catch (AccessControlException ace) { - log.warn("StandardServer.accept security exception: " - + ace.getMessage(), ace); - continue; - } catch (IOException e) { - log.error("StandardServer.await: accept: ", e); - System.exit(1); - } - - // Read a set of characters from the socket - StringBuffer command = new StringBuffer(); - int expected = 1024; // Cut off to avoid DoS attack - while (expected < shutdown.length()) { - if (random == null) - random = new Random(); - expected += (random.nextInt() % 1024); - } - while (expected > 0) { - int ch = -1; + // Loop waiting for a connection and a valid command + while (!stopAwait) { + ServerSocket serverSocket = awaitSocket; + if (serverSocket == null) { + break; + } + + // Wait for the next connection + Socket socket = null; + StringBuilder command = new StringBuilder(); try { - ch = stream.read(); - } catch (IOException e) { - log.warn("StandardServer.await: read: ", e); - ch = -1; + InputStream stream = null; + try { + socket = serverSocket.accept(); + socket.setSoTimeout(10 * 1000); // Ten seconds + stream = socket.getInputStream(); + } catch (AccessControlException ace) { + log.warn("StandardServer.accept security exception: " + + ace.getMessage(), ace); + continue; + } catch (IOException e) { + if (stopAwait) { + // Wait was aborted with socket.close() + break; + } + log.error("StandardServer.await: accept: ", e); + break; + } + + // Read a set of characters from the socket + int expected = 1024; // Cut off to avoid DoS attack + while (expected < shutdown.length()) { + if (random == null) + random = new Random(); + expected += (random.nextInt() % 1024); + } + while (expected > 0) { + int ch = -1; + try { + ch = stream.read(); + } catch (IOException e) { + log.warn("StandardServer.await: read: ", e); + ch = -1; + } + if (ch < 32) // Control character or EOF terminates loop + break; + command.append((char) ch); + expected--; + } + } finally { + // Close the socket now that we are done with it + try { + if (socket != null) { + socket.close(); + } + } catch (IOException e) { + // Ignore + } } - if (ch < 32) // Control character or EOF terminates loop + + // Match against our command string + boolean match = command.toString().equals(shutdown); + if (match) { break; - command.append((char) ch); - expected--; - } + } else + log.warn("StandardServer.await: Invalid command '" + + command.toString() + "' received"); + } + } finally { + ServerSocket serverSocket = awaitSocket; + awaitThread = null; + awaitSocket = null; - // Close the socket now that we are done with it - try { - socket.close(); - } catch (IOException e) { - ; + // Close the server socket and return + if (serverSocket != null) { + try { + serverSocket.close(); + } catch (IOException e) { + // Ignore + } } - - // Match against our command string - boolean match = command.toString().equals(shutdown); - if (match) { - break; - } else - log.warn("StandardServer.await: Invalid command '" + - command.toString() + "' received"); - } - - // Close the server socket and return - try { - serverSocket.close(); - } catch (IOException e) { - ; - } - } @@ -738,8 +791,7 @@ public final class StandardServer // Notify our interested LifecycleListeners lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null); - if (port == -1) - stopAwait(); + stopAwait(); } Modified: tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/Catalina.java URL: http://svn.apache.org/viewvc/tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/Catalina.java?rev=1066492&r1=1066491&r2=1066492&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/Catalina.java (original) +++ tomcat/tc6.0.x/trunk/java/org/apache/catalina/startup/Catalina.java Wed Feb 2 15:02:49 2011 @@ -34,6 +34,7 @@ import java.util.logging.LogManager; import org.apache.catalina.Container; import org.apache.catalina.Lifecycle; import org.apache.catalina.LifecycleException; +import org.apache.catalina.Server; import org.apache.catalina.core.StandardServer; import org.apache.juli.ClassLoaderLogManager; import org.apache.tomcat.util.digester.Digester; @@ -382,7 +383,8 @@ public class Catalina extends Embedded { arguments(arguments); } - if( getServer() == null ) { + Server s = getServer(); + if( s == null ) { // Create and execute our Digester Digester digester = createStopDigester(); digester.setClassLoader(Thread.currentThread().getContextClassLoader()); @@ -401,17 +403,25 @@ public class Catalina extends Embedded { } } else { // Server object already present. Must be running as a service - // Shutdown hook will take care of clean-up - System.exit(0); + if (s instanceof Lifecycle) { + try { + ((Lifecycle) s).stop(); + } catch (LifecycleException e) { + log.error("Catalina.stop: ", e); + } + return; + } + // else fall down } // Stop the existing server + s = getServer(); try { - if (getServer().getPort()>0) { + if (s.getPort()>0) { String hostAddress = InetAddress.getByName("localhost").getHostAddress(); Socket socket = new Socket(hostAddress, getServer().getPort()); OutputStream stream = socket.getOutputStream(); - String shutdown = getServer().getShutdown(); + String shutdown = s.getShutdown(); for (int i = 0; i < shutdown.length(); i++) stream.write(shutdown.charAt(i)); stream.flush(); 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=1066492&r1=1066491&r2=1066492&view=diff ============================================================================== --- tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml (original) +++ tomcat/tc6.0.x/trunk/webapps/docs/changelog.xml Wed Feb 2 15:02:49 2011 @@ -51,6 +51,10 @@ Based on the patch provided by Marc Guillemot. (kkolinko) + 50673: Improve Catalina shutdown when running as a service. + Do not call System.exit(). (kkolinko) + + 50689: Provide 100 Continue responses at appropriate points during FORM authentication if client indicates that they are expected. (kkolinko) --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org For additional commands, e-mail: dev-help@tomcat.apache.org