/* * 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), kind " manager is not top of stack") ConcurrentGCPhaseManager::ConcurrentGCPhaseManager(int phase, ConcurrentGCPhaseManager** stack, int* request) : _phase(phase), _active(true), _request(request), _link(NULL), _stack(stack) { assert_ConcurrentGC_thread(); assert_not_enter_unconstrained(phase); assert(stack != NULL, "NULL stack pointer"); assert(request != NULL, "NULL request pointer"); MonitorLockerEx ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag); assert(*stack == NULL, "Non-empty stack"); *stack = this; ml.notify_all(); } ConcurrentGCPhaseManager::ConcurrentGCPhaseManager(int phase, ConcurrentGCPhaseManager* prev) : _phase(phase), _active(true), _request(NULL), _link(prev), _stack(NULL) { assert_ConcurrentGC_thread(); assert_not_enter_unconstrained(phase); assert(prev != NULL, "NULL previous stack entry"); MonitorLockerEx ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag); assert_manager_is_tos(prev, prev->_stack, "Previous"); assert(prev->_active, "Previous manager is inactive"); _stack = prev->_stack; _request = prev->_request; *_stack = 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 = _link; 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 && (*_request == _phase); } bool ConcurrentGCPhaseManager::wait_when_requested_impl() const { assert_ConcurrentGC_thread(); assert_lock_strong(CGCPhaseManager_lock); bool waited = false; while (_active && (*_request == _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, ConcurrentGCPhaseManager** stack, int* request) { assert(Thread::current()->is_Java_thread(), "precondition"); MonitorLockerEx ml(CGCPhaseManager_lock); // Update request and notify service of change. if (*request != phase) { *request = 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; manager != NULL; manager = manager->_link) { 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. } } }