# HG changeset patch # User kbarrett # Date 1458862966 0 # Node ID 3cda05a8c3f2fff1c26d172351c485ca16ec0c42 # Parent 0e574aa1789109d3fdbe152dd30d33e74c592869# Parent 390e3a2e7cee51346d00b7fc49744f7b8b910b76 Merge diff -r 0e574aa17891 -r 3cda05a8c3f2 hotspot/src/share/vm/gc/g1/suspendibleThreadSet.cpp --- a/hotspot/src/share/vm/gc/g1/suspendibleThreadSet.cpp Thu Mar 24 20:17:07 2016 +0000 +++ b/hotspot/src/share/vm/gc/g1/suspendibleThreadSet.cpp Thu Mar 24 23:42:46 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ #include "precompiled.hpp" #include "gc/g1/suspendibleThreadSet.hpp" #include "runtime/mutexLocker.hpp" +#include "runtime/semaphore.hpp" #include "runtime/thread.inline.hpp" uint SuspendibleThreadSet::_nthreads = 0; @@ -32,6 +33,19 @@ bool SuspendibleThreadSet::_suspend_all = false; double SuspendibleThreadSet::_suspend_all_start = 0.0; +static Semaphore* _synchronize_wakeup = NULL; + +void SuspendibleThreadSet_init() { + assert(_synchronize_wakeup == NULL, "STS already initialized"); + _synchronize_wakeup = new Semaphore(); +} + +bool SuspendibleThreadSet::is_synchronized() { + assert_lock_strong(STS_lock); + assert(_nthreads_stopped <= _nthreads, "invariant"); + return _nthreads_stopped == _nthreads; +} + void SuspendibleThreadSet::join() { assert(!Thread::current()->is_suspendible_thread(), "Thread already joined"); MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); @@ -48,31 +62,30 @@ assert(_nthreads > 0, "Invalid"); DEBUG_ONLY(Thread::current()->clear_suspendible_thread();) _nthreads--; - if (_suspend_all) { - ml.notify_all(); + if (_suspend_all && is_synchronized()) { + // This leave completes a request, so inform the requestor. + _synchronize_wakeup->signal(); } } void SuspendibleThreadSet::yield() { assert(Thread::current()->is_suspendible_thread(), "Must have joined"); + MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); if (_suspend_all) { - MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); - if (_suspend_all) { - _nthreads_stopped++; - if (_nthreads_stopped == _nthreads) { - if (ConcGCYieldTimeout > 0) { - double now = os::elapsedTime(); - guarantee((now - _suspend_all_start) * 1000.0 < (double)ConcGCYieldTimeout, "Long delay"); - } + _nthreads_stopped++; + if (is_synchronized()) { + if (ConcGCYieldTimeout > 0) { + double now = os::elapsedTime(); + guarantee((now - _suspend_all_start) * 1000.0 < (double)ConcGCYieldTimeout, "Long delay"); } - ml.notify_all(); - while (_suspend_all) { - ml.wait(Mutex::_no_safepoint_check_flag); - } - assert(_nthreads_stopped > 0, "Invalid"); - _nthreads_stopped--; - ml.notify_all(); + // This yield completes the request, so inform the requestor. + _synchronize_wakeup->signal(); } + while (_suspend_all) { + ml.wait(Mutex::_no_safepoint_check_flag); + } + assert(_nthreads_stopped > 0, "Invalid"); + _nthreads_stopped--; } } @@ -81,18 +94,41 @@ if (ConcGCYieldTimeout > 0) { _suspend_all_start = os::elapsedTime(); } + { + MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); + assert(!_suspend_all, "Only one at a time"); + _suspend_all = true; + if (is_synchronized()) { + return; + } + } // Release lock before semaphore wait. + + // Semaphore initial count is zero. To reach here, there must be at + // least one not yielded thread in the set, e.g. is_synchronized() + // was false before the lock was released. A thread in the set will + // signal the semaphore iff it is the last to yield or leave while + // there is an active suspend request. So there will be exactly one + // signal, which will increment the semaphore count to one, which + // will then be consumed by this wait, returning it to zero. No + // thread can exit yield or enter the set until desynchronize is + // called, so there are no further opportunities for the semaphore + // being signaled until we get back here again for some later + // synchronize call. Hence, there is no need to re-check for + // is_synchronized after the wait; it will always be true there. + _synchronize_wakeup->wait(); + +#ifdef ASSERT MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); - assert(!_suspend_all, "Only one at a time"); - _suspend_all = true; - while (_nthreads_stopped < _nthreads) { - ml.wait(Mutex::_no_safepoint_check_flag); - } + assert(_suspend_all, "STS not synchronizing"); + assert(is_synchronized(), "STS not synchronized"); +#endif } void SuspendibleThreadSet::desynchronize() { assert(Thread::current()->is_VM_thread(), "Must be the VM thread"); MonitorLockerEx ml(STS_lock, Mutex::_no_safepoint_check_flag); - assert(_nthreads_stopped == _nthreads, "Invalid"); + assert(_suspend_all, "STS not synchronizing"); + assert(is_synchronized(), "STS not synchronized"); _suspend_all = false; ml.notify_all(); } diff -r 0e574aa17891 -r 3cda05a8c3f2 hotspot/src/share/vm/gc/g1/suspendibleThreadSet.hpp --- a/hotspot/src/share/vm/gc/g1/suspendibleThreadSet.hpp Thu Mar 24 20:17:07 2016 +0000 +++ b/hotspot/src/share/vm/gc/g1/suspendibleThreadSet.hpp Thu Mar 24 23:42:46 2016 +0000 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,8 @@ static bool _suspend_all; static double _suspend_all_start; + static bool is_synchronized(); + // Add the current thread to the set. May block if a suspension is in progress. static void join(); diff -r 0e574aa17891 -r 3cda05a8c3f2 hotspot/src/share/vm/runtime/init.cpp --- a/hotspot/src/share/vm/runtime/init.cpp Thu Mar 24 20:17:07 2016 +0000 +++ b/hotspot/src/share/vm/runtime/init.cpp Thu Mar 24 23:42:46 2016 +0000 @@ -47,6 +47,7 @@ void mutex_init(); void chunkpool_init(); void perfMemory_init(); +void SuspendibleThreadSet_init() NOT_ALL_GCS_RETURN; // Initialization done by Java thread in init_globals() void management_init(); @@ -93,6 +94,7 @@ mutex_init(); chunkpool_init(); perfMemory_init(); + SuspendibleThreadSet_init(); }