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

Commit 6538c68

Browse files
authored
Merge pull request #503 from eregon/fix-reentrant-mutex-fiber
Use Mutex#owned? to correctly check if the Mutex is owned by the current Thread or Fiber
2 parents b3563f1 + a4be9d5 commit 6538c68

File tree

3 files changed

+32
-6
lines changed

3 files changed

+32
-6
lines changed

Changelog.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ Breaking Changes:
44

55
* Ruby < 2.3 is no longer supported. (Phil Pirozhkov, #436)
66

7+
Bug Fixes:
8+
* Fix reentrant mutex for Ruby 3.0. (Benoit Daloze, #503)
9+
710
### 3.10.0 / 2020-10-30
811

912
No changes. Released to support other RSpec releases.

lib/rspec/support/reentrant_mutex.rb

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ class << self
1717
# @private
1818
class ReentrantMutex
1919
def initialize
20-
@owner = nil
2120
@count = 0
2221
@mutex = Mutex.new
2322
end
@@ -32,16 +31,16 @@ def synchronize
3231
private
3332

3433
def enter
35-
@mutex.lock if @owner != Thread.current
36-
@owner = Thread.current
34+
@mutex.lock unless @mutex.owned?
3735
@count += 1
3836
end
3937

4038
def exit
39+
unless @mutex.owned?
40+
raise ThreadError, "Attempt to unlock a mutex which is locked by another thread/fiber"
41+
end
4142
@count -= 1
42-
return unless @count == 0
43-
@owner = nil
44-
@mutex.unlock
43+
@mutex.unlock if @count == 0
4544
end
4645
end
4746
end

spec/rspec/support/reentrant_mutex_spec.rb

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

0 commit comments

Comments
 (0)