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

Use Mutex#owned? to correctly check if the Mutex is owned by the current Thread or Fiber #504

Merged
merged 2 commits into from
Apr 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
### Development

Bug Fixes:

* Use `Mutex#owned?` to allow `RSpec::Support::ReentrantMutex` to work in
nested Fibers on Ruby 3.0 and later. (Benoit Daloze, #503, #504)

### 3.10.2 / 2021-01-28
[Full Changelog](http://github.com/rspec/rspec-support/compare/v3.10.1...v3.10.2)

Expand Down
37 changes: 27 additions & 10 deletions lib/rspec/support/reentrant_mutex.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,17 +27,34 @@ def synchronize

private

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

def exit
@count -= 1
return unless @count == 0
@owner = nil
@mutex.unlock
def exit
unless @mutex.owned?
raise ThreadError, "Attempt to unlock a mutex which is locked by another thread/fiber"
end
@count -= 1
@mutex.unlock if @count == 0
end
else
def enter
@mutex.lock if @owner != Thread.current
@owner = Thread.current
@count += 1
end

def exit
@count -= 1
return unless @count == 0
@owner = nil
@mutex.unlock
end
end
end

Expand Down
24 changes: 24 additions & 0 deletions spec/rspec/support/reentrant_mutex_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,28 @@
mutex.synchronize { order.pass_to :thread, :resume_on => :sleep }
order.join_all
end

if RUBY_VERSION >= '3.0'
it 'waits when trying to lock from another Fiber' do
mutex.synchronize do
ready = false
f = Fiber.new do
expect {
ready = true
mutex.send(:enter)
raise 'should reach here: mutex is already locked on different Fiber'
}.to raise_error(Exception, 'waited correctly')
end

main_thread = Thread.current

t = Thread.new do
Thread.pass until ready && main_thread.stop?
main_thread.raise Exception, 'waited correctly'
end
f.resume
t.join
end
end
end
end