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

Tue, 23 Nov 2010 13:22:55 -0800

author
stefank
date
Tue, 23 Nov 2010 13:22:55 -0800
changeset 2314
f95d63e2154a
parent 1907
c18cbe5936b8
child 3294
bca17e38de00
permissions
-rw-r--r--

6989984: Use standard include model for Hospot
Summary: Replaced MakeDeps and the includeDB files with more standardized solutions.
Reviewed-by: coleenp, kvn, kamg

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