SimpleHttpServer doesn't shut down cleanly on some platforms
------------------------------------------------------------

                 Key: WSCOMMONS-402
                 URL: https://issues.apache.org/jira/browse/WSCOMMONS-402
             Project: WS-Commons
          Issue Type: Bug
         Environment: minotaur.apache.org: Java HotSpot(TM) 64-Bit Server VM 
(build diablo-1.5.0_07-b01, mixed mode)

            Reporter: Andreas Veithen
            Priority: Minor


Different JVM implementations show different behaviors when Thread#interrupt is 
called on a thread that is blocked in ServerSocket#accept:

1. Most JVMs only set the interrupted flag on the thread but don't trigger an 
exception.
2. Other JVMs cause a java.io.InterruptedIOException to be thrown out of 
ServerSocket#accept but don't set the interrupted flag.

On JVMs that have behavior 1, when calling SimpleHttpServer#destroy, the 
sequence of events is as follows:

1. SimpleHttpServer#destroy calls ExecutorServide#shutdownNow.
2. ExecutorServide#shutdownNow calls Thread#interrupted on the thread running 
DefaultConnectionListener (and blocked in ServerSocket#accept). This sets the 
interrupted flag, but doesn't cause an exception.
3. SimpleHttpServer#destroy calls ExecutorServide#awaitTermination which will 
only return after the specified timeout (because the DefaultConnectionListener 
thread is still running).
4. SimpleHttpServer#destroy calls DefaultConnectionListener#destroy which 
closes the ServerSocket.
5. ServerSocket#accept throws an exception. The catch block in 
DefaultConnectionListener#run checks the interrupted flag and since it is set, 
the method exits, terminating the thread.

Except for step 3, this approach is correct and results in a clean shutdown.

On JVMs having the other behavior, the sequence of events is completely 
different:

1. SimpleHttpServer#destroy calls ExecutorServide#shutdownNow.
2. ExecutorServide#shutdownNow calls Thread#interrupted on the thread running 
DefaultConnectionListener (and blocked in ServerSocket#accept).
3. An InterruptedIOException is thrown out of ServerSocket#accept. Since the 
interrupted flag is not set, the exception is handed over to the 
DefaultConnectionListenerFailureHandler.
4. DefaultConnectionListenerFailureHandler#failed returns true and 
DefaultConnectionListener will immediately reenter ServerSocket#accept.
5. SimpleHttpServer#destroy calls ExecutorServide#awaitTermination which will 
only return after the specified timeout (because the DefaultConnectionListener 
thread is still running).
6. SimpleHttpServer#destroy calls DefaultConnectionListener#destroy which 
closes the ServerSocket.
7. ServerSocket#accept throws an exception. Since the interrupted flag is still 
not set, the exception is again handed over to 
DefaultConnectionListenerFailureHandler#failed which instructs the 
DefaultConnectionListener to retry.
8. Since the original server socket is now closed, 
DefaultConnectionListener#run will create a new ServerSocket and open the port 
again. It then blocks in ServerSocket#accept.
9. SimpleHttpServer#destroy shuts down the request processors and exits.

As can be seen this leaves the HTTP port open and SimpleHttpServer doesn't shut 
down cleanly.

The problem can be reproduced by running the transport tests on minotaur 
(peope.apache.org). The HTTP tests will fail with an "Address already in use" 
error because at some point a test case tries to start a different HTTP server 
on the port that is still used by the SimpleHttpServer instance that didn't 
shut down cleanly.



-- 
This message is automatically generated by JIRA.
-
You can reply to this email to add a comment to the issue online.

Reply via email to