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 #ifndef SHARE_VM_GC_IMPLEMENTATION_G1_BUFFERINGOOPCLOSURE_HPP
26 #define SHARE_VM_GC_IMPLEMENTATION_G1_BUFFERINGOOPCLOSURE_HPP
28 #include "memory/genOopClosures.hpp"
29 #include "memory/generation.hpp"
30 #include "runtime/os.hpp"
31 #include "utilities/taskqueue.hpp"
33 // A BufferingOops closure tries to separate out the cost of finding roots
34 // from the cost of applying closures to them. It maintains an array of
35 // ref-containing locations. Until the array is full, applying the closure
36 // to an oop* merely records that location in the array. Since this
37 // closure app cost is small, an elapsed timer can approximately attribute
38 // all of this cost to the cost of finding the roots. When the array fills
39 // up, the wrapped closure is applied to all elements, keeping track of
40 // this elapsed time of this process, and leaving the array empty.
41 // The caller must be sure to call "done" to process any unprocessed
42 // buffered entriess.
44 class Generation;
45 class HeapRegion;
47 class BufferingOopClosure: public OopClosure {
48 protected:
49 enum PrivateConstants {
50 BufferLength = 1024
51 };
53 StarTask _buffer[BufferLength];
54 StarTask* _buffer_top;
55 StarTask* _buffer_curr;
57 OopClosure* _oc;
58 double _closure_app_seconds;
60 void process_buffer () {
61 double start = os::elapsedTime();
62 for (StarTask* curr = _buffer; curr < _buffer_curr; ++curr) {
63 if (curr->is_narrow()) {
64 assert(UseCompressedOops, "Error");
65 _oc->do_oop((narrowOop*)(*curr));
66 } else {
67 _oc->do_oop((oop*)(*curr));
68 }
69 }
70 _buffer_curr = _buffer;
71 _closure_app_seconds += (os::elapsedTime() - start);
72 }
74 template <class T> inline void do_oop_work(T* p) {
75 if (_buffer_curr == _buffer_top) {
76 process_buffer();
77 }
78 StarTask new_ref(p);
79 *_buffer_curr = new_ref;
80 ++_buffer_curr;
81 }
83 public:
84 virtual void do_oop(narrowOop* p) { do_oop_work(p); }
85 virtual void do_oop(oop* p) { do_oop_work(p); }
87 void done () {
88 if (_buffer_curr > _buffer) {
89 process_buffer();
90 }
91 }
92 double closure_app_seconds () {
93 return _closure_app_seconds;
94 }
95 BufferingOopClosure (OopClosure *oc) :
96 _oc(oc),
97 _buffer_curr(_buffer), _buffer_top(_buffer + BufferLength),
98 _closure_app_seconds(0.0) { }
99 };
101 class BufferingOopsInGenClosure: public OopsInGenClosure {
102 BufferingOopClosure _boc;
103 OopsInGenClosure* _oc;
104 protected:
105 template <class T> inline void do_oop_work(T* p) {
106 assert(generation()->is_in_reserved((void*)p), "Must be in!");
107 _boc.do_oop(p);
108 }
109 public:
110 BufferingOopsInGenClosure(OopsInGenClosure *oc) :
111 _boc(oc), _oc(oc) {}
113 virtual void do_oop(narrowOop* p) { do_oop_work(p); }
114 virtual void do_oop(oop* p) { do_oop_work(p); }
116 void done() {
117 _boc.done();
118 }
120 double closure_app_seconds () {
121 return _boc.closure_app_seconds();
122 }
124 void set_generation(Generation* gen) {
125 OopsInGenClosure::set_generation(gen);
126 _oc->set_generation(gen);
127 }
129 void reset_generation() {
130 // Make sure we finish the current work with the current generation.
131 _boc.done();
132 OopsInGenClosure::reset_generation();
133 _oc->reset_generation();
134 }
136 };
139 class BufferingOopsInHeapRegionClosure: public OopsInHeapRegionClosure {
140 private:
141 enum PrivateConstants {
142 BufferLength = 1024
143 };
145 StarTask _buffer[BufferLength];
146 StarTask* _buffer_top;
147 StarTask* _buffer_curr;
149 HeapRegion* _hr_buffer[BufferLength];
150 HeapRegion** _hr_curr;
152 OopsInHeapRegionClosure* _oc;
153 double _closure_app_seconds;
155 void process_buffer () {
157 assert((_hr_curr - _hr_buffer) == (_buffer_curr - _buffer),
158 "the two lengths should be the same");
160 double start = os::elapsedTime();
161 HeapRegion** hr_curr = _hr_buffer;
162 HeapRegion* hr_prev = NULL;
163 for (StarTask* curr = _buffer; curr < _buffer_curr; ++curr) {
164 HeapRegion* region = *hr_curr;
165 if (region != hr_prev) {
166 _oc->set_region(region);
167 hr_prev = region;
168 }
169 if (curr->is_narrow()) {
170 assert(UseCompressedOops, "Error");
171 _oc->do_oop((narrowOop*)(*curr));
172 } else {
173 _oc->do_oop((oop*)(*curr));
174 }
175 ++hr_curr;
176 }
177 _buffer_curr = _buffer;
178 _hr_curr = _hr_buffer;
179 _closure_app_seconds += (os::elapsedTime() - start);
180 }
182 public:
183 virtual void do_oop(narrowOop* p) { do_oop_work(p); }
184 virtual void do_oop( oop* p) { do_oop_work(p); }
186 template <class T> void do_oop_work(T* p) {
187 if (_buffer_curr == _buffer_top) {
188 assert(_hr_curr > _hr_buffer, "_hr_curr should be consistent with _buffer_curr");
189 process_buffer();
190 }
191 StarTask new_ref(p);
192 *_buffer_curr = new_ref;
193 ++_buffer_curr;
194 *_hr_curr = _from;
195 ++_hr_curr;
196 }
197 void done () {
198 if (_buffer_curr > _buffer) {
199 assert(_hr_curr > _hr_buffer, "_hr_curr should be consistent with _buffer_curr");
200 process_buffer();
201 }
202 }
203 double closure_app_seconds () {
204 return _closure_app_seconds;
205 }
206 BufferingOopsInHeapRegionClosure (OopsInHeapRegionClosure *oc) :
207 _oc(oc),
208 _buffer_curr(_buffer), _buffer_top(_buffer + BufferLength),
209 _hr_curr(_hr_buffer),
210 _closure_app_seconds(0.0) { }
211 };
213 #endif // SHARE_VM_GC_IMPLEMENTATION_G1_BUFFERINGOOPCLOSURE_HPP