6498581: ThreadInterruptTest3 produces wrong output on Windows
Summary: There is race condition between os::interrupt and os::is_interrupted on Windows. In JVM_Sleep(Thread.sleep), check if thread gets interrupted, it may see interrupted but not really interrupted so cause spurious waking up (early return from sleep). Fix by checking if interrupt event really gets set thus prevent false return. For intrinsic of _isInterrupted, on Windows, go fastpath only on bit not set.
Reviewed-by: acorn, kvn
Contributed-by: david.holmes@oracle.com, yumin.qi@oracle.com
--- a/hotspot/src/os/windows/vm/os_windows.cpp Wed Feb 26 15:47:44 2014 +0100
+++ b/hotspot/src/os/windows/vm/os_windows.cpp Wed Feb 26 15:20:41 2014 -0800
@@ -3619,13 +3619,14 @@
"possibility of dangling Thread pointer");
OSThread* osthread = thread->osthread();
- bool interrupted = osthread->interrupted();
// There is no synchronization between the setting of the interrupt
// and it being cleared here. It is critical - see 6535709 - that
// we only clear the interrupt state, and reset the interrupt event,
// if we are going to report that we were indeed interrupted - else
// an interrupt can be "lost", leading to spurious wakeups or lost wakeups
- // depending on the timing
+ // depending on the timing. By checking thread interrupt event to see
+ // if the thread gets real interrupt thus prevent spurious wakeup.
+ bool interrupted = osthread->interrupted() && (WaitForSingleObject(osthread->interrupt_event(), 0) == WAIT_OBJECT_0);
if (interrupted && clear_interrupted) {
osthread->set_interrupted(false);
ResetEvent(osthread->interrupt_event());
--- a/hotspot/src/share/vm/opto/library_call.cpp Wed Feb 26 15:47:44 2014 +0100
+++ b/hotspot/src/share/vm/opto/library_call.cpp Wed Feb 26 15:20:41 2014 -0800
@@ -3246,7 +3246,8 @@
// private native boolean java.lang.Thread.isInterrupted(boolean ClearInterrupted);
bool LibraryCallKit::inline_native_isInterrupted() {
// Add a fast path to t.isInterrupted(clear_int):
- // (t == Thread.current() && (!TLS._osthread._interrupted || !clear_int))
+ // (t == Thread.current() &&
+ // (!TLS._osthread._interrupted || WINDOWS_ONLY(false) NOT_WINDOWS(!clear_int)))
// ? TLS._osthread._interrupted : /*slow path:*/ t.isInterrupted(clear_int)
// So, in the common case that the interrupt bit is false,
// we avoid making a call into the VM. Even if the interrupt bit
@@ -3303,6 +3304,7 @@
// drop through to next case
set_control( _gvn.transform(new (C) IfTrueNode(iff_bit)));
+#ifndef TARGET_OS_FAMILY_windows
// (c) Or, if interrupt bit is set and clear_int is false, use 2nd fast path.
Node* clr_arg = argument(1);
Node* cmp_arg = _gvn.transform(new (C) CmpINode(clr_arg, intcon(0)));
@@ -3316,6 +3318,10 @@
// drop through to next case
set_control( _gvn.transform(new (C) IfTrueNode(iff_arg)));
+#else
+ // To return true on Windows you must read the _interrupted field
+ // and check the the event state i.e. take the slow path.
+#endif // TARGET_OS_FAMILY_windows
// (d) Otherwise, go to the slow path.
slow_region->add_req(control());