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

Commit

Permalink
Merge pull request #504 from rspec/fix-reentrant-mutex-fiber-3.0
Browse files Browse the repository at this point in the history
Use Mutex#owned? to correctly check if the Mutex is owned by the current Thread or Fiber
  • Loading branch information
JonRowe committed Apr 29, 2021
1 parent 835d085 commit 77269e4
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 10 deletions.
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

0 comments on commit 77269e4

Please sign in to comment.