Skip to content
This repository was archived by the owner on Nov 30, 2024. It is now read-only.

Commit 4ad8392

Browse files
authored
Merge pull request #504 from rspec/fix-reentrant-mutex-fiber-3.0
Use Mutex#owned? to correctly check if the Mutex is owned by the current Thread or Fiber
2 parents d63133f + 18beef8 commit 4ad8392

File tree

3 files changed

+58
-10
lines changed

3 files changed

+58
-10
lines changed

Changelog.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
### Development
2+
3+
Bug Fixes:
4+
5+
* Use `Mutex#owned?` to allow `RSpec::Support::ReentrantMutex` to work in
6+
nested Fibers on Ruby 3.0 and later. (Benoit Daloze, #503, #504)
7+
18
### 3.10.2 / 2021-01-28
29
[Full Changelog](http://github.com/rspec/rspec-support/compare/v3.10.1...v3.10.2)
310

lib/rspec/support/reentrant_mutex.rb

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,34 @@ def synchronize
2727

2828
private
2929

30-
def enter
31-
@mutex.lock if @owner != Thread.current
32-
@owner = Thread.current
33-
@count += 1
34-
end
30+
# This is fixing a bug #501 that is specific to Ruby 3.0. The new implementation
31+
# depends on `owned?` that was introduced in Ruby 2.0, so both should work for Ruby 2.x.
32+
if RUBY_VERSION.to_f >= 3.0
33+
def enter
34+
@mutex.lock unless @mutex.owned?
35+
@count += 1
36+
end
3537

36-
def exit
37-
@count -= 1
38-
return unless @count == 0
39-
@owner = nil
40-
@mutex.unlock
38+
def exit
39+
unless @mutex.owned?
40+
raise ThreadError, "Attempt to unlock a mutex which is locked by another thread/fiber"
41+
end
42+
@count -= 1
43+
@mutex.unlock if @count == 0
44+
end
45+
else
46+
def enter
47+
@mutex.lock if @owner != Thread.current
48+
@owner = Thread.current
49+
@count += 1
50+
end
51+
52+
def exit
53+
@count -= 1
54+
return unless @count == 0
55+
@owner = nil
56+
@mutex.unlock
57+
end
4158
end
4259
end
4360

spec/rspec/support/reentrant_mutex_spec.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,28 @@
2727
mutex.synchronize { order.pass_to :thread, :resume_on => :sleep }
2828
order.join_all
2929
end
30+
31+
if RUBY_VERSION >= '3.0'
32+
it 'waits when trying to lock from another Fiber' do
33+
mutex.synchronize do
34+
ready = false
35+
f = Fiber.new do
36+
expect {
37+
ready = true
38+
mutex.send(:enter)
39+
raise 'should reach here: mutex is already locked on different Fiber'
40+
}.to raise_error(Exception, 'waited correctly')
41+
end
42+
43+
main_thread = Thread.current
44+
45+
t = Thread.new do
46+
Thread.pass until ready && main_thread.stop?
47+
main_thread.raise Exception, 'waited correctly'
48+
end
49+
f.resume
50+
t.join
51+
end
52+
end
53+
end
3054
end

0 commit comments

Comments
 (0)