diff options
author | gotoyuzo <gotoyuzo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2006-05-18 13:42:52 +0000 |
---|---|---|
committer | gotoyuzo <gotoyuzo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2006-05-18 13:42:52 +0000 |
commit | 9a012539baf79006b2c6b25b4eaf8d2cdd40e123 (patch) | |
tree | 0b8f535b800ed312033ff5db7e6ac45415ea15fd /lib/webrick/utils.rb | |
parent | 9e365254a64be2e1eff5ac5aa57ebe72b31ecc51 (diff) |
* lib/webrick/config.rb (WEBrick::Config::HTTP): add new parameters,
:InputBufferSize and :OutputBufferSize.
* lib/webrick/utils.rb (WEBrick::Utils.timeout): add new timeout
method. this implementation is expected to be compatible with
timeout.rb and faster than timeout.rb.
* lib/webrick/httprequest.rb (WEBrick::HTTPRequest#_read_data):
Timeout.timeout is replaced by WEBrick::Utils.timeout.
* lib/webrick/httprequest.rb: WEBrick::HTTPRequest::BUFSIZE is
replaced by config[:InputBufferSize].
* lib/webrick/httpresposne.rb: WEBrick::HTTPResponse::BUFSIZE is
replaced by config[:OutputBufferSize].
* lib/webrick/server.rb: get rid of unnecessary require.
* test/webrick/test_utils.rb: test for WEBrick::Utils.timeout.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10167 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'lib/webrick/utils.rb')
-rw-r--r-- | lib/webrick/utils.rb | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/lib/webrick/utils.rb b/lib/webrick/utils.rb index cf9da6f2ce..4a447aaf85 100644 --- a/lib/webrick/utils.rb +++ b/lib/webrick/utils.rb @@ -96,5 +96,80 @@ module WEBrick end module_function :random_string + ########### + + require "thread" + require "timeout" + require "singleton" + + class TimeoutHandler + include Singleton + TimeoutMutex = Mutex.new + + def TimeoutHandler.register(seconds, exception) + TimeoutMutex.synchronize{ + instance.register(Thread.current, Time.now + seconds, exception) + } + end + + def TimeoutHandler.cancel(id) + TimeoutMutex.synchronize{ + instance.cancel(Thread.current, id) + } + end + + def initialize + @timeout_info = Hash.new + Thread.start{ + while true + now = Time.now + @timeout_info.each{|thread, ary| + ary.each{|info| + time, exception = *info + interrupt(thread, info.object_id, exception) if time < now + } + } + sleep 0.5 + end + } + end + + def interrupt(thread, id, exception) + TimeoutMutex.synchronize{ + if cancel(thread, id) && thread.alive? + thread.raise(exception, "execution timeout") + end + } + end + + def register(thread, time, exception) + @timeout_info[thread] ||= Array.new + @timeout_info[thread] << [time, exception] + return @timeout_info[thread].last.object_id + end + + def cancel(thread, id) + 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 false + end + end + + def timeout(seconds, exception=Timeout::Error) + return yield if seconds.nil? or seconds.zero? + raise ThreadError, "timeout within critical session" if Thread.critical + id = TimeoutHandler.register(seconds, exception) + begin + yield(seconds) + ensure + TimeoutHandler.cancel(id) + end + end + module_function :timeout end end |