src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp

Thu, 22 Sep 2011 10:57:37 -0700

author
johnc
date
Thu, 22 Sep 2011 10:57:37 -0700
changeset 3175
4dfb2df418f2
parent 2314
f95d63e2154a
child 3294
bca17e38de00
permissions
-rw-r--r--

6484982: G1: process references during evacuation pauses
Summary: G1 now uses two reference processors - one is used by concurrent marking and the other is used by STW GCs (both full and incremental evacuation pauses). In an evacuation pause, the reference processor is embedded into the closures used to scan objects. Doing so causes causes reference objects to be 'discovered' by the reference processor. At the end of the evacuation pause, these discovered reference objects are processed - preserving (and copying) referent objects (and their reachable graphs) as appropriate.
Reviewed-by: ysr, jwilhelm, brutisso, stefank, tonyp

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

mercurial