1/*
2 * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#include "precompiled.hpp"
26#include "gc/shared/concurrentGCPhaseManager.hpp"
27#include "runtime/mutexLocker.hpp"
28#include "runtime/thread.hpp"
29
30#define assert_ConcurrentGC_thread() \
31 assert(Thread::current()->is_ConcurrentGC_thread(), "precondition")
32
33#define assert_not_enter_unconstrained(phase) \
34 assert((phase) != UNCONSTRAINED_PHASE, "Cannot enter \"unconstrained\" phase")
35
36#define assert_manager_is_tos(manager, stack, kind) \
37 assert((manager) == (stack)->_top, kind " manager is not top of stack")
38
39ConcurrentGCPhaseManager::Stack::Stack() :
40 _requested_phase(UNCONSTRAINED_PHASE),
41 _top(NULL)
42{ }
43
44ConcurrentGCPhaseManager::ConcurrentGCPhaseManager(int phase, Stack* stack) :
45 _phase(phase),
46 _active(true),
47 _prev(NULL),
48 _stack(stack)
49{
50 assert_ConcurrentGC_thread();
51 assert_not_enter_unconstrained(phase);
52 assert(stack != NULL, "precondition");
53 MonitorLocker ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
54 if (stack->_top != NULL) {
55 assert(stack->_top->_active, "precondition");
56 _prev = stack->_top;
57 }
58 stack->_top = this;
59 ml.notify_all();
60}
61
62ConcurrentGCPhaseManager::~ConcurrentGCPhaseManager() {
63 assert_ConcurrentGC_thread();
64 MonitorLocker ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
65 assert_manager_is_tos(this, _stack, "This");
66 wait_when_requested_impl();
67 _stack->_top = _prev;
68 ml.notify_all();
69}
70
71bool ConcurrentGCPhaseManager::is_requested() const {
72 assert_ConcurrentGC_thread();
73 MonitorLocker ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
74 assert_manager_is_tos(this, _stack, "This");
75 return _active && (_stack->_requested_phase == _phase);
76}
77
78bool ConcurrentGCPhaseManager::wait_when_requested_impl() const {
79 assert_ConcurrentGC_thread();
80 assert_lock_strong(CGCPhaseManager_lock);
81 bool waited = false;
82 while (_active && (_stack->_requested_phase == _phase)) {
83 waited = true;
84 CGCPhaseManager_lock->wait_without_safepoint_check();
85 }
86 return waited;
87}
88
89bool ConcurrentGCPhaseManager::wait_when_requested() const {
90 assert_ConcurrentGC_thread();
91 MonitorLocker ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
92 assert_manager_is_tos(this, _stack, "This");
93 return wait_when_requested_impl();
94}
95
96void ConcurrentGCPhaseManager::set_phase(int phase, bool force) {
97 assert_ConcurrentGC_thread();
98 assert_not_enter_unconstrained(phase);
99 MonitorLocker ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
100 assert_manager_is_tos(this, _stack, "This");
101 if (!force) wait_when_requested_impl();
102 _phase = phase;
103 ml.notify_all();
104}
105
106void ConcurrentGCPhaseManager::deactivate() {
107 assert_ConcurrentGC_thread();
108 MonitorLocker ml(CGCPhaseManager_lock, Mutex::_no_safepoint_check_flag);
109 assert_manager_is_tos(this, _stack, "This");
110 _active = false;
111 ml.notify_all();
112}
113
114bool ConcurrentGCPhaseManager::wait_for_phase(int phase, Stack* stack) {
115 assert(Thread::current()->is_Java_thread(), "precondition");
116 assert(stack != NULL, "precondition");
117 MonitorLocker ml(CGCPhaseManager_lock);
118 // Update request and notify service of change.
119 if (stack->_requested_phase != phase) {
120 stack->_requested_phase = phase;
121 ml.notify_all();
122 }
123
124 if (phase == UNCONSTRAINED_PHASE) {
125 return true;
126 }
127
128 // Wait until phase or IDLE is active.
129 while (true) {
130 bool idle = false;
131 for (ConcurrentGCPhaseManager* manager = stack->_top;
132 manager != NULL;
133 manager = manager->_prev) {
134 if (manager->_phase == phase) {
135 return true; // phase is active.
136 } else if (manager->_phase == IDLE_PHASE) {
137 idle = true; // Note idle active, continue search for phase.
138 }
139 }
140 if (idle) {
141 return false; // idle is active and phase is not.
142 } else {
143 ml.wait(); // Wait for phase change.
144 }
145 }
146}
147