From e337dc65173f11b2be9e620acb34dc91a64fe520 Mon Sep 17 00:00:00 2001 From: ngoto Date: Tue, 15 Dec 2015 16:03:00 +0000 Subject: [PATCH] * lib/webrick/utils.rb (WEBrick::Utils::TimeoutHandler): Acquire TimeoutMutex only when accessing @timeout_info for avoiding potential deadlock. [Bug #11742] [ruby-dev:49387] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@53134 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 6 ++++++ lib/webrick/utils.rb | 43 ++++++++++++++++++++++--------------------- 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/ChangeLog b/ChangeLog index eabfe4646d..ab7d04e8cd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +Wed Dec 16 00:53:45 2015 Naohisa Goto + + * lib/webrick/utils.rb (WEBrick::Utils::TimeoutHandler): Acquire + TimeoutMutex only when accessing @timeout_info for avoiding + potential deadlock. [Bug #11742] [ruby-dev:49387] + Wed Dec 16 00:39:27 2015 Jake Worth * doc/extension.rdoc: [DOC] fix double-word typo. [Fix GH-1153] diff --git a/lib/webrick/utils.rb b/lib/webrick/utils.rb index dc7ce508ea..654d9dea95 100644 --- a/lib/webrick/utils.rb +++ b/lib/webrick/utils.rb @@ -135,24 +135,22 @@ module WEBrick # +time+:: Timeout in seconds # +exception+:: Exception to raise when timeout elapsed def TimeoutHandler.register(seconds, exception) - TimeoutMutex.synchronize{ - instance.register(Thread.current, Time.now + seconds, exception) - } + instance.register(Thread.current, Time.now + seconds, exception) end ## # Cancels the timeout handler +id+ def TimeoutHandler.cancel(id) - TimeoutMutex.synchronize{ - instance.cancel(Thread.current, id) - } + instance.cancel(Thread.current, id) end ## # Creates a new TimeoutHandler. You should use ::register and ::cancel # instead of creating the timeout handler directly. def initialize - @timeout_info = Hash.new + TimeoutMutex.synchronize{ + @timeout_info = Hash.new + } @watcher = Thread.start{ to_interrupt = [] while true @@ -185,11 +183,9 @@ module WEBrick ## # Interrupts the timeout handler +id+ and raises +exception+ def interrupt(thread, id, exception) - TimeoutMutex.synchronize{ - if cancel(thread, id) && thread.alive? - thread.raise(exception, "execution timeout") - end - } + if cancel(thread, id) && thread.alive? + thread.raise(exception, "execution timeout") + end end ## @@ -198,8 +194,11 @@ module WEBrick # +time+:: Timeout in seconds # +exception+:: Exception to raise when timeout elapsed def register(thread, time, exception) - @timeout_info[thread] ||= Array.new - @timeout_info[thread] << (info = [time, exception]) + info = nil + TimeoutMutex.synchronize{ + @timeout_info[thread] ||= Array.new + @timeout_info[thread] << (info = [time, exception]) + } begin @watcher.wakeup rescue ThreadError @@ -210,14 +209,16 @@ module WEBrick ## # Cancels the timeout handler +id+ def cancel(thread, id) - if ary = @timeout_info[thread] - ary.delete_if{|info| info.object_id == id } - if ary.empty? - @timeout_info.delete(thread) + TimeoutMutex.synchronize{ + if ary = @timeout_info[thread] + ary.delete_if{|info| info.object_id == id } + if ary.empty? + @timeout_info.delete(thread) + end + return true end - return true - end - return false + return false + } end end