Please sign in to comment.
Remove several locks involved in thread mail and lifecycle.
The deadlock reported in #1015 was caused by RubyThread#dispose and Thread#kill logic (RubyThread#kill) acquiring the same two locks in opposite order. dispose first acquired the RubyThread monitor, in order to read and write volatile state, and then acquired the ThreadService monitor without releasing RubyThread in order to unregister the RubyThread object. kill acquired the ThreadService monitor and then attempted to acquire the RubyThread monitor in order to deliver the kill event. As it turned out, the "mail" field on RubyThread was the primary actor triggering the use of synchronization, and much of that synchronization was not necessary. The removal of the thread from ThreadService did not need to be synchronized. The dispose and receiveMail methods did not need to be synchronized if the mail slot was made into an atomic reference. The deliverEvent method did not need to be synchronized for any reason. I made the appropriate changes to turn mail into an atomic reference, avoid keeping the RubyThread lock when calling into ThreadService to remove the RubyThread, and remove locks that became irrelevant once mail became atomic. Fixes #1015.
- Loading branch information...
Showing with 43 additions and 13 deletions.
|@@ -0,0 +1,23 @@|
|+describe 'A thread dying naturally while being killed' do|
|+ it 'should not deadlock' do|
|+ ary = |
|+ n = 100|
|+ # This logic is crafted to attempt to maximize likelihood of deadlock.|
|+ # It could probably be better.|
|+ n.times do|
|+ running = false|
|+ t = Thread.new do|
|+ running = true|
|+ Thread.pass until running|
|+ ary << :ok|
|+ ary.should == [:ok] * n|