Mercurial > hg > graal-jvmci-8
annotate src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp @ 795:215f81b4d9b3
6841831: G1: assert(contains_reference(from),"We just added it!") fires
Summary: During parallel rset updating we have to make sure that the worker ids of the refinement threads do not intersect with the worker ids that can be claimed by the mutator threads.
Reviewed-by: tonyp
author | iveresov |
---|---|
date | Mon, 18 May 2009 11:52:46 -0700 |
parents | 315a5d70b295 |
children | bd02caa94611 27f6a9b9c311 |
rev | line source |
---|---|
342 | 1 /* |
470 | 2 * Copyright 2001-2008 Sun Microsystems, Inc. All Rights Reserved. |
342 | 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, | |
20 * CA 95054 USA or visit www.sun.com if you need additional information or | |
21 * have any questions. | |
22 * | |
23 */ | |
24 | |
25 # include "incls/_precompiled.incl" | |
26 # include "incls/_dirtyCardQueue.cpp.incl" | |
27 | |
28 bool DirtyCardQueue::apply_closure(CardTableEntryClosure* cl, | |
29 bool consume, | |
30 size_t worker_i) { | |
31 bool res = true; | |
32 if (_buf != NULL) { | |
33 res = apply_closure_to_buffer(cl, _buf, _index, _sz, | |
34 consume, | |
35 (int) worker_i); | |
36 if (res && consume) _index = _sz; | |
37 } | |
38 return res; | |
39 } | |
40 | |
41 bool DirtyCardQueue::apply_closure_to_buffer(CardTableEntryClosure* cl, | |
42 void** buf, | |
43 size_t index, size_t sz, | |
44 bool consume, | |
45 int worker_i) { | |
46 if (cl == NULL) return true; | |
47 for (size_t i = index; i < sz; i += oopSize) { | |
48 int ind = byte_index_to_index((int)i); | |
49 jbyte* card_ptr = (jbyte*)buf[ind]; | |
50 if (card_ptr != NULL) { | |
51 // Set the entry to null, so we don't do it again (via the test | |
52 // above) if we reconsider this buffer. | |
53 if (consume) buf[ind] = NULL; | |
54 if (!cl->do_card_ptr(card_ptr, worker_i)) return false; | |
55 } | |
56 } | |
57 return true; | |
58 } | |
59 | |
60 #ifdef _MSC_VER // the use of 'this' below gets a warning, make it go away | |
61 #pragma warning( disable:4355 ) // 'this' : used in base member initializer list | |
62 #endif // _MSC_VER | |
63 | |
64 DirtyCardQueueSet::DirtyCardQueueSet() : | |
65 PtrQueueSet(true /*notify_when_complete*/), | |
66 _closure(NULL), | |
67 _shared_dirty_card_queue(this, true /*perm*/), | |
68 _free_ids(NULL), | |
69 _processed_buffers_mut(0), _processed_buffers_rs_thread(0) | |
70 { | |
71 _all_active = true; | |
72 } | |
73 | |
795
215f81b4d9b3
6841831: G1: assert(contains_reference(from),"We just added it!") fires
iveresov
parents:
794
diff
changeset
|
74 // Determines how many mutator threads can process the buffers in parallel. |
342 | 75 size_t DirtyCardQueueSet::num_par_ids() { |
795
215f81b4d9b3
6841831: G1: assert(contains_reference(from),"We just added it!") fires
iveresov
parents:
794
diff
changeset
|
76 return os::processor_count(); |
342 | 77 } |
78 | |
79 void DirtyCardQueueSet::initialize(Monitor* cbl_mon, Mutex* fl_lock, | |
80 int max_completed_queue, | |
616
4f360ec815ba
6720309: G1: don't synchronously update RSet during evacuation pauses
iveresov
parents:
470
diff
changeset
|
81 Mutex* lock, PtrQueueSet* fl_owner) { |
4f360ec815ba
6720309: G1: don't synchronously update RSet during evacuation pauses
iveresov
parents:
470
diff
changeset
|
82 PtrQueueSet::initialize(cbl_mon, fl_lock, max_completed_queue, fl_owner); |
342 | 83 set_buffer_size(DCQBarrierQueueBufferSize); |
84 set_process_completed_threshold(DCQBarrierProcessCompletedThreshold); | |
85 | |
86 _shared_dirty_card_queue.set_lock(lock); | |
87 _free_ids = new FreeIdSet((int) num_par_ids(), _cbl_mon); | |
88 } | |
89 | |
90 void DirtyCardQueueSet::handle_zero_index_for_thread(JavaThread* t) { | |
91 t->dirty_card_queue().handle_zero_index(); | |
92 } | |
93 | |
94 void DirtyCardQueueSet::set_closure(CardTableEntryClosure* closure) { | |
95 _closure = closure; | |
96 } | |
97 | |
98 void DirtyCardQueueSet::iterate_closure_all_threads(bool consume, | |
99 size_t worker_i) { | |
100 assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); | |
101 for(JavaThread* t = Threads::first(); t; t = t->next()) { | |
102 bool b = t->dirty_card_queue().apply_closure(_closure, consume); | |
103 guarantee(b, "Should not be interrupted."); | |
104 } | |
105 bool b = shared_dirty_card_queue()->apply_closure(_closure, | |
106 consume, | |
107 worker_i); | |
108 guarantee(b, "Should not be interrupted."); | |
109 } | |
110 | |
111 bool DirtyCardQueueSet::mut_process_buffer(void** buf) { | |
112 | |
113 // Used to determine if we had already claimed a par_id | |
114 // before entering this method. | |
115 bool already_claimed = false; | |
116 | |
117 // We grab the current JavaThread. | |
118 JavaThread* thread = JavaThread::current(); | |
119 | |
120 // We get the the number of any par_id that this thread | |
121 // might have already claimed. | |
122 int worker_i = thread->get_claimed_par_id(); | |
123 | |
124 // If worker_i is not -1 then the thread has already claimed | |
125 // a par_id. We make note of it using the already_claimed value | |
126 if (worker_i != -1) { | |
127 already_claimed = true; | |
128 } else { | |
129 | |
130 // Otherwise we need to claim a par id | |
131 worker_i = _free_ids->claim_par_id(); | |
132 | |
133 // And store the par_id value in the thread | |
134 thread->set_claimed_par_id(worker_i); | |
135 } | |
136 | |
137 bool b = false; | |
138 if (worker_i != -1) { | |
139 b = DirtyCardQueue::apply_closure_to_buffer(_closure, buf, 0, | |
140 _sz, true, worker_i); | |
141 if (b) Atomic::inc(&_processed_buffers_mut); | |
142 | |
143 // If we had not claimed an id before entering the method | |
144 // then we must release the id. | |
145 if (!already_claimed) { | |
146 | |
147 // we release the id | |
148 _free_ids->release_par_id(worker_i); | |
149 | |
150 // and set the claimed_id in the thread to -1 | |
151 thread->set_claimed_par_id(-1); | |
152 } | |
153 } | |
154 return b; | |
155 } | |
156 | |
157 DirtyCardQueueSet::CompletedBufferNode* | |
158 DirtyCardQueueSet::get_completed_buffer_lock(int stop_at) { | |
159 CompletedBufferNode* nd = NULL; | |
160 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); | |
161 | |
162 if ((int)_n_completed_buffers <= stop_at) { | |
163 _process_completed = false; | |
164 return NULL; | |
165 } | |
166 | |
167 if (_completed_buffers_head != NULL) { | |
168 nd = _completed_buffers_head; | |
169 _completed_buffers_head = nd->next; | |
170 if (_completed_buffers_head == NULL) | |
171 _completed_buffers_tail = NULL; | |
172 _n_completed_buffers--; | |
173 } | |
174 debug_only(assert_completed_buffer_list_len_correct_locked()); | |
175 return nd; | |
176 } | |
177 | |
178 // We only do this in contexts where there is no concurrent enqueueing. | |
179 DirtyCardQueueSet::CompletedBufferNode* | |
180 DirtyCardQueueSet::get_completed_buffer_CAS() { | |
181 CompletedBufferNode* nd = _completed_buffers_head; | |
182 | |
183 while (nd != NULL) { | |
184 CompletedBufferNode* next = nd->next; | |
185 CompletedBufferNode* result = | |
186 (CompletedBufferNode*)Atomic::cmpxchg_ptr(next, | |
187 &_completed_buffers_head, | |
188 nd); | |
189 if (result == nd) { | |
190 return result; | |
191 } else { | |
192 nd = _completed_buffers_head; | |
193 } | |
194 } | |
195 assert(_completed_buffers_head == NULL, "Loop post"); | |
196 _completed_buffers_tail = NULL; | |
197 return NULL; | |
198 } | |
199 | |
200 bool DirtyCardQueueSet:: | |
201 apply_closure_to_completed_buffer_helper(int worker_i, | |
202 CompletedBufferNode* nd) { | |
203 if (nd != NULL) { | |
204 bool b = | |
205 DirtyCardQueue::apply_closure_to_buffer(_closure, nd->buf, | |
206 nd->index, _sz, | |
207 true, worker_i); | |
208 void** buf = nd->buf; | |
364 | 209 size_t index = nd->index; |
342 | 210 delete nd; |
211 if (b) { | |
212 deallocate_buffer(buf); | |
213 return true; // In normal case, go on to next buffer. | |
214 } else { | |
364 | 215 enqueue_complete_buffer(buf, index, true); |
342 | 216 return false; |
217 } | |
218 } else { | |
219 return false; | |
220 } | |
221 } | |
222 | |
223 bool DirtyCardQueueSet::apply_closure_to_completed_buffer(int worker_i, | |
224 int stop_at, | |
225 bool with_CAS) | |
226 { | |
227 CompletedBufferNode* nd = NULL; | |
228 if (with_CAS) { | |
229 guarantee(stop_at == 0, "Precondition"); | |
230 nd = get_completed_buffer_CAS(); | |
231 } else { | |
232 nd = get_completed_buffer_lock(stop_at); | |
233 } | |
234 bool res = apply_closure_to_completed_buffer_helper(worker_i, nd); | |
794 | 235 if (res) Atomic::inc(&_processed_buffers_rs_thread); |
342 | 236 return res; |
237 } | |
238 | |
239 void DirtyCardQueueSet::apply_closure_to_all_completed_buffers() { | |
240 CompletedBufferNode* nd = _completed_buffers_head; | |
241 while (nd != NULL) { | |
242 bool b = | |
243 DirtyCardQueue::apply_closure_to_buffer(_closure, nd->buf, 0, _sz, | |
244 false); | |
245 guarantee(b, "Should not stop early."); | |
246 nd = nd->next; | |
247 } | |
248 } | |
249 | |
250 void DirtyCardQueueSet::abandon_logs() { | |
251 assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); | |
252 CompletedBufferNode* buffers_to_delete = NULL; | |
253 { | |
254 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); | |
255 while (_completed_buffers_head != NULL) { | |
256 CompletedBufferNode* nd = _completed_buffers_head; | |
257 _completed_buffers_head = nd->next; | |
258 nd->next = buffers_to_delete; | |
259 buffers_to_delete = nd; | |
260 } | |
261 _n_completed_buffers = 0; | |
262 _completed_buffers_tail = NULL; | |
263 debug_only(assert_completed_buffer_list_len_correct_locked()); | |
264 } | |
265 while (buffers_to_delete != NULL) { | |
266 CompletedBufferNode* nd = buffers_to_delete; | |
267 buffers_to_delete = nd->next; | |
268 deallocate_buffer(nd->buf); | |
269 delete nd; | |
270 } | |
271 // Since abandon is done only at safepoints, we can safely manipulate | |
272 // these queues. | |
273 for (JavaThread* t = Threads::first(); t; t = t->next()) { | |
274 t->dirty_card_queue().reset(); | |
275 } | |
276 shared_dirty_card_queue()->reset(); | |
277 } | |
278 | |
279 | |
280 void DirtyCardQueueSet::concatenate_logs() { | |
281 // Iterate over all the threads, if we find a partial log add it to | |
282 // the global list of logs. Temporarily turn off the limit on the number | |
283 // of outstanding buffers. | |
284 int save_max_completed_queue = _max_completed_queue; | |
285 _max_completed_queue = max_jint; | |
286 assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint."); | |
287 for (JavaThread* t = Threads::first(); t; t = t->next()) { | |
288 DirtyCardQueue& dcq = t->dirty_card_queue(); | |
289 if (dcq.size() != 0) { | |
290 void **buf = t->dirty_card_queue().get_buf(); | |
291 // We must NULL out the unused entries, then enqueue. | |
292 for (size_t i = 0; i < t->dirty_card_queue().get_index(); i += oopSize) { | |
293 buf[PtrQueue::byte_index_to_index((int)i)] = NULL; | |
294 } | |
295 enqueue_complete_buffer(dcq.get_buf(), dcq.get_index()); | |
296 dcq.reinitialize(); | |
297 } | |
298 } | |
299 if (_shared_dirty_card_queue.size() != 0) { | |
300 enqueue_complete_buffer(_shared_dirty_card_queue.get_buf(), | |
301 _shared_dirty_card_queue.get_index()); | |
302 _shared_dirty_card_queue.reinitialize(); | |
303 } | |
304 // Restore the completed buffer queue limit. | |
305 _max_completed_queue = save_max_completed_queue; | |
306 } |