Skip to content

Commit 36ae16c

Browse files
committed
Fix spurious return in Promises#wait_until_resolved
* Fixes #1015
1 parent 068212f commit 36ae16c

File tree

2 files changed

+40
-2
lines changed

2 files changed

+40
-2
lines changed

lib/concurrent-ruby/concurrent/promises.rb

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
require 'concurrent/configuration'
66
require 'concurrent/errors'
77
require 'concurrent/re_include'
8+
require 'concurrent/utility/monotonic_time'
89

910
module Concurrent
1011

@@ -772,8 +773,17 @@ def wait_until_resolved(timeout)
772773
@Lock.synchronize do
773774
@Waiters.increment
774775
begin
775-
unless resolved?
776-
@Condition.wait @Lock, timeout
776+
if timeout
777+
start = Concurrent.monotonic_time
778+
until resolved?
779+
break if @Condition.wait(@Lock, timeout) == nil # nil means timeout
780+
timeout -= (Concurrent.monotonic_time - start)
781+
break if timeout <= 0
782+
end
783+
else
784+
until resolved?
785+
@Condition.wait(@Lock, timeout)
786+
end
777787
end
778788
ensure
779789
# JRuby may raise ConcurrencyError

spec/concurrent/promises_spec.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,4 +754,32 @@ def behaves_as_delay(delay, value)
754754
specify 'zip_futures_over' do
755755
expect(zip_futures_over([1, 2]) { |v| v.succ }.value!).to eq [2, 3]
756756
end
757+
758+
describe 'value!' do
759+
%w[with without].each do |timeout|
760+
it "does not return spuriously #{timeout} timeout" do
761+
# https://github.com/ruby-concurrency/concurrent-ruby/issues/1015
762+
trapped = false
763+
original_handler = Signal.trap(:SIGHUP) { trapped = true }
764+
begin
765+
task = Concurrent::Promises.future { sleep }
766+
main = Thread.current
767+
t = Thread.new do
768+
Thread.pass until main.stop?
769+
Process.kill(:SIGHUP, Process.pid)
770+
sleep 0.1
771+
main.raise "Done"
772+
end
773+
expect {
774+
timeout == 'with' ? task.value!(3600) : task.value!
775+
expect(task).to be_resolved # fail if #value! returned
776+
}.to raise_error(RuntimeError, "Done")
777+
expect(trapped).to be true
778+
t.join
779+
ensure
780+
Signal.trap(:SIGHUP, original_handler)
781+
end
782+
end
783+
end
784+
end
757785
end

0 commit comments

Comments
 (0)