Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I write native code which responds to `Thread.interrupt()`?

In Java, all the standard blocking methods can be interrupted by calling Thread.interrupt(), but what if we have Java bindings wrapping a native library which does its own I/O? How then should the native code hook into the Thread and respond to calls to Thread.interrupt()?

like image 972
Nicholas Wilson Avatar asked Mar 29 '15 15:03

Nicholas Wilson


People also ask

How do you handle a thread interrupt?

interrupt() method: If any thread is in sleeping or waiting for a state then using the interrupt() method, we can interrupt the execution of that thread by showing InterruptedException. A thread that is in the sleeping or waiting state can be interrupted with the help of the interrupt() method of Thread class.

What happens when thread is interrupted?

The "interrupted" status of the thread is set to true. If the thread is currently blocked by a call to sleep or wait, an InterruptedException is thrown. tests whether or not the current thread (that is, the thread that is executing this instruction) has been interrupted. Note that this is a static method.

What is the use of the interrupt () function of thread class?

An interrupt is an indication to a thread that it should stop what it is doing and do something else. It's up to the programmer to decide exactly how a thread responds to an interrupt, but it is very common for the thread to terminate.

What does thread currentThread () interrupt () do?

currentThread(). interrupt() in Interruptible Methods? By an interruptible method, we mean a blocking method that may throw InterruptedException , for example, Thread. sleep() , BlockingQueue.


1 Answers

Example code

For a full writeup, including runnable sample code, see https://github.com/NWilson/javaInterruptHook.

How does Thread.interrupt() work?

In Sun's JRE (and OpenJDK), interrupt() is able to wake up a few low-level operations itself, such as waiting on a monitor (Object.wait()), and provides an internal hook for higher-level code to be notified of the interruption. This is provided through JavaLangAccess.blockedOn(), which can actually be called directly by your code through sun.misc.SharedSecrets, if you're willing to use Sun-specific implementation details.

As far as I can tell, there's only one public, documented way to register for that notification, which is using java.nio.channels.spi.AbstractSelector. This is a partial implementation of Selector which does the dirty work for you of hooking up the JavaLangAccess.blockedOn() notification to the selector's wakeup() method.

How to implement this all

Implement AbstractSelector to make your own selector; most of the methods are not relevant so just ignore them and put in stubs to shut up the compiler. When you are about to enter your JNI blocking method, call the AbstractSelector begin() method, then call end() when the JNI call has returned.

The selector should cancel the JNI method in its implementation of wakeup().

Rough code

(For a full running example see the github repo linked at the top.)

class NativeTask {
    public NativeTask() {}

    public void doTask()
            throws InterruptedException {
        NativeTaskSelector selector = new NativeTaskSelector(this);
        try {
            selector.registerStart();
            doTask0(); // native method
            if (Thread.interrupted())
                    throw new InterruptedException();
        } finally {
            selector.registerEnd();
            try { selector.close(); } catch (IOException impossible) {}
        }
    }
    /* The long-running native operation. */
    native private void doTask0();

    public void wakeupTask() { wakeupTask0(); }
    /* A way to cause the native operation to wake up. */
    native private void wakeupTask0();
}

class NativeTaskSelector extends AbstractSelector {

    protected NativeTaskSelector(NativeTask task_) {
        super(null);
        task = task_;
    }

    public void registerStart() { begin(); }
    public void registerEnd() { end(); }

    final private NativeTask task;

    @Override
    public Selector wakeup() {
        task.wakeupTask();
        return this;
    }

    @Override
    protected void implCloseSelector() throws IOException {
    }

    @Override
    protected SelectionKey register(AbstractSelectableChannel arg0, int arg1,
            Object arg2) {
        throw new UnsupportedOperationException();
    }

    @Override
    public Set<SelectionKey> keys() {
        throw new UnsupportedOperationException();
    }

    @Override
    public int select() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public int select(long arg0) throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public int selectNow() throws IOException {
        throw new UnsupportedOperationException();
    }

    @Override
    public Set<SelectionKey> selectedKeys() {
        throw new UnsupportedOperationException();
    }

}
like image 109
Nicholas Wilson Avatar answered Oct 05 '22 07:10

Nicholas Wilson