* lib/webrick/server.rb (initialize): Initialize shutdown pipe here
to avoid race condition. (cleanup_shutdown_pipe): New private method. (cleanup_listener): Extracted from shutdown method. Call this method from start method to avoid race condition. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@48353 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
ef82fcf067
commit
2a9ea11355
@ -1,3 +1,11 @@
|
|||||||
|
Mon Nov 10 07:31:59 2014 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
|
* lib/webrick/server.rb (initialize): Initialize shutdown pipe here
|
||||||
|
to avoid race condition.
|
||||||
|
(cleanup_shutdown_pipe): New private method.
|
||||||
|
(cleanup_listener): Extracted from shutdown method.
|
||||||
|
Call this method from start method to avoid race condition.
|
||||||
|
|
||||||
Mon Nov 10 05:57:53 2014 Tanaka Akira <akr@fsij.org>
|
Mon Nov 10 05:57:53 2014 Tanaka Akira <akr@fsij.org>
|
||||||
|
|
||||||
* test/webrick/webrick.cgi: Don't use debug mode.
|
* test/webrick/webrick.cgi: Don't use debug mode.
|
||||||
|
@ -106,6 +106,7 @@ module WEBrick
|
|||||||
@logger.info("ruby #{rubyv}")
|
@logger.info("ruby #{rubyv}")
|
||||||
|
|
||||||
@listeners = []
|
@listeners = []
|
||||||
|
@shutdown_pipe_r = @shutdown_pipe_w = nil
|
||||||
unless @config[:DoNotListen]
|
unless @config[:DoNotListen]
|
||||||
if @config[:Listen]
|
if @config[:Listen]
|
||||||
warn(":Listen option is deprecated; use GenericServer#listen")
|
warn(":Listen option is deprecated; use GenericServer#listen")
|
||||||
@ -114,8 +115,8 @@ module WEBrick
|
|||||||
if @config[:Port] == 0
|
if @config[:Port] == 0
|
||||||
@config[:Port] = @listeners[0].addr[1]
|
@config[:Port] = @listeners[0].addr[1]
|
||||||
end
|
end
|
||||||
|
@shutdown_pipe_r, @shutdown_pipe_w = IO.pipe
|
||||||
end
|
end
|
||||||
@shutdown_pipe_w = nil
|
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
@ -158,9 +159,6 @@ module WEBrick
|
|||||||
raise ServerError, "already started." if @status != :Stop
|
raise ServerError, "already started." if @status != :Stop
|
||||||
server_type = @config[:ServerType] || SimpleServer
|
server_type = @config[:ServerType] || SimpleServer
|
||||||
|
|
||||||
shutdown_pipe_r, shutdown_pipe_w = IO.pipe
|
|
||||||
@shutdown_pipe_w = shutdown_pipe_w
|
|
||||||
|
|
||||||
server_type.start{
|
server_type.start{
|
||||||
@logger.info \
|
@logger.info \
|
||||||
"#{self.class}#start: pid=#{$$} port=#{@config[:Port]}"
|
"#{self.class}#start: pid=#{$$} port=#{@config[:Port]}"
|
||||||
@ -171,8 +169,8 @@ module WEBrick
|
|||||||
begin
|
begin
|
||||||
while @status == :Running
|
while @status == :Running
|
||||||
begin
|
begin
|
||||||
if svrs = IO.select([shutdown_pipe_r, *@listeners], nil, nil, 2.0)
|
if svrs = IO.select([@shutdown_pipe_r, *@listeners], nil, nil, 2.0)
|
||||||
if svrs[0].include? shutdown_pipe_r
|
if svrs[0].include? @shutdown_pipe_r
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
svrs[0].each{|svr|
|
svrs[0].each{|svr|
|
||||||
@ -198,16 +196,9 @@ module WEBrick
|
|||||||
raise
|
raise
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
ensure
|
ensure
|
||||||
shutdown_pipe_r.close
|
cleanup_shutdown_pipe
|
||||||
if !shutdown_pipe_w.closed?
|
cleanup_listener
|
||||||
begin
|
|
||||||
shutdown_pipe_w.close
|
|
||||||
rescue IOError # Another thread closed shutdown_pipe_w.
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@shutdown_pipe_w = nil
|
|
||||||
@status = :Shutdown
|
@status = :Shutdown
|
||||||
@logger.info "going to shutdown ..."
|
@logger.info "going to shutdown ..."
|
||||||
thgroup.list.each{|th| th.join if th[:WEBrickThread] }
|
thgroup.list.each{|th| th.join if th[:WEBrickThread] }
|
||||||
@ -234,34 +225,14 @@ module WEBrick
|
|||||||
def shutdown
|
def shutdown
|
||||||
stop
|
stop
|
||||||
|
|
||||||
shutdown_pipe_w = @shutdown_pipe_w
|
shutdown_pipe_w = @shutdown_pipe_w # another thread may modify @shutdown_pipe_w.
|
||||||
@shutdown_pipe_w = nil
|
if shutdown_pipe_w
|
||||||
if shutdown_pipe_w && !shutdown_pipe_w.closed?
|
|
||||||
begin
|
begin
|
||||||
shutdown_pipe_w.close
|
shutdown_pipe_w.write_nonblock "a"
|
||||||
rescue IOError # Another thread closed shutdown_pipe_w.
|
rescue IO::WaitWritable
|
||||||
|
rescue IOError # closed by another thread.
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@listeners.each{|s|
|
|
||||||
if @logger.debug?
|
|
||||||
addr = s.addr
|
|
||||||
@logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})")
|
|
||||||
end
|
|
||||||
begin
|
|
||||||
s.shutdown
|
|
||||||
rescue Errno::ENOTCONN
|
|
||||||
# when `Errno::ENOTCONN: Socket is not connected' on some platforms,
|
|
||||||
# call #close instead of #shutdown.
|
|
||||||
# (ignore @config[:ShutdownSocketWithoutClose])
|
|
||||||
s.close
|
|
||||||
else
|
|
||||||
unless @config[:ShutdownSocketWithoutClose]
|
|
||||||
s.close
|
|
||||||
end
|
|
||||||
end
|
|
||||||
}
|
|
||||||
@listeners.clear
|
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
@ -346,5 +317,33 @@ module WEBrick
|
|||||||
cb.call(*args)
|
cb.call(*args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def cleanup_shutdown_pipe
|
||||||
|
@shutdown_pipe_r.close
|
||||||
|
@shutdown_pipe_w.close
|
||||||
|
@shutdown_pipe_r = @shutdown_pipe_w = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def cleanup_listener
|
||||||
|
@listeners.each{|s|
|
||||||
|
if @logger.debug?
|
||||||
|
addr = s.addr
|
||||||
|
@logger.debug("close TCPSocket(#{addr[2]}, #{addr[1]})")
|
||||||
|
end
|
||||||
|
begin
|
||||||
|
s.shutdown
|
||||||
|
rescue Errno::ENOTCONN
|
||||||
|
# when `Errno::ENOTCONN: Socket is not connected' on some platforms,
|
||||||
|
# call #close instead of #shutdown.
|
||||||
|
# (ignore @config[:ShutdownSocketWithoutClose])
|
||||||
|
s.close
|
||||||
|
else
|
||||||
|
unless @config[:ShutdownSocketWithoutClose]
|
||||||
|
s.close
|
||||||
|
end
|
||||||
|
end
|
||||||
|
}
|
||||||
|
@listeners.clear
|
||||||
|
end
|
||||||
end # end of GenericServer
|
end # end of GenericServer
|
||||||
end
|
end
|
||||||
|
@ -34,6 +34,10 @@ class TestWEBrickServer < Test::Unit::TestCase
|
|||||||
def listener.to_io # IO.select invokes #to_io.
|
def listener.to_io # IO.select invokes #to_io.
|
||||||
raise SignalException, 'SIGTERM' # simulate signal in main thread
|
raise SignalException, 'SIGTERM' # simulate signal in main thread
|
||||||
end
|
end
|
||||||
|
def listener.shutdown
|
||||||
|
end
|
||||||
|
def listener.close
|
||||||
|
end
|
||||||
|
|
||||||
server = WEBrick::HTTPServer.new({
|
server = WEBrick::HTTPServer.new({
|
||||||
:BindAddress => "127.0.0.1", :Port => 0,
|
:BindAddress => "127.0.0.1", :Port => 0,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user