8 # Copyright - (C) 2008 Evan Phoenix
9 # Copyright:: (C) 2000 Network Applied Communication Laboratory, Inc.
10 # Copyright:: (C) 2000 Information-technology Promotion Agency, Japan
16 # A way of performing a potentially long-running operation in a thread, and
17 # terminating it's execution if it hasn't finished within fixed amount of
20 # Previous versions of timeout didn't use a module for namespace. This version
21 # provides both Timeout.timeout, and a backwards-compatible #timeout.
26 # status = Timeout::timeout(5) {
27 # # Something that should be interrupted if it takes too much time...
36 # Raised by Timeout#timeout when the block times out.
41 # A mutex to protect @requests
44 # All the outstanding TimeoutRequests
47 # Represents +thr+ asking for it to be timeout at in +secs+
48 # seconds. At timeout, raise +exc+.
50 def initialize(secs, thr, exc)
56 attr_reader :thread, :left
58 # Called because +time+ seconds have gone by. Returns
59 # true if the request has no more time left to run.
65 # Raise @exception if @thread.
67 if @thread and @thread.alive?
68 @thread.raise @exception, "execution expired"
74 # Abort this request, ie, we don't care about tracking
82 def self.add_timeout(time, exc)
84 @controller ||= Thread.new do
94 min = @requests.min { |a,b| a.left <=> b.left }
97 slept_for = sleep(min.left)
100 @requests.delete_if do |r|
101 if r.elapsed(slept_for)
113 req = TimeoutRequest.new(time, Thread.current, exc)
115 @mutex.synchronize do
125 # Executes the method's block. If the block execution terminates before +sec+
126 # seconds has passed, it returns true. If not, it terminates the execution
127 # and raises +exception+ (which defaults to Timeout::Error).
129 # Note that this is both a method of module Timeout, so you can 'include
130 # Timeout' into your classes so they have a #timeout method, as well as a
131 # module method, so you can call it directly as Timeout.timeout().
133 def timeout(sec, exception=Error)
134 return yield if sec == nil or sec.zero?
135 raise ThreadError, "timeout within critical session" if Thread.critical
137 req = Timeout.add_timeout sec, exception
146 module_function :timeout
153 # Timeout::timeout(n, e, &block).
155 # Defined for backwards compatibility with earlier versions of timeout.rb, see
158 def timeout(n, e=Timeout::Error, &block) # :nodoc:
159 Timeout::timeout(n, e, &block)
163 # Another name for Timeout::Error, defined for backwards compatibility with
164 # earlier versions of timeout.rb.
166 TimeoutError = Timeout::Error # :nodoc:
172 p timeout(5, TimeoutError) {