Bug #6369
closedGServer blocking after shutdown called
Description
Hi,
My investigation of bug #6358 points the finger at GServer triggering bug #5343 on lower power arm-linux platforms, because of the blocking TCPServer#accept call.
I believe there is also an underlying design flaw: the main thread (@tcpServerThread) is blocked in the TCPServer#accept call, so if no further connections are attempted after #shutdown() is called, the main thread remains blocked and will hang until it is forced into the ensure clause by the destruction of the GServer object by GC
This proposed patch to GServer seems to tackle the first issue, and also effectively makes the TCPServer#accept nonblocking by using a Timeout block to ensure that the main thread periodically (every 0.1s) has the chance to shut down gracefully if no further connections are forthcoming.
It also adds a GServer#shutdown! method which will block until the GServer has gracefully shut down
59,60c59,62
< # server.shutdown
< #
server.shutdown #will not wait for the server thread to quit¶
server.shutdown! #blocks until server thread has quit¶
122c124,131
<
def shutdown!
shutdown
while !stopped?
sleep 0.01
end
end
189c198
< @@servicesMutex.synchronize {
@@servicesMutex.synchronize do
197,198c206,208
< }
< @tcpServerThread = Thread.new {
end @tcpServerThread = Thread.new do
202c212
< @connectionsMutex.synchronize {
@connectionsMutex.synchronize do
206,217c216,240
< }
< client = @tcpServer.accept
< @connections << Thread.new(client) { |myClient|
< begin
< myPort = myClient.peeraddr[1]
< serve(myClient) if @audit or connecting(myClient)
< rescue => detail
< error(detail) if @debug
< ensure
< begin
< myClient.close
< rescue
end begin Timeout::timeout(0.1) do client = @tcpServer.accept @connections << Thread.new(client) do |myClient| begin myPort = myClient.peeraddr[1] serve(myClient) if !@audit or connecting(myClient) rescue => detail error(detail) if @debug ensure begin myClient.close sleep 1 rescue end @connectionsMutex.synchronize do @connections.delete(Thread.current) @connectionsCV.signal end disconnecting(myPort) if @audit end
219,223d241
< @connectionsMutex.synchronize {
< @connections.delete(Thread.current)
< @connectionsCV.signal
< }
< disconnecting(myPort) if @audit
225c243,245
< }
rescue Timeout::Error end
226a247
235c256
< @connectionsMutex.synchronize {
@connectionsMutex.synchronize do
239c260
< }
end
244c265
< @@servicesMutex.synchronize {
@@servicesMutex.synchronize do
246c267
< }
end
249c270
< }
end