United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6772683 : Thread.isInterrupted() fails to return true on multiprocessor PC

Details
Type:
Bug
Submit Date:
2008-11-18
Status:
Closed
Updated Date:
2011-02-16
Project Name:
JDK
Resolved Date:
2009-08-13
Component:
hotspot
OS:
windows_vista,other
Sub-Component:
compiler
CPU:
x86,unknown
Priority:
P4
Resolution:
Fixed
Affected Versions:
5.0-pool,6u10
Fixed Versions:
hs16 (b04)

Related Reports
Backport:
Backport:
Backport:
Backport:
Backport:
Backport:
Backport:

Sub Tasks

Description
FULL PRODUCT VERSION :
On Windows Vista 64-Bit:
java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) 64-Bit Server VM (build 11.0-b15, mixed mode)

java version "1.5.0_16"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_16-b02)
Java HotSpot(TM) 64-Bit Server VM (build 1.5.0_16-b02, mixed mode)

java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b39)
Java HotSpot(TM) 64-Bit Server VM (build 14.0-b06, mixed mode)

On Linux Ubuntu 64-Bit:
java version "1.5.0_16"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_16-b02)
Java HotSpot(TM) Server VM (build 1.5.0_16-b02, mixed mode)

java version "1.5.0_16"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_16-b02)
Java HotSpot(TM) 64-Bit Server VM (build 1.5.0_16-b02, mixed mode)

java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) Server VM (build 11.0-b15, mixed mode)

java version "1.6.0_10"
Java(TM) SE Runtime Environment (build 1.6.0_10-b33)
Java HotSpot(TM) 64-Bit Server VM (build 11.0-b15, mixed mode)

java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b39)
Java HotSpot(TM) Server VM (build 14.0-b06, mixed mode)

java version "1.7.0-ea"
Java(TM) SE Runtime Environment (build 1.7.0-ea-b39)
Java HotSpot(TM) 64-Bit Server VM (build 14.0-b06, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [version 6.0.6001] 64-Bit edition
Linux QuadCore 2.6.24-19-generic #1 SMP Wed Aug 20 17:53:40 UTC 2008 x86_64 GNU/Linux


EXTRA RELEVANT SYSTEM CONFIGURATION :
CPU: Q6600
memory: 4Gb


A DESCRIPTION OF THE PROBLEM :
While running two simultaneous threads, the first thread interrupts the second one using Thread.interrupt().
The second thread tests if it has been interrupted calling the Thread.isInterrupted() method which always returns false.

This occurs on a multiprocessor PC running a 64-Bit OS (Vista and Linux).
On Vista 64-Bit, this occurs when using a 64-bit JVM (all versions from 1.5 to 1.7), but does not occur when using a 32-bit JVM.
On Linux 64-bit, this occurs when using a 64-bit JVM (all versions from 1.5 to 1.7) or when using a 32-bit JVM (all versions from 1.5 to 1.7).


STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. In the following program, the main thread creates a worker thread.
2. The worker thread enters in an infinite loop until it is interrupted. (calling the isInterrupted() method)
3. The main thread waits for the worker thread to die with a timeout of 1 second.
4. The main thread interrupts the worker thread and waits for it to die.
5. The worker thread continuously calls the isInterrupted() method that always return false whereas the thread is interrupted !


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The Thread.isInterrupted() method should return true and the worker thread should exit.
Here is output of the program executed with a 32-bit JVM on Vista 64-Bit:

Main thread: starts a worker thread...
Main thread: waits at most 1s for the worker thread to die...
Worker thread: running...
Main thread: interrupts the worker thread...
Worker thread: bye
Main thread: worker thread is interrupted
Main thread: waits for the worker thread to die...
Main thread: bye
ACTUAL -
The Thread.isInterrupted() method returns false and the worker thread never exit.
Here is output of the program executed with a 64-bit JVM on Vista 64-Bit:

Main thread: starts a worker thread...
Main thread: waits at most 1s for the worker thread to die...
Worker thread: running...
Main thread: interrupts the worker thread...
Main thread: worker thread is interrupted
Main thread: waits for the worker thread to die...

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
public class InterruptedTest {

    public static void main(String[] args) throws Exception {
        Thread workerThread = new Thread("worker") {
            public void run() {
                System.out.println("Worker thread: running...");
                while (!Thread.currentThread().isInterrupted()) {
                }
                System.out.println("Worker thread: bye");
            }
        };
        System.out.println("Main thread: starts a worker thread...");
        workerThread.start();
        System.out.println("Main thread: waits at most 1s for the worker thread to die...");
        workerThread.join(1000);
        if (workerThread.isAlive()) {
            System.out.println("Main thread: interrupts the worker thread...");
            workerThread.interrupt();
            if (workerThread.isInterrupted()) {
                System.out.println("Main thread: worker thread is interrupted");
            }
            System.out.println("Main thread: waits for the worker thread to die...");
            workerThread.join();
        }
        System.out.println("Main thread: bye");
    }

}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Calling Thread.yield() before Thread.isInterrupted() bypasses the bug.
Calling Thread.interrupted() instead of Thread.isInterrupted() bypasses the bug.

                                    

Comments
SUGGESTED FIX

src/share/vm/opto/library_call.cpp
@@ -2593,7 +2593,8 @@ bool LibraryCallKit::inline_native_isInt
   Node* p = basic_plus_adr(top()/*!oop*/, tls_ptr, in_bytes(JavaThread::osthread_offset()));
   Node* osthread = make_load(NULL, p, TypeRawPtr::NOTNULL, T_ADDRESS);
   p = basic_plus_adr(top()/*!oop*/, osthread, in_bytes(OSThread::interrupted_offset()));
-  Node* int_bit = make_load(NULL, p, TypeInt::BOOL, T_INT);
+  // Set the control input on the field _interrupted read to prevent it floating up.
+  Node* int_bit = make_load(control(), p, TypeInt::BOOL, T_INT);
   Node* cmp_bit = _gvn.transform( new (C, 3) CmpINode(int_bit, intcon(0)) );
   Node* bol_bit = _gvn.transform( new (C, 2) BoolNode(cmp_bit, BoolTest::ne) );
                                     
2009-05-21
PUBLIC COMMENTS

Problem:
The C2 intrinsic isInterrupted() misses a control edge setting for
the field thread::_interrupted load. The load use raw (not oop) thread
pointer for which we don't generate a NULL check which prevents in
an oop case the load to flow up.
In the bug case the field load flow up from the loop and the field check
follows it which is wrong.

Solution:
Set the control edge for the field _interrupted load.
                                     
2009-05-21
EVALUATION

C2 has an instrinic implementation of isInterrupt to avoid the call into the VM for the case that the receiver is the current thread. The issue is likely to be there as this doesn't duplicate with the client VM or with -Xint.
                                     
2009-05-19
EVALUATION

http://hg.openjdk.java.net/jdk7/hotspot-comp/hotspot/rev/aabd393cf1ee
                                     
2009-05-21



Hardware and Software, Engineered to Work Together