Skip to content

Commit 58905f5

Browse files
authored
Merge pull request #9259 from headius/deadlock_interrupted_lock
Only set locking thread once successful
2 parents 0303464 + fd66320 commit 58905f5

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,6 @@ public IRubyObject lock(ThreadContext context) {
124124
}
125125
}
126126

127-
this.lockingThread = parentThread;
128-
129127
// always check for thread interrupts after acquiring lock
130128
try {
131129
thread.pollThreadEvents(context);
@@ -137,6 +135,9 @@ public IRubyObject lock(ThreadContext context) {
137135
Helpers.throwException(t);
138136
}
139137

138+
// set locking thread once successfully locked with no interrupts
139+
this.lockingThread = parentThread;
140+
140141
return this;
141142
}
142143

spec/ruby/core/mutex/lock_spec.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,42 @@
4848
f1.resume
4949
-> { f2.resume }.should raise_error(ThreadError, /deadlock/)
5050
end
51+
52+
it "does not raise deadlock if a fiber's attempt to lock was interrupted" do
53+
lock = Mutex.new
54+
main = Thread.current
55+
56+
t2 = nil
57+
t1 = Thread.new do
58+
loop do
59+
# interrupt fiber below looping on synchronize
60+
sleep 0.01
61+
t2.raise if t2
62+
end
63+
end
64+
65+
# loop ten times to try to handle the interrupt during synchronize
66+
t2 = Thread.new do
67+
10.times do
68+
Fiber.new do
69+
begin
70+
loop { lock.synchronize {} }
71+
rescue RuntimeError
72+
end
73+
end.resume
74+
75+
Fiber.new do
76+
->() do
77+
lock.synchronize {}
78+
end.should_not raise_error(ThreadError)
79+
end.resume
80+
rescue RuntimeError
81+
retry
82+
end
83+
end
84+
t2.join
85+
ensure
86+
t1.kill rescue nil
87+
t2.kill rescue nil
88+
end
5189
end

0 commit comments

Comments
 (0)