Mon, 12 Mar 2012 14:59:00 -0700
7147724: G1: hang in SurrogateLockerThread::manipulatePLL
Summary: Attempting to initiate a marking cycle when allocating a humongous object can, if a marking cycle is successfully initiated by another thread, result in the allocating thread spinning until the marking cycle is complete. Eliminate a deadlock between the main ConcurrentMarkThread, the SurrogateLocker thread, the VM thread, and a mutator thread waiting on the SecondaryFreeList_lock (while free regions are going to become available) by not manipulating the pending list lock during the prologue and epilogue of the cleanup pause.
Reviewed-by: brutisso, jcoomes, tonyp
1 /*
2 * Copyright (c) 2001, 2010, 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 */
25 #include "precompiled.hpp"
26 #include "gc_implementation/g1/concurrentG1Refine.hpp"
27 #include "gc_implementation/g1/concurrentG1RefineThread.hpp"
28 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
29 #include "gc_implementation/g1/g1CollectorPolicy.hpp"
30 #include "memory/resourceArea.hpp"
31 #include "runtime/handles.inline.hpp"
32 #include "runtime/mutexLocker.hpp"
34 ConcurrentG1RefineThread::
35 ConcurrentG1RefineThread(ConcurrentG1Refine* cg1r, ConcurrentG1RefineThread *next,
36 int worker_id_offset, int worker_id) :
37 ConcurrentGCThread(),
38 _worker_id_offset(worker_id_offset),
39 _worker_id(worker_id),
40 _active(false),
41 _next(next),
42 _monitor(NULL),
43 _cg1r(cg1r),
44 _vtime_accum(0.0)
45 {
47 // Each thread has its own monitor. The i-th thread is responsible for signalling
48 // to thread i+1 if the number of buffers in the queue exceeds a threashold for this
49 // thread. Monitors are also used to wake up the threads during termination.
50 // The 0th worker in notified by mutator threads and has a special monitor.
51 // The last worker is used for young gen rset size sampling.
52 if (worker_id > 0) {
53 _monitor = new Monitor(Mutex::nonleaf, "Refinement monitor", true);
54 } else {
55 _monitor = DirtyCardQ_CBL_mon;
56 }
57 initialize();
58 create_and_start();
59 }
61 void ConcurrentG1RefineThread::initialize() {
62 if (_worker_id < cg1r()->worker_thread_num()) {
63 // Current thread activation threshold
64 _threshold = MIN2<int>(cg1r()->thread_threshold_step() * (_worker_id + 1) + cg1r()->green_zone(),
65 cg1r()->yellow_zone());
66 // A thread deactivates once the number of buffer reached a deactivation threshold
67 _deactivation_threshold = MAX2<int>(_threshold - cg1r()->thread_threshold_step(), cg1r()->green_zone());
68 } else {
69 set_active(true);
70 }
71 }
73 void ConcurrentG1RefineThread::sample_young_list_rs_lengths() {
74 G1CollectedHeap* g1h = G1CollectedHeap::heap();
75 G1CollectorPolicy* g1p = g1h->g1_policy();
76 if (g1p->adaptive_young_list_length()) {
77 int regions_visited = 0;
78 g1h->young_list()->rs_length_sampling_init();
79 while (g1h->young_list()->rs_length_sampling_more()) {
80 g1h->young_list()->rs_length_sampling_next();
81 ++regions_visited;
83 // we try to yield every time we visit 10 regions
84 if (regions_visited == 10) {
85 if (_sts.should_yield()) {
86 _sts.yield("G1 refine");
87 // we just abandon the iteration
88 break;
89 }
90 regions_visited = 0;
91 }
92 }
94 g1p->revise_young_list_target_length_if_necessary();
95 }
96 }
98 void ConcurrentG1RefineThread::run_young_rs_sampling() {
99 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
100 _vtime_start = os::elapsedVTime();
101 while(!_should_terminate) {
102 _sts.join();
103 sample_young_list_rs_lengths();
104 _sts.leave();
106 if (os::supports_vtime()) {
107 _vtime_accum = (os::elapsedVTime() - _vtime_start);
108 } else {
109 _vtime_accum = 0.0;
110 }
112 MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
113 if (_should_terminate) {
114 break;
115 }
116 _monitor->wait(Mutex::_no_safepoint_check_flag, G1ConcRefinementServiceIntervalMillis);
117 }
118 }
120 void ConcurrentG1RefineThread::wait_for_completed_buffers() {
121 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
122 MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
123 while (!_should_terminate && !is_active()) {
124 _monitor->wait(Mutex::_no_safepoint_check_flag);
125 }
126 }
128 bool ConcurrentG1RefineThread::is_active() {
129 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
130 return _worker_id > 0 ? _active : dcqs.process_completed_buffers();
131 }
133 void ConcurrentG1RefineThread::activate() {
134 MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
135 if (_worker_id > 0) {
136 if (G1TraceConcRefinement) {
137 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
138 gclog_or_tty->print_cr("G1-Refine-activated worker %d, on threshold %d, current %d",
139 _worker_id, _threshold, (int)dcqs.completed_buffers_num());
140 }
141 set_active(true);
142 } else {
143 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
144 dcqs.set_process_completed(true);
145 }
146 _monitor->notify();
147 }
149 void ConcurrentG1RefineThread::deactivate() {
150 MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
151 if (_worker_id > 0) {
152 if (G1TraceConcRefinement) {
153 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
154 gclog_or_tty->print_cr("G1-Refine-deactivated worker %d, off threshold %d, current %d",
155 _worker_id, _deactivation_threshold, (int)dcqs.completed_buffers_num());
156 }
157 set_active(false);
158 } else {
159 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
160 dcqs.set_process_completed(false);
161 }
162 }
164 void ConcurrentG1RefineThread::run() {
165 initialize_in_thread();
166 wait_for_universe_init();
168 if (_worker_id >= cg1r()->worker_thread_num()) {
169 run_young_rs_sampling();
170 terminate();
171 return;
172 }
174 _vtime_start = os::elapsedVTime();
175 while (!_should_terminate) {
176 DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set();
178 // Wait for work
179 wait_for_completed_buffers();
181 if (_should_terminate) {
182 break;
183 }
185 _sts.join();
187 do {
188 int curr_buffer_num = (int)dcqs.completed_buffers_num();
189 // If the number of the buffers falls down into the yellow zone,
190 // that means that the transition period after the evacuation pause has ended.
191 if (dcqs.completed_queue_padding() > 0 && curr_buffer_num <= cg1r()->yellow_zone()) {
192 dcqs.set_completed_queue_padding(0);
193 }
195 if (_worker_id > 0 && curr_buffer_num <= _deactivation_threshold) {
196 // If the number of the buffer has fallen below our threshold
197 // we should deactivate. The predecessor will reactivate this
198 // thread should the number of the buffers cross the threshold again.
199 deactivate();
200 break;
201 }
203 // Check if we need to activate the next thread.
204 if (_next != NULL && !_next->is_active() && curr_buffer_num > _next->_threshold) {
205 _next->activate();
206 }
207 } while (dcqs.apply_closure_to_completed_buffer(_worker_id + _worker_id_offset, cg1r()->green_zone()));
209 // We can exit the loop above while being active if there was a yield request.
210 if (is_active()) {
211 deactivate();
212 }
214 _sts.leave();
216 if (os::supports_vtime()) {
217 _vtime_accum = (os::elapsedVTime() - _vtime_start);
218 } else {
219 _vtime_accum = 0.0;
220 }
221 }
222 assert(_should_terminate, "just checking");
223 terminate();
224 }
227 void ConcurrentG1RefineThread::yield() {
228 if (G1TraceConcRefinement) {
229 gclog_or_tty->print_cr("G1-Refine-yield");
230 }
231 _sts.yield("G1 refine");
232 if (G1TraceConcRefinement) {
233 gclog_or_tty->print_cr("G1-Refine-yield-end");
234 }
235 }
237 void ConcurrentG1RefineThread::stop() {
238 // it is ok to take late safepoints here, if needed
239 {
240 MutexLockerEx mu(Terminator_lock);
241 _should_terminate = true;
242 }
244 {
245 MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag);
246 _monitor->notify();
247 }
249 {
250 MutexLockerEx mu(Terminator_lock);
251 while (!_has_terminated) {
252 Terminator_lock->wait();
253 }
254 }
255 if (G1TraceConcRefinement) {
256 gclog_or_tty->print_cr("G1-Refine-stop");
257 }
258 }
260 void ConcurrentG1RefineThread::print() const {
261 print_on(tty);
262 }
264 void ConcurrentG1RefineThread::print_on(outputStream* st) const {
265 st->print("\"G1 Concurrent Refinement Thread#%d\" ", _worker_id);
266 Thread::print_on(st);
267 st->cr();
268 }