summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/timeout.rb51
-rw-r--r--test/test_timeout.rb20
2 files changed, 49 insertions, 22 deletions
diff --git a/lib/timeout.rb b/lib/timeout.rb
index 3c3cb8e066..414983088c 100644
--- a/lib/timeout.rb
+++ b/lib/timeout.rb
@@ -95,30 +95,37 @@ module Timeout
end
private_constant :Request
+ def self.create_timeout_thread
+ Thread.new do
+ requests = []
+ while true
+ until QUEUE.empty? and !requests.empty? # wait to have at least one request
+ req = QUEUE.pop
+ requests << req unless req.done?
+ end
+ closest_deadline = requests.min_by(&:deadline).deadline
+
+ now = 0.0
+ QUEUE_MUTEX.synchronize do
+ while (now = Process.clock_gettime(Process::CLOCK_MONOTONIC)) < closest_deadline and QUEUE.empty?
+ CONDVAR.wait(QUEUE_MUTEX, closest_deadline - now)
+ end
+ end
+
+ requests.each do |req|
+ req.interrupt if req.expired?(now)
+ end
+ requests.reject!(&:done?)
+ end
+ end
+ end
+ private_class_method :create_timeout_thread
+
def self.ensure_timeout_thread_created
- unless @timeout_thread
+ unless @timeout_thread and @timeout_thread.alive?
TIMEOUT_THREAD_MUTEX.synchronize do
- @timeout_thread ||= Thread.new do
- requests = []
- while true
- until QUEUE.empty? and !requests.empty? # wait to have at least one request
- req = QUEUE.pop
- requests << req unless req.done?
- end
- closest_deadline = requests.min_by(&:deadline).deadline
-
- now = 0.0
- QUEUE_MUTEX.synchronize do
- while (now = Process.clock_gettime(Process::CLOCK_MONOTONIC)) < closest_deadline and QUEUE.empty?
- CONDVAR.wait(QUEUE_MUTEX, closest_deadline - now)
- end
- end
-
- requests.each do |req|
- req.interrupt if req.expired?(now)
- end
- requests.reject!(&:done?)
- end
+ unless @timeout_thread and @timeout_thread.alive?
+ @timeout_thread = create_timeout_thread
end
end
end
diff --git a/test/test_timeout.rb b/test/test_timeout.rb
index 58eb8421db..76de38949d 100644
--- a/test/test_timeout.rb
+++ b/test/test_timeout.rb
@@ -139,4 +139,24 @@ class TestTimeout < Test::Unit::TestCase
}
assert(ok, bug11344)
end
+
+ def test_fork
+ omit 'fork not supported' unless Process.respond_to?(:fork)
+ r, w = IO.pipe
+ pid = fork do
+ r.close
+ begin
+ r = Timeout.timeout(0.01) { sleep 5 }
+ w.write r.inspect
+ rescue Timeout::Error
+ w.write 'timeout'
+ ensure
+ w.close
+ end
+ end
+ w.close
+ Process.wait pid
+ assert_equal 'timeout', r.read
+ r.close
+ end
end