From 4518e6fdad2d85bf8dacddcd73192d394dd7ec56 Mon Sep 17 00:00:00 2001 From: Marc Siegel Date: Fri, 27 Dec 2013 15:15:07 -0500 Subject: [PATCH] Fix ConditionVariable#signal to only post if semaphore has waiters This fixes a bug where calls to #signal would end up "over-posting" the semaphore, causing subsequent waits to return immediately until the semaphore value is back down to zero. --- lib/process_shared/condition_variable.rb | 4 +++- spec/process_shared/condition_variable_spec.rb | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/process_shared/condition_variable.rb b/lib/process_shared/condition_variable.rb index 0fd42b4..bf4d17c 100644 --- a/lib/process_shared/condition_variable.rb +++ b/lib/process_shared/condition_variable.rb @@ -16,7 +16,9 @@ module ProcessShared end def signal - @sem.post + @internal.synchronize do + @sem.post unless @waiting.read_int.zero? + end end def wait(mutex, timeout = nil) diff --git a/spec/process_shared/condition_variable_spec.rb b/spec/process_shared/condition_variable_spec.rb index 7ffcaba..8631503 100644 --- a/spec/process_shared/condition_variable_spec.rb +++ b/spec/process_shared/condition_variable_spec.rb @@ -63,5 +63,19 @@ module ProcessShared (Time.now.to_f - start).must be_gte(0.1) } end + + it 'correctly handles #signal when no waiters' do + mutex = Mutex.new + cond = ConditionVariable.new + + # fix for bug: #wait not waiting after unmatched call to #signal + cond.signal + + mutex.synchronize { + start = Time.now.to_f + cond.wait(mutex, 0.1) + (Time.now.to_f - start).must be_gte(0.1) + } + end end end