diff --git a/lib/mach/functions.rb b/lib/mach/functions.rb index d5cd8e7..eda7628 100644 --- a/lib/mach/functions.rb +++ b/lib/mach/functions.rb @@ -72,8 +72,8 @@ module Mach # Attach a function as with +attach_function+, but check the # return value and raise an exception on errors. - def self.attach_mach_function(sym, argtypes, rettype) - attach_function(sym, argtypes, rettype) + def self.attach_mach_function(sym, argtypes, rettype, options = nil) + attach_function(sym, argtypes, rettype, options) error_check(sym) end @@ -208,10 +208,12 @@ module Mach :kern_return_t) attach_mach_function(:semaphore_wait, [:semaphore_t], - :kern_return_t) + :kern_return_t, + :blocking => true) attach_mach_function(:semaphore_timedwait, [:semaphore_t, TimeSpec.val], - :kern_return_t) + :kern_return_t, + :blocking => true) end end diff --git a/lib/process_shared/posix/semaphore.rb b/lib/process_shared/posix/semaphore.rb index e75028f..d1fe59e 100644 --- a/lib/process_shared/posix/semaphore.rb +++ b/lib/process_shared/posix/semaphore.rb @@ -26,9 +26,12 @@ module ProcessShared attach_function :sem_getvalue, [:sem_p, :pointer], :int attach_function :sem_post, [:sem_p], :int - attach_function :sem_wait, [:sem_p], :int - attach_function :sem_trywait, [:sem_p], :int - attach_function :sem_timedwait, [:sem_p, TimeSpec], :int + attach_function :sem_wait, [:sem_p], :int, :blocking => true + attach_function :sem_trywait, [:sem_p], :int, :blocking => true + + # Workaround bug which only appears to affect Ruby 1.8.7 and REE + BLOCKING_SEM_TIMEDWAIT = (RUBY_VERSION != '1.8.7') + attach_function :sem_timedwait, [:sem_p, TimeSpec], :int, :blocking => BLOCKING_SEM_TIMEDWAIT error_check(:sem_close, :sem_unlink, :sem_init, :sem_destroy, :sem_getvalue, :sem_post, :sem_wait, :sem_trywait, diff --git a/spec/process_shared/lock_behavior.rb b/spec/process_shared/lock_behavior.rb index 77f97bc..7e49869 100644 --- a/spec/process_shared/lock_behavior.rb +++ b/spec/process_shared/lock_behavior.rb @@ -55,6 +55,5 @@ module ProcessShared mem.get_char(0).must_equal(0) end - end end diff --git a/spec/process_shared/semaphore_spec.rb b/spec/process_shared/semaphore_spec.rb index c6afad1..a0a844c 100644 --- a/spec/process_shared/semaphore_spec.rb +++ b/spec/process_shared/semaphore_spec.rb @@ -91,6 +91,32 @@ module ProcessShared end end end + + it 'allows other threads in a process to continue while waiting' do + sem = Semaphore.new + was_set = false + t2 = nil + + sem.synchronize do + t1 = Thread.new do + # give t2 a chance to wait on the lock, then set the flag + sleep 0.01 + was_set = true + end + + t2 = Thread.new do + sem.synchronize { } + end + + # t1 should set the flag and die while t2 is still waiting on the lock + t1.join + end + + was_set.must_equal true + + t2.join + end + end describe '#try_wait' do @@ -131,6 +157,39 @@ module ProcessShared ::Process.wait(pid) end end + + unless RUBY_VERSION == '1.8.7' + it 'allows other threads in a process to continue while waiting' do + start = Time.now.to_f + sem = Semaphore.new + was_set = false + t2 = nil + + sem.synchronize do + t1 = Thread.new do + # give t2 a chance to wait on the lock, then set the flag + sleep 0.01 + was_set = true + end + + t2 = Thread.new do + begin + sem.try_wait(10.0) + rescue Errno::ETIMEDOUT + # success + end + end + + # t1 should set the flag and die while t2 is still waiting on the lock + t1.join + end + + was_set.must_equal true + (Time.now.to_f - start).must be_lt(0.1) + + t2.join + end + end end end end