Skip to content

[fix] lock interruptibly / interrupt thread#5490

Closed
alexis779 wants to merge 1 commit intojruby:masterfrom
alexis779:issue_5476
Closed

[fix] lock interruptibly / interrupt thread#5490
alexis779 wants to merge 1 commit intojruby:masterfrom
alexis779:issue_5476

Conversation

@alexis779
Copy link
Contributor

Fixes #5476

Revert lock commit to be able to interrupt thread trying to acquire a lock.
Otherwise deadlock may appear if lock was already acquired by another thread.

Thread#join would block forever even though Thread#kill was called right before:

m = Mutex.new
m.lock

t = Thread.new do
  m.lock
end

t.kill
t.join

This is equivalent to following Java test

import org.junit.Test;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ThreadInterruptTest {

   @Test
   public void interrupt() {
      final Lock lock = new ReentrantLock();
      lock.lock();

      Thread thread = new Thread(() -> {
         try {
            lock.lockInterruptibly();
         } catch (InterruptedException ie) {
            System.err.println("lock acquiring was interrupted");
            return;
         }
      });
      thread.start();

      thread.interrupt();

      try {
         thread.join();
      } catch (InterruptedException ie) {
         System.err.println("Can not join thread");
         return;
      }
   }
}

2 conditions need to happen to avoid getting stuck

  • call Thread#lockInterruptibly to acquire lock
  • call Thread#interrupt to unblock thread

Thread Dumps

Here are the thread dumps to illustrate the deadlock:

Main thread:

"main@1" prio=5 tid=0x1 nid=NA waiting
  java.lang.Thread.State: WAITING
	  at java.lang.Object.wait(Object.java:-1)
	  at java.lang.Thread.join(Thread.java:1260)
	  at org.jruby.internal.runtime.NativeThread.join(NativeThread.java:75)
	  at org.jruby.RubyThread.join(RubyThread.java:1079)
	  at org.jruby.RubyThread$INVOKER$i$0$1$join.call(RubyThread$INVOKER$i$0$1$join.gen:-1)

New thread:

"Ruby-0-Thread-1: thread_kill.rb:4@6126" daemon prio=5 tid=0xe nid=NA waiting
  java.lang.Thread.State: WAITING
	  at sun.misc.Unsafe.park(Unsafe.java:-1)
	  at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
	  at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
	  at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
	  at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
	  at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:209)
	  at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:285)
	  at org.jruby.RubyThread.lock(RubyThread.java:2087)
	  at org.jruby.ext.thread.Mutex.lock(Mutex.java:95)
	  at org.jruby.ext.thread.Mutex$INVOKER$i$0$0$lock.call(Mutex$INVOKER$i$0$0$lock.gen:-1)

thread.lockInterruptibly(lock);
} catch (InterruptedException ie) {
context.pollThreadEvents();
throw context.runtime.newConcurrencyError("interrupted waiting for mutex");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConcurrencyError is JRuby specific, not sure what MRI does but maybe raise an Interrupt here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interrupt is probably not right because it typically corresponds to SIGINT and usually leads to termination of the runtime. This patch basically undoes a "fix" I did in #4261. Simply going back to interruptible/Interrupted exception would undo that "fix" and break LogStash. We need a better option.

@kares
Copy link
Member

kares commented Jun 24, 2019

this one is pretty much defunct - the alternative from #5683 got merged for 9.2.8.0

@kares kares closed this Jun 24, 2019
@kares kares added this to the Invalid or Duplicate milestone Jun 24, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Mutex#lock and Mutex#synchronize are not interruptible by Thread#kill

3 participants