--- old/src/hotspot/share/runtime/biasedLocking.cpp 2020-04-03 07:06:20.374619659 +0000 +++ new/src/hotspot/share/runtime/biasedLocking.cpp 2020-04-03 07:06:19.511598934 +0000 @@ -668,7 +668,7 @@ void BiasedLocking::walk_stack_and_revoke(oop obj, JavaThread* biased_locker) { Thread* cur = Thread::current(); assert(!SafepointSynchronize::is_at_safepoint(), "this should always be executed outside safepoints"); - assert(cur == biased_locker || cur == biased_locker->get_active_handshaker(), "wrong thread"); + assert(cur == biased_locker || cur == biased_locker->active_handshaker(), "wrong thread"); markWord mark = obj->mark(); assert(mark.biased_locker() == biased_locker && --- old/src/hotspot/share/runtime/handshake.cpp 2020-04-03 07:06:21.360643338 +0000 +++ new/src/hotspot/share/runtime/handshake.cpp 2020-04-03 07:06:20.504622781 +0000 @@ -53,7 +53,7 @@ void do_handshake(JavaThread* thread); bool is_completed() { int32_t val = Atomic::load(&_pending_threads); - assert(val >= 0, "_pending_threads cannot be negative"); + assert(val >= 0, "_pending_threads=%d cannot be negative", val); return val == 0; } void add_target_count(int count) { Atomic::add(&_pending_threads, count); } @@ -64,7 +64,7 @@ #ifdef ASSERT void check_state() { - assert(_pending_threads == 0, "Must be zero"); + assert(_pending_threads == 0, "Must be zero: %d", _pending_threads); } #endif }; @@ -225,7 +225,12 @@ name(), p2i(thread), BOOL_TO_STR(Thread::current()->is_VM_thread()), completion_time); } - // Inform VMThread/Handshaker that we have completed the operation + // Inform VMThread/Handshaker that we have completed the operation. + // When this is executed by the Handshakee we need a release store + // here to make sure memory operations executed in the handshake + // closure are visible to the Handshaker after it reads that the + // operation has completed. Atomic::dec() already provides a full + // memory fence. Atomic::dec(&_pending_threads); // It is no longer safe to refer to 'this' as the VMThread/Handshaker may have destroyed this operation @@ -273,6 +278,11 @@ DEBUG_ONLY(op.check_state();) log_handshake_info(start_time_ns, op.name(), 1, by_handshaker ? 1 : 0); + // Prevent future loads from floating above the load of _pending_threads + // in is_completed(). This prevents reading stale data modified in the + // handshake closure by the Handshakee. + OrderAccess::acquire(); + return op.executed(); } @@ -399,7 +409,7 @@ // Check if the handshake operation is the same as the one we meant to execute. The // handshake could have been already processed by the handshakee and a new handshake // by another JavaThread might be in progress. - if ( (is_direct && op != _operation_direct)) { + if (is_direct && op != _operation_direct) { _processing_sem.signal(); return false; } --- old/src/hotspot/share/runtime/handshake.hpp 2020-04-03 07:06:22.374667690 +0000 +++ new/src/hotspot/share/runtime/handshake.hpp 2020-04-03 07:06:21.512646989 +0000 @@ -82,7 +82,7 @@ public: HandshakeState(); - void set_thread(JavaThread* thread) { _handshakee = thread; } + void set_handshakee(JavaThread* thread) { _handshakee = thread; } void set_operation(HandshakeOperation* op); bool has_operation() const { return _operation != NULL || _operation_direct != NULL; } @@ -100,7 +100,7 @@ #ifdef ASSERT Thread* _active_handshaker; - Thread* get_active_handshaker() const { return _active_handshaker; } + Thread* active_handshaker() const { return _active_handshaker; } #endif }; --- old/src/hotspot/share/runtime/mutexLocker.cpp 2020-04-03 07:06:23.485694371 +0000 +++ new/src/hotspot/share/runtime/mutexLocker.cpp 2020-04-03 07:06:22.618673549 +0000 @@ -188,7 +188,7 @@ } void assert_locked_or_safepoint_or_handshake(const Mutex* lock, const JavaThread* thread) { - if (Thread::current() == thread->get_active_handshaker()) return; + if (Thread::current() == thread->active_handshaker()) return; assert_locked_or_safepoint(lock); } #endif --- old/src/hotspot/share/runtime/thread.cpp 2020-04-03 07:06:24.596721051 +0000 +++ new/src/hotspot/share/runtime/thread.cpp 2020-04-03 07:06:23.732700302 +0000 @@ -1691,7 +1691,7 @@ _SleepEvent = ParkEvent::Allocate(this); // Setup safepoint state info for this thread ThreadSafepointState::create(this); - _handshake.set_thread(this); + _handshake.set_handshakee(this); debug_only(_java_call_counter = 0); @@ -4468,12 +4468,12 @@ exit_globals(); // We are here after VM_Exit::set_vm_exited() so we can't call - // thread->smr_delete() or we will block on the Threads_lock. - // We must check there are no active references to this thread - // before attempting to delete it. A thread could be waiting - // on _handshake_turn_sem trying to execute a direct handshake - // with this thread. - if (!ThreadsSMRSupport::is_a_protected_JavaThread((JavaThread *) thread)) { + // thread->smr_delete() or we will block on the Threads_lock. We + // must check that there are no active references to this thread + // before attempting to delete it. A thread could be waiting on + // _handshake_turn_sem trying to execute a direct handshake with + // this thread. + if (!ThreadsSMRSupport::is_a_protected_JavaThread(thread)) { delete thread; } else { // Clear value for _thread_key in TLS to prevent, depending --- old/src/hotspot/share/runtime/thread.hpp 2020-04-03 07:06:25.755748885 +0000 +++ new/src/hotspot/share/runtime/thread.hpp 2020-04-03 07:06:24.890728112 +0000 @@ -1356,8 +1356,8 @@ } #ifdef ASSERT - Thread* get_active_handshaker() const { - return _handshake.get_active_handshaker(); + Thread* active_handshaker() const { + return _handshake.active_handshaker(); } #endif --- old/test/hotspot/jtreg/runtime/handshake/HandshakeDirectTest.java 2020-04-03 07:06:26.994778640 +0000 +++ new/test/hotspot/jtreg/runtime/handshake/HandshakeDirectTest.java 2020-04-03 07:06:26.133757963 +0000 @@ -24,6 +24,7 @@ /* * @test HandshakeDirectTest + * @bug 8240918 * @summary This test tries to stress direct handshakes between threads while suspending them. * @library /testlibrary /test/lib * @build HandshakeDirectTest @@ -60,8 +61,9 @@ } // Handshake directly some other worker - int handshakee = ThreadLocalRandom.current().nextInt(0, WORKING_THREADS-1); + int handshakee = ThreadLocalRandom.current().nextInt(0, WORKING_THREADS - 1); if (handshakee == me) { + // Pick another thread instead of me. handshakee = handshakee != 0 ? handshakee - 1 : handshakee + 1; } handshakeSem[handshakee].acquire(); @@ -108,7 +110,7 @@ @Override public void run() { while (true) { - int i = ThreadLocalRandom.current().nextInt(0, WORKING_THREADS-1); + int i = ThreadLocalRandom.current().nextInt(0, WORKING_THREADS - 1); workingThreads[i].suspend(); try { Thread.sleep(1); // sleep for 1 ms