Class: WEBrick::Utils::TimeoutHandler
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Instance Chain:
self,
Singleton
|
|
Inherits: | Object |
Defined in: | lib/webrick/utils.rb |
Overview
Class used to manage timeout handlers across multiple threads.
Timeout handlers should be managed by using the class methods which are synchronized.
id = TimeoutHandler.register(10, Timeout::Error)
begin
sleep 20
puts 'foo'
ensure
TimeoutHandler.cancel(id)
end
will raise Timeout::Error
id = TimeoutHandler.register(10, Timeout::Error)
begin
sleep 5
puts 'foo'
ensure
TimeoutHandler.cancel(id)
end
will print ‘foo’
Constant Summary
-
TimeoutMutex =
Internal use only
Mutex used to synchronize access across threads
Thread::Mutex.new
Class Method Summary
-
.cancel(id)
Cancels the timeout handler
id
-
.new ⇒ TimeoutHandler
constructor
Creates a new
TimeoutHandler
. -
.register(seconds, exception)
Registers a new timeout handler.
- .terminate
Instance Method Summary
-
#cancel(thread, id)
Cancels the timeout handler
id
-
#interrupt(thread, id, exception)
Interrupts the timeout handler
id
and raisesexception
-
#register(thread, time, exception)
Registers a new timeout handler.
- #terminate
- #watch private
- #watcher private
Constructor Details
.new ⇒ TimeoutHandler
# File 'lib/webrick/utils.rb', line 153
def initialize TimeoutMutex.synchronize{ @timeout_info = Hash.new } @queue = Thread::Queue.new @watcher = nil end
Class Method Details
.cancel(id)
Cancels the timeout handler id
# File 'lib/webrick/utils.rb', line 142
def TimeoutHandler.cancel(id) instance.cancel(Thread.current, id) end
.register(seconds, exception)
Registers a new timeout handler
time
-
Timeout in seconds
exception
-
Exception to raise when timeout elapsed
# File 'lib/webrick/utils.rb', line 135
def TimeoutHandler.register(seconds, exception) at = Process.clock_gettime(Process::CLOCK_MONOTONIC) + seconds instance.register(Thread.current, at, exception) end
.terminate
[ GitHub ]# File 'lib/webrick/utils.rb', line 146
def self.terminate instance.terminate end
Instance Method Details
#cancel(thread, id)
Cancels the timeout handler id
# File 'lib/webrick/utils.rb', line 231
def cancel(thread, id) 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 false } end
#interrupt(thread, id, exception)
Interrupts the timeout handler id
and raises exception
# File 'lib/webrick/utils.rb', line 208
def interrupt(thread, id, exception) if cancel(thread, id) && thread.alive? thread.raise(exception, "execution timeout") end end
#register(thread, time, exception)
Registers a new timeout handler
time
-
Timeout in seconds
exception
-
Exception to raise when timeout elapsed
# File 'lib/webrick/utils.rb', line 219
def register(thread, time, exception) info = nil TimeoutMutex.synchronize{ (@timeout_info[thread] ||= []) << (info = [time, exception]) } @queue.push nil watcher return info.object_id end
#terminate
[ GitHub ]# File 'lib/webrick/utils.rb', line 245
def terminate TimeoutMutex.synchronize{ @timeout_info.clear @watcher&.kill&.join } end
#watch (private)
[ GitHub ]# File 'lib/webrick/utils.rb', line 163
private \ def watch to_interrupt = [] while true now = Process.clock_gettime(Process::CLOCK_MONOTONIC) wakeup = nil to_interrupt.clear TimeoutMutex.synchronize{ @timeout_info.each {|thread, ary| next unless ary ary.each{|info| time, exception = *info if time < now to_interrupt.push [thread, info.object_id, exception] elsif !wakeup || time < wakeup wakeup = time end } } } to_interrupt.each {|arg| interrupt(*arg)} if !wakeup @queue.pop elsif (wakeup -= now) > 0 begin (th = Thread.start {@queue.pop}).join(wakeup) ensure th&.kill&.join end end @queue.clear end end
#watcher (private)
[ GitHub ]# File 'lib/webrick/utils.rb', line 198
private \ def watcher (w = @watcher)&.alive? and return w # usual case TimeoutMutex.synchronize{ (w = @watcher)&.alive? and next w # pathological check @watcher = Thread.start(&method(:watch)) } end