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)
endwill raise Timeout::Error
id = TimeoutHandler.register(10, Timeout::Error)
begin
  sleep 5
  puts 'foo'
ensure
  TimeoutHandler.cancel(id)
endwill print 'foo'
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 idand 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 154
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 143
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 136
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 147
def self.terminate instance.terminate end
Instance Method Details
#cancel(thread, id)
Cancels the timeout handler id
# File 'lib/webrick/utils.rb', line 232
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 209
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 220
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 246
def terminate TimeoutMutex.synchronize{ @timeout_info.clear @watcher&.kill&.join } end
#watch (private)
[ GitHub ]# File 'lib/webrick/utils.rb', line 164
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 199
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