| /* |
| * 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. |
| } |
| } |
| } |