Skip to content

Commit a66cf51

Browse files
authored
Merge pull request jruby#9226 from headius/narrow_fiber_deadlock_check
Narrow deadlock check for sibling fibers locking mutex
2 parents 8bbf037 + a418dd9 commit a66cf51

2 files changed

Lines changed: 27 additions & 5 deletions

File tree

core/src/main/java/org/jruby/ext/thread/Mutex.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ public IRubyObject lock(ThreadContext context) {
106106

107107
checkRelocking(context);
108108

109-
if (this.lockingThread == parentThread) {
109+
RubyThread lockingThread = this.lockingThread;
110+
if (lockingThread == parentThread && context.getFiber() != lockingThread.getContext().getFiber()) {
110111
throw context.runtime.newThreadError("deadlock; lock already owned by another fiber belonging to the same thread");
111112
}
112113

@@ -123,7 +124,7 @@ public IRubyObject lock(ThreadContext context) {
123124
}
124125
}
125126

126-
this.lockingThread = thread;
127+
this.lockingThread = parentThread;
127128

128129
// always check for thread interrupts after acquiring lock
129130
try {
@@ -204,7 +205,7 @@ public IRubyObject owned_p(ThreadContext context) {
204205

205206
private void checkRelocking(ThreadContext context) {
206207
if (lock.isHeldByCurrentThread()) {
207-
throw context.runtime.newThreadError("Mutex relocking by same thread");
208+
throw context.runtime.newThreadError("deadlock; recursive locking");
208209
}
209210
}
210211

spec/ruby/core/mutex/lock_spec.rb

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,32 @@
2020

2121
# Unable to find a specific ticket but behavior change may be
2222
# related to this ML thread.
23-
it "raises a ThreadError when used recursively" do
23+
it "raises a deadlock ThreadError when used recursively" do
2424
m = Mutex.new
2525
m.lock
2626
-> {
2727
m.lock
28-
}.should raise_error(ThreadError)
28+
}.should raise_error(ThreadError, /deadlock/)
29+
end
30+
31+
it "raises a deadlock ThreadError when multiple fibers from the same thread try to lock" do
32+
m = Mutex.new
33+
34+
m.lock
35+
f0 = Fiber.new do
36+
m.lock
37+
end
38+
-> { f0.resume }.should raise_error(ThreadError, /deadlock/)
39+
40+
m.unlock
41+
f1 = Fiber.new do
42+
m.lock
43+
Fiber.yield
44+
end
45+
f2 = Fiber.new do
46+
m.lock
47+
end
48+
f1.resume
49+
-> { f2.resume }.should raise_error(ThreadError, /deadlock/)
2950
end
3051
end

0 commit comments

Comments
 (0)