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)
</update>
<fix>
+ <bug>50673</bug>: Improve Catalina shutdown when running as a service.
+ Do not call System.exit(). (kkolinko)
+ </fix>
+ <fix>
<bug>50689</bug>: Provide 100 Continue responses at appropriate points
during FORM authentication if client indicates that they are expected.
(kkolinko)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]