Sat, 06 Oct 2012 01:17:44 -0700
7127708: G1: change task num types from int to uint in concurrent mark
Summary: Change the type of various task num fields, parameters etc to unsigned and rename them to be more consistent with the other collectors. Code changes were also reviewed by Vitaly Davidovich.
Reviewed-by: johnc
Contributed-by: Kaushik Srenevasan <kaushik@twitter.com>
1 /*
2 * Copyright (c) 2001, 2011, 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/ptrQueue.hpp"
27 #include "memory/allocation.hpp"
28 #include "memory/allocation.inline.hpp"
29 #include "runtime/mutex.hpp"
30 #include "runtime/mutexLocker.hpp"
31 #ifdef TARGET_OS_FAMILY_linux
32 # include "thread_linux.inline.hpp"
33 #endif
34 #ifdef TARGET_OS_FAMILY_solaris
35 # include "thread_solaris.inline.hpp"
36 #endif
37 #ifdef TARGET_OS_FAMILY_windows
38 # include "thread_windows.inline.hpp"
39 #endif
40 #ifdef TARGET_OS_FAMILY_bsd
41 # include "thread_bsd.inline.hpp"
42 #endif
44 PtrQueue::PtrQueue(PtrQueueSet* qset, bool perm, bool active) :
45 _qset(qset), _buf(NULL), _index(0), _active(active),
46 _perm(perm), _lock(NULL)
47 {}
49 void PtrQueue::flush() {
50 if (!_perm && _buf != NULL) {
51 if (_index == _sz) {
52 // No work to do.
53 qset()->deallocate_buffer(_buf);
54 } else {
55 // We must NULL out the unused entries, then enqueue.
56 for (size_t i = 0; i < _index; i += oopSize) {
57 _buf[byte_index_to_index((int)i)] = NULL;
58 }
59 qset()->enqueue_complete_buffer(_buf);
60 }
61 _buf = NULL;
62 _index = 0;
63 }
64 }
67 static int byte_index_to_index(int ind) {
68 assert((ind % oopSize) == 0, "Invariant.");
69 return ind / oopSize;
70 }
72 static int index_to_byte_index(int byte_ind) {
73 return byte_ind * oopSize;
74 }
76 void PtrQueue::enqueue_known_active(void* ptr) {
77 assert(0 <= _index && _index <= _sz, "Invariant.");
78 assert(_index == 0 || _buf != NULL, "invariant");
80 while (_index == 0) {
81 handle_zero_index();
82 }
84 assert(_index > 0, "postcondition");
85 _index -= oopSize;
86 _buf[byte_index_to_index((int)_index)] = ptr;
87 assert(0 <= _index && _index <= _sz, "Invariant.");
88 }
90 void PtrQueue::locking_enqueue_completed_buffer(void** buf) {
91 assert(_lock->owned_by_self(), "Required.");
93 // We have to unlock _lock (which may be Shared_DirtyCardQ_lock) before
94 // we acquire DirtyCardQ_CBL_mon inside enqeue_complete_buffer as they
95 // have the same rank and we may get the "possible deadlock" message
96 _lock->unlock();
98 qset()->enqueue_complete_buffer(buf);
99 // We must relock only because the caller will unlock, for the normal
100 // case.
101 _lock->lock_without_safepoint_check();
102 }
105 PtrQueueSet::PtrQueueSet(bool notify_when_complete) :
106 _max_completed_queue(0),
107 _cbl_mon(NULL), _fl_lock(NULL),
108 _notify_when_complete(notify_when_complete),
109 _sz(0),
110 _completed_buffers_head(NULL),
111 _completed_buffers_tail(NULL),
112 _n_completed_buffers(0),
113 _process_completed_threshold(0), _process_completed(false),
114 _buf_free_list(NULL), _buf_free_list_sz(0)
115 {
116 _fl_owner = this;
117 }
119 void** PtrQueueSet::allocate_buffer() {
120 assert(_sz > 0, "Didn't set a buffer size.");
121 MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
122 if (_fl_owner->_buf_free_list != NULL) {
123 void** res = BufferNode::make_buffer_from_node(_fl_owner->_buf_free_list);
124 _fl_owner->_buf_free_list = _fl_owner->_buf_free_list->next();
125 _fl_owner->_buf_free_list_sz--;
126 return res;
127 } else {
128 // Allocate space for the BufferNode in front of the buffer.
129 char *b = NEW_C_HEAP_ARRAY(char, _sz + BufferNode::aligned_size(), mtGC);
130 return BufferNode::make_buffer_from_block(b);
131 }
132 }
134 void PtrQueueSet::deallocate_buffer(void** buf) {
135 assert(_sz > 0, "Didn't set a buffer size.");
136 MutexLockerEx x(_fl_owner->_fl_lock, Mutex::_no_safepoint_check_flag);
137 BufferNode *node = BufferNode::make_node_from_buffer(buf);
138 node->set_next(_fl_owner->_buf_free_list);
139 _fl_owner->_buf_free_list = node;
140 _fl_owner->_buf_free_list_sz++;
141 }
143 void PtrQueueSet::reduce_free_list() {
144 assert(_fl_owner == this, "Free list reduction is allowed only for the owner");
145 // For now we'll adopt the strategy of deleting half.
146 MutexLockerEx x(_fl_lock, Mutex::_no_safepoint_check_flag);
147 size_t n = _buf_free_list_sz / 2;
148 while (n > 0) {
149 assert(_buf_free_list != NULL, "_buf_free_list_sz must be wrong.");
150 void* b = BufferNode::make_block_from_node(_buf_free_list);
151 _buf_free_list = _buf_free_list->next();
152 FREE_C_HEAP_ARRAY(char, b, mtGC);
153 _buf_free_list_sz --;
154 n--;
155 }
156 }
158 void PtrQueue::handle_zero_index() {
159 assert(_index == 0, "Precondition.");
161 // This thread records the full buffer and allocates a new one (while
162 // holding the lock if there is one).
163 if (_buf != NULL) {
164 if (!should_enqueue_buffer()) {
165 assert(_index > 0, "the buffer can only be re-used if it's not full");
166 return;
167 }
169 if (_lock) {
170 assert(_lock->owned_by_self(), "Required.");
172 // The current PtrQ may be the shared dirty card queue and
173 // may be being manipulated by more than one worker thread
174 // during a pause. Since the enqueuing of the completed
175 // buffer unlocks the Shared_DirtyCardQ_lock more than one
176 // worker thread can 'race' on reading the shared queue attributes
177 // (_buf and _index) and multiple threads can call into this
178 // routine for the same buffer. This will cause the completed
179 // buffer to be added to the CBL multiple times.
181 // We "claim" the current buffer by caching value of _buf in
182 // a local and clearing the field while holding _lock. When
183 // _lock is released (while enqueueing the completed buffer)
184 // the thread that acquires _lock will skip this code,
185 // preventing the subsequent the multiple enqueue, and
186 // install a newly allocated buffer below.
188 void** buf = _buf; // local pointer to completed buffer
189 _buf = NULL; // clear shared _buf field
191 locking_enqueue_completed_buffer(buf); // enqueue completed buffer
193 // While the current thread was enqueuing the buffer another thread
194 // may have a allocated a new buffer and inserted it into this pointer
195 // queue. If that happens then we just return so that the current
196 // thread doesn't overwrite the buffer allocated by the other thread
197 // and potentially losing some dirtied cards.
199 if (_buf != NULL) return;
200 } else {
201 if (qset()->process_or_enqueue_complete_buffer(_buf)) {
202 // Recycle the buffer. No allocation.
203 _sz = qset()->buffer_size();
204 _index = _sz;
205 return;
206 }
207 }
208 }
209 // Reallocate the buffer
210 _buf = qset()->allocate_buffer();
211 _sz = qset()->buffer_size();
212 _index = _sz;
213 assert(0 <= _index && _index <= _sz, "Invariant.");
214 }
216 bool PtrQueueSet::process_or_enqueue_complete_buffer(void** buf) {
217 if (Thread::current()->is_Java_thread()) {
218 // We don't lock. It is fine to be epsilon-precise here.
219 if (_max_completed_queue == 0 || _max_completed_queue > 0 &&
220 _n_completed_buffers >= _max_completed_queue + _completed_queue_padding) {
221 bool b = mut_process_buffer(buf);
222 if (b) {
223 // True here means that the buffer hasn't been deallocated and the caller may reuse it.
224 return true;
225 }
226 }
227 }
228 // The buffer will be enqueued. The caller will have to get a new one.
229 enqueue_complete_buffer(buf);
230 return false;
231 }
233 void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) {
234 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
235 BufferNode* cbn = BufferNode::new_from_buffer(buf);
236 cbn->set_index(index);
237 if (_completed_buffers_tail == NULL) {
238 assert(_completed_buffers_head == NULL, "Well-formedness");
239 _completed_buffers_head = cbn;
240 _completed_buffers_tail = cbn;
241 } else {
242 _completed_buffers_tail->set_next(cbn);
243 _completed_buffers_tail = cbn;
244 }
245 _n_completed_buffers++;
247 if (!_process_completed && _process_completed_threshold >= 0 &&
248 _n_completed_buffers >= _process_completed_threshold) {
249 _process_completed = true;
250 if (_notify_when_complete)
251 _cbl_mon->notify();
252 }
253 debug_only(assert_completed_buffer_list_len_correct_locked());
254 }
256 int PtrQueueSet::completed_buffers_list_length() {
257 int n = 0;
258 BufferNode* cbn = _completed_buffers_head;
259 while (cbn != NULL) {
260 n++;
261 cbn = cbn->next();
262 }
263 return n;
264 }
266 void PtrQueueSet::assert_completed_buffer_list_len_correct() {
267 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
268 assert_completed_buffer_list_len_correct_locked();
269 }
271 void PtrQueueSet::assert_completed_buffer_list_len_correct_locked() {
272 guarantee(completed_buffers_list_length() == _n_completed_buffers,
273 "Completed buffer length is wrong.");
274 }
276 void PtrQueueSet::set_buffer_size(size_t sz) {
277 assert(_sz == 0 && sz > 0, "Should be called only once.");
278 _sz = sz * oopSize;
279 }
281 // Merge lists of buffers. Notify the processing threads.
282 // The source queue is emptied as a result. The queues
283 // must share the monitor.
284 void PtrQueueSet::merge_bufferlists(PtrQueueSet *src) {
285 assert(_cbl_mon == src->_cbl_mon, "Should share the same lock");
286 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
287 if (_completed_buffers_tail == NULL) {
288 assert(_completed_buffers_head == NULL, "Well-formedness");
289 _completed_buffers_head = src->_completed_buffers_head;
290 _completed_buffers_tail = src->_completed_buffers_tail;
291 } else {
292 assert(_completed_buffers_head != NULL, "Well formedness");
293 if (src->_completed_buffers_head != NULL) {
294 _completed_buffers_tail->set_next(src->_completed_buffers_head);
295 _completed_buffers_tail = src->_completed_buffers_tail;
296 }
297 }
298 _n_completed_buffers += src->_n_completed_buffers;
300 src->_n_completed_buffers = 0;
301 src->_completed_buffers_head = NULL;
302 src->_completed_buffers_tail = NULL;
304 assert(_completed_buffers_head == NULL && _completed_buffers_tail == NULL ||
305 _completed_buffers_head != NULL && _completed_buffers_tail != NULL,
306 "Sanity");
307 }
309 void PtrQueueSet::notify_if_necessary() {
310 MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag);
311 if (_n_completed_buffers >= _process_completed_threshold || _max_completed_queue == 0) {
312 _process_completed = true;
313 if (_notify_when_complete)
314 _cbl_mon->notify();
315 }
316 }