Skip to content

Commit 54025b3

Browse files
committed
Don't double-interrupt the test HTTP server
The shutdown process here attempted to terminate the test server by interrupting it with Thread#kill, and then proceeded to close the server and join the thread. The kill does indeed interrupt the accept call, but the close call could also interrupt the thread as part of notifying blocked threads waiting on that socket call. In JRuby, where all of this can happen at the same time, it leads to the following scenario: * The server thread enters TCPServer#accept and blocks. * The main thread calls Thread#kill to interrupt the accept call. * The server thread wakes up and starts to propagate the kill. There is a slight delay between this wakeup and removing the server thread from the TCPServer's blocked threads list. * The main thread calls TCPServer#close, which sees that the server thread is still in the blocked list, so it initiates a second interrupt to raise IOError "closed in another thread" on the server thread. * As the kill is bubbling out, another check for interrupts occurs, causing it to see the new raise interrupt and propagate that instead of the active kill. * Because the server is now closed and the rescue here is empty, the server loop will endlessly attempt and fail to call accept. I was unable to determine how CRuby avoids this race. There may be code that prevents an active kill interrupt from triggering further interrupts. In order to get these tests running on JRuby, I've made the following changes: * Only kill the thread; one interrupt is sufficient to break it out of the accept call. * Ensure outside the server loop that the server gets closed. This happens within the server thread, so triggers no new interrupts. * Minor cleanup for the pattern of using @ssl_server or @server. This change avoids the race in JRuby (and possibly other parallel- threaded implementations) and does not impact the behavior of the tests.
1 parent 6475fa6 commit 54025b3

File tree

1 file changed

+4
-3
lines changed

1 file changed

+4
-3
lines changed

test/net/http/utils.rb

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,14 @@ def initialize(config, &block)
2727
def start
2828
@thread = Thread.new do
2929
loop do
30-
socket = @ssl_server ? @ssl_server.accept : @server.accept
30+
socket = (@ssl_server || @server).accept
3131
run(socket)
3232
rescue
3333
ensure
34-
socket.close if socket
34+
socket&.close
3535
end
36+
ensure
37+
(@ssl_server || @server).close
3638
end
3739
end
3840

@@ -42,7 +44,6 @@ def run(socket)
4244

4345
def shutdown
4446
@thread&.kill
45-
@server&.close
4647
@thread&.join
4748
end
4849

0 commit comments

Comments
 (0)