Skip to content

Instantly share code, notes, and snippets.

@adacosta
Last active August 29, 2015 14:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adacosta/65358efeb970ac84ca75 to your computer and use it in GitHub Desktop.
Save adacosta/65358efeb970ac84ca75 to your computer and use it in GitHub Desktop.
WEBrick TimeoutHandler race condition
require 'webrick/utils'
# The initialize below is augmented to stall the @timeout_info iteration.
# The fix is uncommenting TimeoutMutex.synchronize{} around the @timeout_info iteration.
class WEBrick::Utils::TimeoutHandler
def initialize
@timeout_info = Hash.new
Thread.start{
while true
now = Time.now
# uncomment the block below to prevent a race
# TimeoutMutex.synchronize{
@timeout_info.each{|thread, ary|
ary.dup.each{|info|
puts "stalling timeout_info iteration"
sleep 0.1
time, exception = *info
interrupt(thread, info.object_id, exception) if time < now
puts "finished timeout_info iteration"
}
}
# }
sleep 0.5
end
}
end
end
while true do
loader_thread = Thread.new do
print '.'
WEBrick::Utils::TimeoutHandler.register(1, Timeout::Error)
end
loader_thread.join
sleep 0.1
end
# Expect to see something like:
# ➥ ruby webrick_race.rb
# .....stalling timeout_info iteration
# .finished timeout_info iteration/Users/adacosta/.rvm/rubies/ruby-2.1.5/lib/ruby/2.1.0/webrick/utils.rb:197:in `register': can't add a new key into hash during iteration (RuntimeError)
# from /Users/adacosta/.rvm/rubies/ruby-2.1.5/lib/ruby/2.1.0/webrick/utils.rb:148:in `block in register'
# from /Users/adacosta/.rvm/rubies/ruby-2.1.5/lib/ruby/2.1.0/webrick/utils.rb:147:in `synchronize'
# from /Users/adacosta/.rvm/rubies/ruby-2.1.5/lib/ruby/2.1.0/webrick/utils.rb:147:in `register'
# from webrick_race.rb:32:in `block in <main>'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment