You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commons-dev@ws.apache.org by "Andreas Veithen (JIRA)" <ji...@apache.org> on 2008/11/09 23:40:44 UTC

[jira] Created: (WSCOMMONS-402) SimpleHttpServer doesn't shut down cleanly on some platforms

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.


[jira] Commented: (WSCOMMONS-402) SimpleHttpServer doesn't shut down cleanly on some platforms

Posted by "Andreas Veithen (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/WSCOMMONS-402?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12646616#action_12646616 ] 

Andreas Veithen commented on WSCOMMONS-402:
-------------------------------------------

Catching the InterruptedIOException and breaking to loop is indeed the simplest solution to the problem. However, I would prefer that SimpleHttpServer#destroy directly closes the ServerSocket without trying ExecutorServide#shutdownNow. The reason is that this would work on all platforms in the same way and on JVMs of the first type it would avoid spending unnecessary time in ExecutorServide#awaitTermination. Actually on this type of platform, the test cases for the HTTP transport probably spend more time waiting than to execute the actual tests...

> 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.


[jira] Commented: (WSCOMMONS-402) SimpleHttpServer doesn't shut down cleanly on some platforms

Posted by "David Illsley (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/WSCOMMONS-402?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12647626#action_12647626 ] 

David Illsley commented on WSCOMMONS-402:
-----------------------------------------

Andreas,
I can see the benefit, but I'm not entirely sure how to do it. Perhaps you could provide a patch?
David

> 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.


[jira] Resolved: (WSCOMMONS-402) SimpleHttpServer doesn't shut down cleanly on some platforms

Posted by "Davanum Srinivas (JIRA)" <ji...@apache.org>.
     [ https://issues.apache.org/jira/browse/WSCOMMONS-402?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Davanum Srinivas resolved WSCOMMONS-402.
----------------------------------------

    Resolution: Fixed

applied fix from David. Many thanks Andreas

-- dims

> 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.


[jira] Commented: (WSCOMMONS-402) SimpleHttpServer doesn't shut down cleanly on some platforms

Posted by "David Illsley (JIRA)" <ji...@apache.org>.
    [ https://issues.apache.org/jira/browse/WSCOMMONS-402?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=12646409#action_12646409 ] 

David Illsley commented on WSCOMMONS-402:
-----------------------------------------

That's a really good bug report... this problem's been annoying me for a VERY long time.

I really can't believe it's this simple... simply catching the InterruptedIOException and calling break in the catch block.

I tried that and it seemed to work on people.apache.org. Patch at [1].

Can someone else sanity check it and try it on other platforms/jvms?

David

[1] http://people.apache.org/~davidillsley/wscommons/wscommons402.patch

> 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.