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

Commit 5e76f82

Browse files
committed
Use Mutex#owned? to correctly check if the Mutex is owned by the current Thread or Fiber
* In Ruby >= 3, Mutex are held per Fiber, not per Thread. * Fixes #501
1 parent d63133f commit 5e76f82

File tree

2 files changed

+29
-6
lines changed

2 files changed

+29
-6
lines changed

lib/rspec/support/reentrant_mutex.rb

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ module Support
1313
# @private
1414
class ReentrantMutex
1515
def initialize
16-
@owner = nil
1716
@count = 0
1817
@mutex = Mutex.new
1918
end
@@ -28,16 +27,16 @@ def synchronize
2827
private
2928

3029
def enter
31-
@mutex.lock if @owner != Thread.current
32-
@owner = Thread.current
30+
@mutex.lock unless @mutex.owned?
3331
@count += 1
3432
end
3533

3634
def exit
35+
unless @mutex.owned?
36+
raise ThreadError, "Attempt to unlock a mutex which is locked by another thread/fiber"
37+
end
3738
@count -= 1
38-
return unless @count == 0
39-
@owner = nil
40-
@mutex.unlock
39+
@mutex.unlock if @count == 0
4140
end
4241
end
4342

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 and 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)