Mercurial > hg > graal-compiler
annotate src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp @ 1656:4e5661ba9d98
6944166: G1: explicit GCs are not always handled correctly
Summary: G1 was not handling explicit GCs correctly in many ways. It does now. See the CR for the list of improvements contained in this changeset.
Reviewed-by: iveresov, ysr, johnc
author | tonyp |
---|---|
date | Mon, 28 Jun 2010 14:13:17 -0400 |
parents | c18cbe5936b8 |
children | f95d63e2154a |
rev | line source |
---|---|
0 | 1 /* |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
2 * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
25 #include "incls/_precompiled.incl" | |
26 #include "incls/_gcTaskManager.cpp.incl" | |
27 | |
28 // | |
29 // GCTask | |
30 // | |
31 | |
32 const char* GCTask::Kind::to_string(kind value) { | |
33 const char* result = "unknown GCTask kind"; | |
34 switch (value) { | |
35 default: | |
36 result = "unknown GCTask kind"; | |
37 break; | |
38 case unknown_task: | |
39 result = "unknown task"; | |
40 break; | |
41 case ordinary_task: | |
42 result = "ordinary task"; | |
43 break; | |
44 case barrier_task: | |
45 result = "barrier task"; | |
46 break; | |
47 case noop_task: | |
48 result = "noop task"; | |
49 break; | |
50 } | |
51 return result; | |
52 }; | |
53 | |
54 GCTask::GCTask() : | |
55 _kind(Kind::ordinary_task), | |
56 _affinity(GCTaskManager::sentinel_worker()){ | |
57 initialize(); | |
58 } | |
59 | |
60 GCTask::GCTask(Kind::kind kind) : | |
61 _kind(kind), | |
62 _affinity(GCTaskManager::sentinel_worker()) { | |
63 initialize(); | |
64 } | |
65 | |
66 GCTask::GCTask(uint affinity) : | |
67 _kind(Kind::ordinary_task), | |
68 _affinity(affinity) { | |
69 initialize(); | |
70 } | |
71 | |
72 GCTask::GCTask(Kind::kind kind, uint affinity) : | |
73 _kind(kind), | |
74 _affinity(affinity) { | |
75 initialize(); | |
76 } | |
77 | |
78 void GCTask::initialize() { | |
79 _older = NULL; | |
80 _newer = NULL; | |
81 } | |
82 | |
83 void GCTask::destruct() { | |
84 assert(older() == NULL, "shouldn't have an older task"); | |
85 assert(newer() == NULL, "shouldn't have a newer task"); | |
86 // Nothing to do. | |
87 } | |
88 | |
89 NOT_PRODUCT( | |
90 void GCTask::print(const char* message) const { | |
91 tty->print(INTPTR_FORMAT " <- " INTPTR_FORMAT "(%u) -> " INTPTR_FORMAT, | |
92 newer(), this, affinity(), older()); | |
93 } | |
94 ) | |
95 | |
96 // | |
97 // GCTaskQueue | |
98 // | |
99 | |
100 GCTaskQueue* GCTaskQueue::create() { | |
101 GCTaskQueue* result = new GCTaskQueue(false); | |
102 if (TraceGCTaskQueue) { | |
103 tty->print_cr("GCTaskQueue::create()" | |
104 " returns " INTPTR_FORMAT, result); | |
105 } | |
106 return result; | |
107 } | |
108 | |
109 GCTaskQueue* GCTaskQueue::create_on_c_heap() { | |
110 GCTaskQueue* result = new(ResourceObj::C_HEAP) GCTaskQueue(true); | |
111 if (TraceGCTaskQueue) { | |
112 tty->print_cr("GCTaskQueue::create_on_c_heap()" | |
113 " returns " INTPTR_FORMAT, | |
114 result); | |
115 } | |
116 return result; | |
117 } | |
118 | |
119 GCTaskQueue::GCTaskQueue(bool on_c_heap) : | |
120 _is_c_heap_obj(on_c_heap) { | |
121 initialize(); | |
122 if (TraceGCTaskQueue) { | |
123 tty->print_cr("[" INTPTR_FORMAT "]" | |
124 " GCTaskQueue::GCTaskQueue() constructor", | |
125 this); | |
126 } | |
127 } | |
128 | |
129 void GCTaskQueue::destruct() { | |
130 // Nothing to do. | |
131 } | |
132 | |
133 void GCTaskQueue::destroy(GCTaskQueue* that) { | |
134 if (TraceGCTaskQueue) { | |
135 tty->print_cr("[" INTPTR_FORMAT "]" | |
136 " GCTaskQueue::destroy()" | |
137 " is_c_heap_obj: %s", | |
138 that, | |
139 that->is_c_heap_obj() ? "true" : "false"); | |
140 } | |
141 // That instance may have been allocated as a CHeapObj, | |
142 // in which case we have to free it explicitly. | |
143 if (that != NULL) { | |
144 that->destruct(); | |
145 assert(that->is_empty(), "should be empty"); | |
146 if (that->is_c_heap_obj()) { | |
147 FreeHeap(that); | |
148 } | |
149 } | |
150 } | |
151 | |
152 void GCTaskQueue::initialize() { | |
153 set_insert_end(NULL); | |
154 set_remove_end(NULL); | |
155 set_length(0); | |
156 } | |
157 | |
158 // Enqueue one task. | |
159 void GCTaskQueue::enqueue(GCTask* task) { | |
160 if (TraceGCTaskQueue) { | |
161 tty->print_cr("[" INTPTR_FORMAT "]" | |
162 " GCTaskQueue::enqueue(task: " | |
163 INTPTR_FORMAT ")", | |
164 this, task); | |
165 print("before:"); | |
166 } | |
167 assert(task != NULL, "shouldn't have null task"); | |
168 assert(task->older() == NULL, "shouldn't be on queue"); | |
169 assert(task->newer() == NULL, "shouldn't be on queue"); | |
170 task->set_newer(NULL); | |
171 task->set_older(insert_end()); | |
172 if (is_empty()) { | |
173 set_remove_end(task); | |
174 } else { | |
175 insert_end()->set_newer(task); | |
176 } | |
177 set_insert_end(task); | |
178 increment_length(); | |
179 if (TraceGCTaskQueue) { | |
180 print("after:"); | |
181 } | |
182 } | |
183 | |
184 // Enqueue a whole list of tasks. Empties the argument list. | |
185 void GCTaskQueue::enqueue(GCTaskQueue* list) { | |
186 if (TraceGCTaskQueue) { | |
187 tty->print_cr("[" INTPTR_FORMAT "]" | |
188 " GCTaskQueue::enqueue(list: " | |
189 INTPTR_FORMAT ")", | |
190 this); | |
191 print("before:"); | |
192 list->print("list:"); | |
193 } | |
194 if (list->is_empty()) { | |
195 // Enqueuing the empty list: nothing to do. | |
196 return; | |
197 } | |
198 uint list_length = list->length(); | |
199 if (is_empty()) { | |
200 // Enqueuing to empty list: just acquire elements. | |
201 set_insert_end(list->insert_end()); | |
202 set_remove_end(list->remove_end()); | |
203 set_length(list_length); | |
204 } else { | |
205 // Prepend argument list to our queue. | |
206 list->remove_end()->set_older(insert_end()); | |
207 insert_end()->set_newer(list->remove_end()); | |
208 set_insert_end(list->insert_end()); | |
209 // empty the argument list. | |
210 } | |
211 set_length(length() + list_length); | |
212 list->initialize(); | |
213 if (TraceGCTaskQueue) { | |
214 print("after:"); | |
215 list->print("list:"); | |
216 } | |
217 } | |
218 | |
219 // Dequeue one task. | |
220 GCTask* GCTaskQueue::dequeue() { | |
221 if (TraceGCTaskQueue) { | |
222 tty->print_cr("[" INTPTR_FORMAT "]" | |
223 " GCTaskQueue::dequeue()", this); | |
224 print("before:"); | |
225 } | |
226 assert(!is_empty(), "shouldn't dequeue from empty list"); | |
227 GCTask* result = remove(); | |
228 assert(result != NULL, "shouldn't have NULL task"); | |
229 if (TraceGCTaskQueue) { | |
230 tty->print_cr(" return: " INTPTR_FORMAT, result); | |
231 print("after:"); | |
232 } | |
233 return result; | |
234 } | |
235 | |
236 // Dequeue one task, preferring one with affinity. | |
237 GCTask* GCTaskQueue::dequeue(uint affinity) { | |
238 if (TraceGCTaskQueue) { | |
239 tty->print_cr("[" INTPTR_FORMAT "]" | |
240 " GCTaskQueue::dequeue(%u)", this, affinity); | |
241 print("before:"); | |
242 } | |
243 assert(!is_empty(), "shouldn't dequeue from empty list"); | |
244 // Look down to the next barrier for a task with this affinity. | |
245 GCTask* result = NULL; | |
246 for (GCTask* element = remove_end(); | |
247 element != NULL; | |
248 element = element->newer()) { | |
249 if (element->is_barrier_task()) { | |
250 // Don't consider barrier tasks, nor past them. | |
251 result = NULL; | |
252 break; | |
253 } | |
254 if (element->affinity() == affinity) { | |
255 result = remove(element); | |
256 break; | |
257 } | |
258 } | |
259 // If we didn't find anything with affinity, just take the next task. | |
260 if (result == NULL) { | |
261 result = remove(); | |
262 } | |
263 if (TraceGCTaskQueue) { | |
264 tty->print_cr(" return: " INTPTR_FORMAT, result); | |
265 print("after:"); | |
266 } | |
267 return result; | |
268 } | |
269 | |
270 GCTask* GCTaskQueue::remove() { | |
271 // Dequeue from remove end. | |
272 GCTask* result = remove_end(); | |
273 assert(result != NULL, "shouldn't have null task"); | |
274 assert(result->older() == NULL, "not the remove_end"); | |
275 set_remove_end(result->newer()); | |
276 if (remove_end() == NULL) { | |
277 assert(insert_end() == result, "not a singleton"); | |
278 set_insert_end(NULL); | |
279 } else { | |
280 remove_end()->set_older(NULL); | |
281 } | |
282 result->set_newer(NULL); | |
283 decrement_length(); | |
284 assert(result->newer() == NULL, "shouldn't be on queue"); | |
285 assert(result->older() == NULL, "shouldn't be on queue"); | |
286 return result; | |
287 } | |
288 | |
289 GCTask* GCTaskQueue::remove(GCTask* task) { | |
290 // This is slightly more work, and has slightly fewer asserts | |
291 // than removing from the remove end. | |
292 assert(task != NULL, "shouldn't have null task"); | |
293 GCTask* result = task; | |
294 if (result->newer() != NULL) { | |
295 result->newer()->set_older(result->older()); | |
296 } else { | |
297 assert(insert_end() == result, "not youngest"); | |
298 set_insert_end(result->older()); | |
299 } | |
300 if (result->older() != NULL) { | |
301 result->older()->set_newer(result->newer()); | |
302 } else { | |
303 assert(remove_end() == result, "not oldest"); | |
304 set_remove_end(result->newer()); | |
305 } | |
306 result->set_newer(NULL); | |
307 result->set_older(NULL); | |
308 decrement_length(); | |
309 return result; | |
310 } | |
311 | |
312 NOT_PRODUCT( | |
313 void GCTaskQueue::print(const char* message) const { | |
314 tty->print_cr("[" INTPTR_FORMAT "] GCTaskQueue:" | |
315 " insert_end: " INTPTR_FORMAT | |
316 " remove_end: " INTPTR_FORMAT | |
317 " %s", | |
318 this, insert_end(), remove_end(), message); | |
319 for (GCTask* element = insert_end(); | |
320 element != NULL; | |
321 element = element->older()) { | |
322 element->print(" "); | |
323 tty->cr(); | |
324 } | |
325 } | |
326 ) | |
327 | |
328 // | |
329 // SynchronizedGCTaskQueue | |
330 // | |
331 | |
332 SynchronizedGCTaskQueue::SynchronizedGCTaskQueue(GCTaskQueue* queue_arg, | |
333 Monitor * lock_arg) : | |
334 _unsynchronized_queue(queue_arg), | |
335 _lock(lock_arg) { | |
336 assert(unsynchronized_queue() != NULL, "null queue"); | |
337 assert(lock() != NULL, "null lock"); | |
338 } | |
339 | |
340 SynchronizedGCTaskQueue::~SynchronizedGCTaskQueue() { | |
341 // Nothing to do. | |
342 } | |
343 | |
344 // | |
345 // GCTaskManager | |
346 // | |
347 GCTaskManager::GCTaskManager(uint workers) : | |
348 _workers(workers), | |
349 _ndc(NULL) { | |
350 initialize(); | |
351 } | |
352 | |
353 GCTaskManager::GCTaskManager(uint workers, NotifyDoneClosure* ndc) : | |
354 _workers(workers), | |
355 _ndc(ndc) { | |
356 initialize(); | |
357 } | |
358 | |
359 void GCTaskManager::initialize() { | |
360 if (TraceGCTaskManager) { | |
361 tty->print_cr("GCTaskManager::initialize: workers: %u", workers()); | |
362 } | |
363 assert(workers() != 0, "no workers"); | |
364 _monitor = new Monitor(Mutex::barrier, // rank | |
365 "GCTaskManager monitor", // name | |
366 Mutex::_allow_vm_block_flag); // allow_vm_block | |
367 // The queue for the GCTaskManager must be a CHeapObj. | |
368 GCTaskQueue* unsynchronized_queue = GCTaskQueue::create_on_c_heap(); | |
369 _queue = SynchronizedGCTaskQueue::create(unsynchronized_queue, lock()); | |
370 _noop_task = NoopGCTask::create_on_c_heap(); | |
371 _resource_flag = NEW_C_HEAP_ARRAY(bool, workers()); | |
372 { | |
373 // Set up worker threads. | |
374 // Distribute the workers among the available processors, | |
375 // unless we were told not to, or if the os doesn't want to. | |
376 uint* processor_assignment = NEW_C_HEAP_ARRAY(uint, workers()); | |
377 if (!BindGCTaskThreadsToCPUs || | |
378 !os::distribute_processes(workers(), processor_assignment)) { | |
379 for (uint a = 0; a < workers(); a += 1) { | |
380 processor_assignment[a] = sentinel_worker(); | |
381 } | |
382 } | |
383 _thread = NEW_C_HEAP_ARRAY(GCTaskThread*, workers()); | |
384 for (uint t = 0; t < workers(); t += 1) { | |
385 set_thread(t, GCTaskThread::create(this, t, processor_assignment[t])); | |
386 } | |
387 if (TraceGCTaskThread) { | |
388 tty->print("GCTaskManager::initialize: distribution:"); | |
389 for (uint t = 0; t < workers(); t += 1) { | |
390 tty->print(" %u", processor_assignment[t]); | |
391 } | |
392 tty->cr(); | |
393 } | |
394 FREE_C_HEAP_ARRAY(uint, processor_assignment); | |
395 } | |
396 reset_busy_workers(); | |
397 set_unblocked(); | |
398 for (uint w = 0; w < workers(); w += 1) { | |
399 set_resource_flag(w, false); | |
400 } | |
401 reset_delivered_tasks(); | |
402 reset_completed_tasks(); | |
403 reset_noop_tasks(); | |
404 reset_barriers(); | |
405 reset_emptied_queue(); | |
406 for (uint s = 0; s < workers(); s += 1) { | |
407 thread(s)->start(); | |
408 } | |
409 } | |
410 | |
411 GCTaskManager::~GCTaskManager() { | |
412 assert(busy_workers() == 0, "still have busy workers"); | |
413 assert(queue()->is_empty(), "still have queued work"); | |
414 NoopGCTask::destroy(_noop_task); | |
415 _noop_task = NULL; | |
416 if (_thread != NULL) { | |
417 for (uint i = 0; i < workers(); i += 1) { | |
418 GCTaskThread::destroy(thread(i)); | |
419 set_thread(i, NULL); | |
420 } | |
421 FREE_C_HEAP_ARRAY(GCTaskThread*, _thread); | |
422 _thread = NULL; | |
423 } | |
424 if (_resource_flag != NULL) { | |
425 FREE_C_HEAP_ARRAY(bool, _resource_flag); | |
426 _resource_flag = NULL; | |
427 } | |
428 if (queue() != NULL) { | |
429 GCTaskQueue* unsynchronized_queue = queue()->unsynchronized_queue(); | |
430 GCTaskQueue::destroy(unsynchronized_queue); | |
431 SynchronizedGCTaskQueue::destroy(queue()); | |
432 _queue = NULL; | |
433 } | |
434 if (monitor() != NULL) { | |
435 delete monitor(); | |
436 _monitor = NULL; | |
437 } | |
438 } | |
439 | |
440 void GCTaskManager::print_task_time_stamps() { | |
441 for(uint i=0; i<ParallelGCThreads; i++) { | |
442 GCTaskThread* t = thread(i); | |
443 t->print_task_time_stamps(); | |
444 } | |
445 } | |
446 | |
447 void GCTaskManager::print_threads_on(outputStream* st) { | |
448 uint num_thr = workers(); | |
449 for (uint i = 0; i < num_thr; i++) { | |
450 thread(i)->print_on(st); | |
451 st->cr(); | |
452 } | |
453 } | |
454 | |
455 void GCTaskManager::threads_do(ThreadClosure* tc) { | |
456 assert(tc != NULL, "Null ThreadClosure"); | |
457 uint num_thr = workers(); | |
458 for (uint i = 0; i < num_thr; i++) { | |
459 tc->do_thread(thread(i)); | |
460 } | |
461 } | |
462 | |
463 GCTaskThread* GCTaskManager::thread(uint which) { | |
464 assert(which < workers(), "index out of bounds"); | |
465 assert(_thread[which] != NULL, "shouldn't have null thread"); | |
466 return _thread[which]; | |
467 } | |
468 | |
469 void GCTaskManager::set_thread(uint which, GCTaskThread* value) { | |
470 assert(which < workers(), "index out of bounds"); | |
471 assert(value != NULL, "shouldn't have null thread"); | |
472 _thread[which] = value; | |
473 } | |
474 | |
475 void GCTaskManager::add_task(GCTask* task) { | |
476 assert(task != NULL, "shouldn't have null task"); | |
477 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
478 if (TraceGCTaskManager) { | |
479 tty->print_cr("GCTaskManager::add_task(" INTPTR_FORMAT " [%s])", | |
480 task, GCTask::Kind::to_string(task->kind())); | |
481 } | |
482 queue()->enqueue(task); | |
483 // Notify with the lock held to avoid missed notifies. | |
484 if (TraceGCTaskManager) { | |
485 tty->print_cr(" GCTaskManager::add_task (%s)->notify_all", | |
486 monitor()->name()); | |
487 } | |
488 (void) monitor()->notify_all(); | |
489 // Release monitor(). | |
490 } | |
491 | |
492 void GCTaskManager::add_list(GCTaskQueue* list) { | |
493 assert(list != NULL, "shouldn't have null task"); | |
494 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
495 if (TraceGCTaskManager) { | |
496 tty->print_cr("GCTaskManager::add_list(%u)", list->length()); | |
497 } | |
498 queue()->enqueue(list); | |
499 // Notify with the lock held to avoid missed notifies. | |
500 if (TraceGCTaskManager) { | |
501 tty->print_cr(" GCTaskManager::add_list (%s)->notify_all", | |
502 monitor()->name()); | |
503 } | |
504 (void) monitor()->notify_all(); | |
505 // Release monitor(). | |
506 } | |
507 | |
508 GCTask* GCTaskManager::get_task(uint which) { | |
509 GCTask* result = NULL; | |
510 // Grab the queue lock. | |
511 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
512 // Wait while the queue is block or | |
513 // there is nothing to do, except maybe release resources. | |
514 while (is_blocked() || | |
515 (queue()->is_empty() && !should_release_resources(which))) { | |
516 if (TraceGCTaskManager) { | |
517 tty->print_cr("GCTaskManager::get_task(%u)" | |
518 " blocked: %s" | |
519 " empty: %s" | |
520 " release: %s", | |
521 which, | |
522 is_blocked() ? "true" : "false", | |
523 queue()->is_empty() ? "true" : "false", | |
524 should_release_resources(which) ? "true" : "false"); | |
525 tty->print_cr(" => (%s)->wait()", | |
526 monitor()->name()); | |
527 } | |
528 monitor()->wait(Mutex::_no_safepoint_check_flag, 0); | |
529 } | |
530 // We've reacquired the queue lock here. | |
531 // Figure out which condition caused us to exit the loop above. | |
532 if (!queue()->is_empty()) { | |
533 if (UseGCTaskAffinity) { | |
534 result = queue()->dequeue(which); | |
535 } else { | |
536 result = queue()->dequeue(); | |
537 } | |
538 if (result->is_barrier_task()) { | |
539 assert(which != sentinel_worker(), | |
540 "blocker shouldn't be bogus"); | |
541 set_blocking_worker(which); | |
542 } | |
543 } else { | |
544 // The queue is empty, but we were woken up. | |
545 // Just hand back a Noop task, | |
546 // in case someone wanted us to release resources, or whatever. | |
547 result = noop_task(); | |
548 increment_noop_tasks(); | |
549 } | |
550 assert(result != NULL, "shouldn't have null task"); | |
551 if (TraceGCTaskManager) { | |
552 tty->print_cr("GCTaskManager::get_task(%u) => " INTPTR_FORMAT " [%s]", | |
553 which, result, GCTask::Kind::to_string(result->kind())); | |
554 tty->print_cr(" %s", result->name()); | |
555 } | |
556 increment_busy_workers(); | |
557 increment_delivered_tasks(); | |
558 return result; | |
559 // Release monitor(). | |
560 } | |
561 | |
562 void GCTaskManager::note_completion(uint which) { | |
563 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
564 if (TraceGCTaskManager) { | |
565 tty->print_cr("GCTaskManager::note_completion(%u)", which); | |
566 } | |
567 // If we are blocked, check if the completing thread is the blocker. | |
568 if (blocking_worker() == which) { | |
569 assert(blocking_worker() != sentinel_worker(), | |
570 "blocker shouldn't be bogus"); | |
571 increment_barriers(); | |
572 set_unblocked(); | |
573 } | |
574 increment_completed_tasks(); | |
575 uint active = decrement_busy_workers(); | |
576 if ((active == 0) && (queue()->is_empty())) { | |
577 increment_emptied_queue(); | |
578 if (TraceGCTaskManager) { | |
579 tty->print_cr(" GCTaskManager::note_completion(%u) done", which); | |
580 } | |
581 // Notify client that we are done. | |
582 NotifyDoneClosure* ndc = notify_done_closure(); | |
583 if (ndc != NULL) { | |
584 ndc->notify(this); | |
585 } | |
586 } | |
587 if (TraceGCTaskManager) { | |
588 tty->print_cr(" GCTaskManager::note_completion(%u) (%s)->notify_all", | |
589 which, monitor()->name()); | |
590 tty->print_cr(" " | |
591 " blocked: %s" | |
592 " empty: %s" | |
593 " release: %s", | |
594 is_blocked() ? "true" : "false", | |
595 queue()->is_empty() ? "true" : "false", | |
596 should_release_resources(which) ? "true" : "false"); | |
597 tty->print_cr(" " | |
598 " delivered: %u" | |
599 " completed: %u" | |
600 " barriers: %u" | |
601 " emptied: %u", | |
602 delivered_tasks(), | |
603 completed_tasks(), | |
604 barriers(), | |
605 emptied_queue()); | |
606 } | |
607 // Tell everyone that a task has completed. | |
608 (void) monitor()->notify_all(); | |
609 // Release monitor(). | |
610 } | |
611 | |
612 uint GCTaskManager::increment_busy_workers() { | |
613 assert(queue()->own_lock(), "don't own the lock"); | |
614 _busy_workers += 1; | |
615 return _busy_workers; | |
616 } | |
617 | |
618 uint GCTaskManager::decrement_busy_workers() { | |
619 assert(queue()->own_lock(), "don't own the lock"); | |
620 _busy_workers -= 1; | |
621 return _busy_workers; | |
622 } | |
623 | |
624 void GCTaskManager::release_all_resources() { | |
625 // If you want this to be done atomically, do it in a BarrierGCTask. | |
626 for (uint i = 0; i < workers(); i += 1) { | |
627 set_resource_flag(i, true); | |
628 } | |
629 } | |
630 | |
631 bool GCTaskManager::should_release_resources(uint which) { | |
632 // This can be done without a lock because each thread reads one element. | |
633 return resource_flag(which); | |
634 } | |
635 | |
636 void GCTaskManager::note_release(uint which) { | |
637 // This can be done without a lock because each thread writes one element. | |
638 set_resource_flag(which, false); | |
639 } | |
640 | |
641 void GCTaskManager::execute_and_wait(GCTaskQueue* list) { | |
642 WaitForBarrierGCTask* fin = WaitForBarrierGCTask::create(); | |
643 list->enqueue(fin); | |
644 add_list(list); | |
645 fin->wait_for(); | |
646 // We have to release the barrier tasks! | |
647 WaitForBarrierGCTask::destroy(fin); | |
648 } | |
649 | |
650 bool GCTaskManager::resource_flag(uint which) { | |
651 assert(which < workers(), "index out of bounds"); | |
652 return _resource_flag[which]; | |
653 } | |
654 | |
655 void GCTaskManager::set_resource_flag(uint which, bool value) { | |
656 assert(which < workers(), "index out of bounds"); | |
657 _resource_flag[which] = value; | |
658 } | |
659 | |
660 // | |
661 // NoopGCTask | |
662 // | |
663 | |
664 NoopGCTask* NoopGCTask::create() { | |
665 NoopGCTask* result = new NoopGCTask(false); | |
666 return result; | |
667 } | |
668 | |
669 NoopGCTask* NoopGCTask::create_on_c_heap() { | |
670 NoopGCTask* result = new(ResourceObj::C_HEAP) NoopGCTask(true); | |
671 return result; | |
672 } | |
673 | |
674 void NoopGCTask::destroy(NoopGCTask* that) { | |
675 if (that != NULL) { | |
676 that->destruct(); | |
677 if (that->is_c_heap_obj()) { | |
678 FreeHeap(that); | |
679 } | |
680 } | |
681 } | |
682 | |
683 void NoopGCTask::destruct() { | |
684 // This has to know it's superclass structure, just like the constructor. | |
685 this->GCTask::destruct(); | |
686 // Nothing else to do. | |
687 } | |
688 | |
689 // | |
690 // BarrierGCTask | |
691 // | |
692 | |
693 void BarrierGCTask::do_it(GCTaskManager* manager, uint which) { | |
694 // Wait for this to be the only busy worker. | |
695 // ??? I thought of having a StackObj class | |
696 // whose constructor would grab the lock and come to the barrier, | |
697 // and whose destructor would release the lock, | |
698 // but that seems like too much mechanism for two lines of code. | |
699 MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); | |
700 do_it_internal(manager, which); | |
701 // Release manager->lock(). | |
702 } | |
703 | |
704 void BarrierGCTask::do_it_internal(GCTaskManager* manager, uint which) { | |
705 // Wait for this to be the only busy worker. | |
706 assert(manager->monitor()->owned_by_self(), "don't own the lock"); | |
707 assert(manager->is_blocked(), "manager isn't blocked"); | |
708 while (manager->busy_workers() > 1) { | |
709 if (TraceGCTaskManager) { | |
710 tty->print_cr("BarrierGCTask::do_it(%u) waiting on %u workers", | |
711 which, manager->busy_workers()); | |
712 } | |
713 manager->monitor()->wait(Mutex::_no_safepoint_check_flag, 0); | |
714 } | |
715 } | |
716 | |
717 void BarrierGCTask::destruct() { | |
718 this->GCTask::destruct(); | |
719 // Nothing else to do. | |
720 } | |
721 | |
722 // | |
723 // ReleasingBarrierGCTask | |
724 // | |
725 | |
726 void ReleasingBarrierGCTask::do_it(GCTaskManager* manager, uint which) { | |
727 MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); | |
728 do_it_internal(manager, which); | |
729 manager->release_all_resources(); | |
730 // Release manager->lock(). | |
731 } | |
732 | |
733 void ReleasingBarrierGCTask::destruct() { | |
734 this->BarrierGCTask::destruct(); | |
735 // Nothing else to do. | |
736 } | |
737 | |
738 // | |
739 // NotifyingBarrierGCTask | |
740 // | |
741 | |
742 void NotifyingBarrierGCTask::do_it(GCTaskManager* manager, uint which) { | |
743 MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); | |
744 do_it_internal(manager, which); | |
745 NotifyDoneClosure* ndc = notify_done_closure(); | |
746 if (ndc != NULL) { | |
747 ndc->notify(manager); | |
748 } | |
749 // Release manager->lock(). | |
750 } | |
751 | |
752 void NotifyingBarrierGCTask::destruct() { | |
753 this->BarrierGCTask::destruct(); | |
754 // Nothing else to do. | |
755 } | |
756 | |
757 // | |
758 // WaitForBarrierGCTask | |
759 // | |
760 WaitForBarrierGCTask* WaitForBarrierGCTask::create() { | |
761 WaitForBarrierGCTask* result = new WaitForBarrierGCTask(false); | |
762 return result; | |
763 } | |
764 | |
765 WaitForBarrierGCTask* WaitForBarrierGCTask::create_on_c_heap() { | |
766 WaitForBarrierGCTask* result = new WaitForBarrierGCTask(true); | |
767 return result; | |
768 } | |
769 | |
770 WaitForBarrierGCTask::WaitForBarrierGCTask(bool on_c_heap) : | |
771 _is_c_heap_obj(on_c_heap) { | |
772 _monitor = MonitorSupply::reserve(); | |
773 set_should_wait(true); | |
774 if (TraceGCTaskManager) { | |
775 tty->print_cr("[" INTPTR_FORMAT "]" | |
776 " WaitForBarrierGCTask::WaitForBarrierGCTask()" | |
777 " monitor: " INTPTR_FORMAT, | |
778 this, monitor()); | |
779 } | |
780 } | |
781 | |
782 void WaitForBarrierGCTask::destroy(WaitForBarrierGCTask* that) { | |
783 if (that != NULL) { | |
784 if (TraceGCTaskManager) { | |
785 tty->print_cr("[" INTPTR_FORMAT "]" | |
786 " WaitForBarrierGCTask::destroy()" | |
787 " is_c_heap_obj: %s" | |
788 " monitor: " INTPTR_FORMAT, | |
789 that, | |
790 that->is_c_heap_obj() ? "true" : "false", | |
791 that->monitor()); | |
792 } | |
793 that->destruct(); | |
794 if (that->is_c_heap_obj()) { | |
795 FreeHeap(that); | |
796 } | |
797 } | |
798 } | |
799 | |
800 void WaitForBarrierGCTask::destruct() { | |
801 assert(monitor() != NULL, "monitor should not be NULL"); | |
802 if (TraceGCTaskManager) { | |
803 tty->print_cr("[" INTPTR_FORMAT "]" | |
804 " WaitForBarrierGCTask::destruct()" | |
805 " monitor: " INTPTR_FORMAT, | |
806 this, monitor()); | |
807 } | |
808 this->BarrierGCTask::destruct(); | |
809 // Clean up that should be in the destructor, | |
810 // except that ResourceMarks don't call destructors. | |
811 if (monitor() != NULL) { | |
812 MonitorSupply::release(monitor()); | |
813 } | |
814 _monitor = (Monitor*) 0xDEAD000F; | |
815 } | |
816 | |
817 void WaitForBarrierGCTask::do_it(GCTaskManager* manager, uint which) { | |
818 if (TraceGCTaskManager) { | |
819 tty->print_cr("[" INTPTR_FORMAT "]" | |
820 " WaitForBarrierGCTask::do_it() waiting for idle" | |
821 " monitor: " INTPTR_FORMAT, | |
822 this, monitor()); | |
823 } | |
824 { | |
825 // First, wait for the barrier to arrive. | |
826 MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); | |
827 do_it_internal(manager, which); | |
828 // Release manager->lock(). | |
829 } | |
830 { | |
831 // Then notify the waiter. | |
832 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
833 set_should_wait(false); | |
834 // Waiter doesn't miss the notify in the wait_for method | |
835 // since it checks the flag after grabbing the monitor. | |
836 if (TraceGCTaskManager) { | |
837 tty->print_cr("[" INTPTR_FORMAT "]" | |
838 " WaitForBarrierGCTask::do_it()" | |
839 " [" INTPTR_FORMAT "] (%s)->notify_all()", | |
840 this, monitor(), monitor()->name()); | |
841 } | |
842 monitor()->notify_all(); | |
843 // Release monitor(). | |
844 } | |
845 } | |
846 | |
847 void WaitForBarrierGCTask::wait_for() { | |
848 if (TraceGCTaskManager) { | |
849 tty->print_cr("[" INTPTR_FORMAT "]" | |
850 " WaitForBarrierGCTask::wait_for()" | |
851 " should_wait: %s", | |
852 this, should_wait() ? "true" : "false"); | |
853 } | |
854 { | |
855 // Grab the lock and check again. | |
856 MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); | |
857 while (should_wait()) { | |
858 if (TraceGCTaskManager) { | |
859 tty->print_cr("[" INTPTR_FORMAT "]" | |
860 " WaitForBarrierGCTask::wait_for()" | |
861 " [" INTPTR_FORMAT "] (%s)->wait()", | |
862 this, monitor(), monitor()->name()); | |
863 } | |
864 monitor()->wait(Mutex::_no_safepoint_check_flag, 0); | |
865 } | |
866 // Reset the flag in case someone reuses this task. | |
867 set_should_wait(true); | |
868 if (TraceGCTaskManager) { | |
869 tty->print_cr("[" INTPTR_FORMAT "]" | |
870 " WaitForBarrierGCTask::wait_for() returns" | |
871 " should_wait: %s", | |
872 this, should_wait() ? "true" : "false"); | |
873 } | |
874 // Release monitor(). | |
875 } | |
876 } | |
877 | |
878 Mutex* MonitorSupply::_lock = NULL; | |
879 GrowableArray<Monitor*>* MonitorSupply::_freelist = NULL; | |
880 | |
881 Monitor* MonitorSupply::reserve() { | |
882 Monitor* result = NULL; | |
883 // Lazy initialization: possible race. | |
884 if (lock() == NULL) { | |
885 _lock = new Mutex(Mutex::barrier, // rank | |
886 "MonitorSupply mutex", // name | |
887 Mutex::_allow_vm_block_flag); // allow_vm_block | |
888 } | |
889 { | |
890 MutexLockerEx ml(lock()); | |
891 // Lazy initialization. | |
892 if (freelist() == NULL) { | |
893 _freelist = | |
894 new(ResourceObj::C_HEAP) GrowableArray<Monitor*>(ParallelGCThreads, | |
895 true); | |
896 } | |
897 if (! freelist()->is_empty()) { | |
898 result = freelist()->pop(); | |
899 } else { | |
900 result = new Monitor(Mutex::barrier, // rank | |
901 "MonitorSupply monitor", // name | |
902 Mutex::_allow_vm_block_flag); // allow_vm_block | |
903 } | |
904 guarantee(result != NULL, "shouldn't return NULL"); | |
905 assert(!result->is_locked(), "shouldn't be locked"); | |
906 // release lock(). | |
907 } | |
908 return result; | |
909 } | |
910 | |
911 void MonitorSupply::release(Monitor* instance) { | |
912 assert(instance != NULL, "shouldn't release NULL"); | |
913 assert(!instance->is_locked(), "shouldn't be locked"); | |
914 { | |
915 MutexLockerEx ml(lock()); | |
916 freelist()->push(instance); | |
917 // release lock(). | |
918 } | |
919 } |