Class: WEBrick::Utils::TimeoutHandler
- Inherits:
-
Object
- Object
- WEBrick::Utils::TimeoutHandler
- Includes:
- Singleton
- 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’
Defined Under Namespace
Classes: Thread
Constant Summary collapse
- TimeoutMutex =
Mutex used to synchronize access across threads
Mutex.new
Class Method Summary collapse
-
.cancel(id) ⇒ Object
Cancels the timeout handler
id
. -
.register(seconds, exception) ⇒ Object
Registers a new timeout handler.
Instance Method Summary collapse
-
#cancel(thread, id) ⇒ Object
Cancels the timeout handler
id
. -
#initialize ⇒ TimeoutHandler
constructor
Creates a new TimeoutHandler.
-
#interrupt(thread, id, exception) ⇒ Object
Interrupts the timeout handler
id
and raisesexception
. -
#register(thread, time, exception) ⇒ Object
Registers a new timeout handler.
Constructor Details
#initialize ⇒ TimeoutHandler
Creates a new TimeoutHandler. You should use ::register and ::cancel instead of creating the timeout handler directly.
151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
# File 'lib/webrick/utils.rb', line 151 def initialize TimeoutMutex.synchronize{ @timeout_info = Hash.new } @queue = Queue.new @watcher = Thread.start{ to_interrupt = [] while true now = Time.now 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 |
Class Method Details
.cancel(id) ⇒ Object
Cancels the timeout handler id
144 145 146 |
# File 'lib/webrick/utils.rb', line 144 def TimeoutHandler.cancel(id) instance.cancel(Thread.current, id) end |
.register(seconds, exception) ⇒ Object
Registers a new timeout handler
time
-
Timeout in seconds
exception
-
Exception to raise when timeout elapsed
138 139 140 |
# File 'lib/webrick/utils.rb', line 138 def TimeoutHandler.register(seconds, exception) instance.register(Thread.current, Time.now + seconds, exception) end |
Instance Method Details
#cancel(thread, id) ⇒ Object
Cancels the timeout handler id
215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/webrick/utils.rb', line 215 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) ⇒ Object
Interrupts the timeout handler id
and raises exception
192 193 194 195 196 |
# File 'lib/webrick/utils.rb', line 192 def interrupt(thread, id, exception) if cancel(thread, id) && thread.alive? thread.raise(exception, "execution timeout") end end |
#register(thread, time, exception) ⇒ Object
Registers a new timeout handler
time
-
Timeout in seconds
exception
-
Exception to raise when timeout elapsed
203 204 205 206 207 208 209 210 211 |
# File 'lib/webrick/utils.rb', line 203 def register(thread, time, exception) info = nil TimeoutMutex.synchronize{ @timeout_info[thread] ||= Array.new @timeout_info[thread] << (info = [time, exception]) } @queue.push nil return info.object_id end |