--- /dev/null 2017-02-06 22:16:02.409658130 -0500 +++ new/src/share/vm/gc/shared/concurrentGCPhaseManager.cpp 2017-02-17 20:09:49.330238562 -0500 @@ -0,0 +1,163 @@ +/* + * 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. + } + } +}