/*
* Copyright (c) 2017, 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
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "gc/shared/concurrentGCPhaseManager.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/thread.hpp"
#define assert_ConcurrentGC_thread() \
assert(Thread::current()->is_ConcurrentGC_thread(), "precondition")
#define assert_not_enter_unconstrained(phase) \
assert((phase) != UNCONSTRAINED_PHASE, "Cannot enter \"unconstrained\" phase")
#define assert_manager_is_tos(manager, stack, kind) \
assert((manager) == (stack)->_top, kind " manager is not top of stack")
ConcurrentGCPhaseManager::Stack::Stack() :
_requested_phase(UNCONSTRAINED_PHASE),
_top(NULL)
{ }
ConcurrentGCPhaseManager::ConcurrentGCPhaseManager(int phase, Stack* stack) :
_phase(phase),
_active(true),
_prev(NULL),
_stack(stack)
{
assert_ConcurrentGC_thread();
assert_not_enter_unconstrained(phase);
assert(stack != NULL, "precondition");
MonitorLockerEx ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
if (stack->_top != NULL) {
assert(stack->_top->_active, "precondition");
_prev = stack->_top;
}
stack->_top = this;
ml.notify_all();
}
ConcurrentGCPhaseManager::~ConcurrentGCPhaseManager() {
assert_ConcurrentGC_thread();
MonitorLockerEx ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
assert_manager_is_tos(this, _stack, "This");
wait_when_requested_impl();
_stack->_top = _prev;
ml.notify_all();
}
bool ConcurrentGCPhaseManager::is_requested() const {
assert_ConcurrentGC_thread();
MonitorLockerEx ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
assert_manager_is_tos(this, _stack, "This");
return _active && (_stack->_requested_phase == _phase);
}
bool ConcurrentGCPhaseManager::wait_when_requested_impl() const {
assert_ConcurrentGC_thread();
assert_lock_strong(CGCPhaseManager_lock);
bool waited = false;
while (_active && (_stack->_requested_phase == _phase)) {
waited = true;
CGCPhaseManager_lock->wait(Mutex::_no_safepoint_check_flag);
}
return waited;
}
bool ConcurrentGCPhaseManager::wait_when_requested() const {
assert_ConcurrentGC_thread();
MonitorLockerEx ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
assert_manager_is_tos(this, _stack, "This");
return wait_when_requested_impl();
}
void ConcurrentGCPhaseManager::set_phase(int phase, bool force) {
assert_ConcurrentGC_thread();
assert_not_enter_unconstrained(phase);
MonitorLockerEx ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
assert_manager_is_tos(this, _stack, "This");
if (!force) wait_when_requested_impl();
_phase = phase;
ml.notify_all();
}
void ConcurrentGCPhaseManager::deactivate() {
assert_ConcurrentGC_thread();
MonitorLockerEx ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
assert_manager_is_tos(this, _stack, "This");
_active = false;
ml.notify_all();
}
bool ConcurrentGCPhaseManager::wait_for_phase(int phase, Stack* stack) {
assert(Thread::current()->is_Java_thread(), "precondition");
assert(stack != NULL, "precondition");
MonitorLockerEx ml(CGCPhaseManager_lock);
// Update request and notify service of change.
if (stack->_requested_phase != phase) {
stack->_requested_phase = phase;
ml.notify_all();
}
if (phase == UNCONSTRAINED_PHASE) {
return true;
}
// Wait until phase or IDLE is active.
while (true) {
bool idle = false;
for (ConcurrentGCPhaseManager* manager = stack->_top;
manager != NULL;
manager = manager->_prev) {
if (manager->_phase == phase) {
return true; // phase is active.
} else if (manager->_phase == IDLE_PHASE) {
idle = true; // Note idle active, continue search for phase.
}
}
if (idle) {
return false; // idle is active and phase is not.
} else {
ml.wait(); // Wait for phase change.
}
}
}