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

Commit

Permalink
Use Mutex#owned? to correctly check if the Mutex is owned by the curr…
Browse files Browse the repository at this point in the history
…ent Thread or Fiber

* In Ruby >= 3, Mutex are held per Fiber, not per Thread.
* Fixes #501
  • Loading branch information
eregon committed Apr 28, 2021
1 parent b3563f1 commit 708d217
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 6 deletions.
11 changes: 5 additions & 6 deletions lib/rspec/support/reentrant_mutex.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ class << self
# @private
class ReentrantMutex
def initialize
@owner = nil
@count = 0
@mutex = Mutex.new
end
Expand All @@ -32,16 +31,16 @@ def synchronize
private

def enter
@mutex.lock if @owner != Thread.current
@owner = Thread.current
@mutex.lock unless @mutex.owned?
@count += 1
end

def exit
unless @mutex.owned?
raise ThreadError, "Attempt to unlock a mutex which is locked by another thread/fiber"
end
@count -= 1
return unless @count == 0
@owner = nil
@mutex.unlock
@mutex.unlock if @count == 0
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 @@ -34,4 +34,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 and main_thread.stop?
main_thread.raise Exception, 'waited correctly'
end
f.resume
t.join
end
end
end
end

0 comments on commit 708d217

Please sign in to comment.