Merge pull request #5 from ms-ati/allow-ruby-threads-to-continue
Fix: Allow ruby green threads to continue while waiting on semaphore
This commit is contained in:
commit
c663e81774
|
@ -72,8 +72,8 @@ module Mach
|
||||||
|
|
||||||
# Attach a function as with +attach_function+, but check the
|
# Attach a function as with +attach_function+, but check the
|
||||||
# return value and raise an exception on errors.
|
# return value and raise an exception on errors.
|
||||||
def self.attach_mach_function(sym, argtypes, rettype)
|
def self.attach_mach_function(sym, argtypes, rettype, options = nil)
|
||||||
attach_function(sym, argtypes, rettype)
|
attach_function(sym, argtypes, rettype, options)
|
||||||
error_check(sym)
|
error_check(sym)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -208,10 +208,12 @@ module Mach
|
||||||
:kern_return_t)
|
:kern_return_t)
|
||||||
attach_mach_function(:semaphore_wait,
|
attach_mach_function(:semaphore_wait,
|
||||||
[:semaphore_t],
|
[:semaphore_t],
|
||||||
:kern_return_t)
|
:kern_return_t,
|
||||||
|
:blocking => true)
|
||||||
attach_mach_function(:semaphore_timedwait,
|
attach_mach_function(:semaphore_timedwait,
|
||||||
[:semaphore_t, TimeSpec.val],
|
[:semaphore_t, TimeSpec.val],
|
||||||
:kern_return_t)
|
:kern_return_t,
|
||||||
|
:blocking => true)
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -26,9 +26,12 @@ module ProcessShared
|
||||||
|
|
||||||
attach_function :sem_getvalue, [:sem_p, :pointer], :int
|
attach_function :sem_getvalue, [:sem_p, :pointer], :int
|
||||||
attach_function :sem_post, [:sem_p], :int
|
attach_function :sem_post, [:sem_p], :int
|
||||||
attach_function :sem_wait, [:sem_p], :int
|
attach_function :sem_wait, [:sem_p], :int, :blocking => true
|
||||||
attach_function :sem_trywait, [:sem_p], :int
|
attach_function :sem_trywait, [:sem_p], :int, :blocking => true
|
||||||
attach_function :sem_timedwait, [:sem_p, TimeSpec], :int
|
|
||||||
|
# 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,
|
error_check(:sem_close, :sem_unlink, :sem_init, :sem_destroy,
|
||||||
:sem_getvalue, :sem_post, :sem_wait, :sem_trywait,
|
:sem_getvalue, :sem_post, :sem_wait, :sem_trywait,
|
||||||
|
|
|
@ -55,6 +55,5 @@ module ProcessShared
|
||||||
mem.get_char(0).must_equal(0)
|
mem.get_char(0).must_equal(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -91,6 +91,32 @@ module ProcessShared
|
||||||
end
|
end
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
describe '#try_wait' do
|
describe '#try_wait' do
|
||||||
|
@ -131,6 +157,39 @@ module ProcessShared
|
||||||
::Process.wait(pid)
|
::Process.wait(pid)
|
||||||
end
|
end
|
||||||
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
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue