aboutsummaryrefslogtreecommitdiffstats
path: root/lib/webrick/utils.rb
diff options
context:
space:
mode:
authorgotoyuzo <gotoyuzo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-05-18 13:42:52 +0000
committergotoyuzo <gotoyuzo@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2006-05-18 13:42:52 +0000
commit9a012539baf79006b2c6b25b4eaf8d2cdd40e123 (patch)
tree0b8f535b800ed312033ff5db7e6ac45415ea15fd /lib/webrick/utils.rb
parent9e365254a64be2e1eff5ac5aa57ebe72b31ecc51 (diff)
downloadruby-9a012539baf79006b2c6b25b4eaf8d2cdd40e123.tar.gz
* 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.rb75
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