1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp Sat Dec 01 00:00:00 2007 +0000 1.3 @@ -0,0 +1,919 @@ 1.4 +/* 1.5 + * Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. 1.11 + * 1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.15 + * version 2 for more details (a copy is included in the LICENSE file that 1.16 + * accompanied this code). 1.17 + * 1.18 + * You should have received a copy of the GNU General Public License version 1.19 + * 2 along with this work; if not, write to the Free Software Foundation, 1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.21 + * 1.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 1.24 + * have any questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +#include "incls/_precompiled.incl" 1.29 +#include "incls/_gcTaskManager.cpp.incl" 1.30 + 1.31 +// 1.32 +// GCTask 1.33 +// 1.34 + 1.35 +const char* GCTask::Kind::to_string(kind value) { 1.36 + const char* result = "unknown GCTask kind"; 1.37 + switch (value) { 1.38 + default: 1.39 + result = "unknown GCTask kind"; 1.40 + break; 1.41 + case unknown_task: 1.42 + result = "unknown task"; 1.43 + break; 1.44 + case ordinary_task: 1.45 + result = "ordinary task"; 1.46 + break; 1.47 + case barrier_task: 1.48 + result = "barrier task"; 1.49 + break; 1.50 + case noop_task: 1.51 + result = "noop task"; 1.52 + break; 1.53 + } 1.54 + return result; 1.55 +}; 1.56 + 1.57 +GCTask::GCTask() : 1.58 + _kind(Kind::ordinary_task), 1.59 + _affinity(GCTaskManager::sentinel_worker()){ 1.60 + initialize(); 1.61 +} 1.62 + 1.63 +GCTask::GCTask(Kind::kind kind) : 1.64 + _kind(kind), 1.65 + _affinity(GCTaskManager::sentinel_worker()) { 1.66 + initialize(); 1.67 +} 1.68 + 1.69 +GCTask::GCTask(uint affinity) : 1.70 + _kind(Kind::ordinary_task), 1.71 + _affinity(affinity) { 1.72 + initialize(); 1.73 +} 1.74 + 1.75 +GCTask::GCTask(Kind::kind kind, uint affinity) : 1.76 + _kind(kind), 1.77 + _affinity(affinity) { 1.78 + initialize(); 1.79 +} 1.80 + 1.81 +void GCTask::initialize() { 1.82 + _older = NULL; 1.83 + _newer = NULL; 1.84 +} 1.85 + 1.86 +void GCTask::destruct() { 1.87 + assert(older() == NULL, "shouldn't have an older task"); 1.88 + assert(newer() == NULL, "shouldn't have a newer task"); 1.89 + // Nothing to do. 1.90 +} 1.91 + 1.92 +NOT_PRODUCT( 1.93 +void GCTask::print(const char* message) const { 1.94 + tty->print(INTPTR_FORMAT " <- " INTPTR_FORMAT "(%u) -> " INTPTR_FORMAT, 1.95 + newer(), this, affinity(), older()); 1.96 +} 1.97 +) 1.98 + 1.99 +// 1.100 +// GCTaskQueue 1.101 +// 1.102 + 1.103 +GCTaskQueue* GCTaskQueue::create() { 1.104 + GCTaskQueue* result = new GCTaskQueue(false); 1.105 + if (TraceGCTaskQueue) { 1.106 + tty->print_cr("GCTaskQueue::create()" 1.107 + " returns " INTPTR_FORMAT, result); 1.108 + } 1.109 + return result; 1.110 +} 1.111 + 1.112 +GCTaskQueue* GCTaskQueue::create_on_c_heap() { 1.113 + GCTaskQueue* result = new(ResourceObj::C_HEAP) GCTaskQueue(true); 1.114 + if (TraceGCTaskQueue) { 1.115 + tty->print_cr("GCTaskQueue::create_on_c_heap()" 1.116 + " returns " INTPTR_FORMAT, 1.117 + result); 1.118 + } 1.119 + return result; 1.120 +} 1.121 + 1.122 +GCTaskQueue::GCTaskQueue(bool on_c_heap) : 1.123 + _is_c_heap_obj(on_c_heap) { 1.124 + initialize(); 1.125 + if (TraceGCTaskQueue) { 1.126 + tty->print_cr("[" INTPTR_FORMAT "]" 1.127 + " GCTaskQueue::GCTaskQueue() constructor", 1.128 + this); 1.129 + } 1.130 +} 1.131 + 1.132 +void GCTaskQueue::destruct() { 1.133 + // Nothing to do. 1.134 +} 1.135 + 1.136 +void GCTaskQueue::destroy(GCTaskQueue* that) { 1.137 + if (TraceGCTaskQueue) { 1.138 + tty->print_cr("[" INTPTR_FORMAT "]" 1.139 + " GCTaskQueue::destroy()" 1.140 + " is_c_heap_obj: %s", 1.141 + that, 1.142 + that->is_c_heap_obj() ? "true" : "false"); 1.143 + } 1.144 + // That instance may have been allocated as a CHeapObj, 1.145 + // in which case we have to free it explicitly. 1.146 + if (that != NULL) { 1.147 + that->destruct(); 1.148 + assert(that->is_empty(), "should be empty"); 1.149 + if (that->is_c_heap_obj()) { 1.150 + FreeHeap(that); 1.151 + } 1.152 + } 1.153 +} 1.154 + 1.155 +void GCTaskQueue::initialize() { 1.156 + set_insert_end(NULL); 1.157 + set_remove_end(NULL); 1.158 + set_length(0); 1.159 +} 1.160 + 1.161 +// Enqueue one task. 1.162 +void GCTaskQueue::enqueue(GCTask* task) { 1.163 + if (TraceGCTaskQueue) { 1.164 + tty->print_cr("[" INTPTR_FORMAT "]" 1.165 + " GCTaskQueue::enqueue(task: " 1.166 + INTPTR_FORMAT ")", 1.167 + this, task); 1.168 + print("before:"); 1.169 + } 1.170 + assert(task != NULL, "shouldn't have null task"); 1.171 + assert(task->older() == NULL, "shouldn't be on queue"); 1.172 + assert(task->newer() == NULL, "shouldn't be on queue"); 1.173 + task->set_newer(NULL); 1.174 + task->set_older(insert_end()); 1.175 + if (is_empty()) { 1.176 + set_remove_end(task); 1.177 + } else { 1.178 + insert_end()->set_newer(task); 1.179 + } 1.180 + set_insert_end(task); 1.181 + increment_length(); 1.182 + if (TraceGCTaskQueue) { 1.183 + print("after:"); 1.184 + } 1.185 +} 1.186 + 1.187 +// Enqueue a whole list of tasks. Empties the argument list. 1.188 +void GCTaskQueue::enqueue(GCTaskQueue* list) { 1.189 + if (TraceGCTaskQueue) { 1.190 + tty->print_cr("[" INTPTR_FORMAT "]" 1.191 + " GCTaskQueue::enqueue(list: " 1.192 + INTPTR_FORMAT ")", 1.193 + this); 1.194 + print("before:"); 1.195 + list->print("list:"); 1.196 + } 1.197 + if (list->is_empty()) { 1.198 + // Enqueuing the empty list: nothing to do. 1.199 + return; 1.200 + } 1.201 + uint list_length = list->length(); 1.202 + if (is_empty()) { 1.203 + // Enqueuing to empty list: just acquire elements. 1.204 + set_insert_end(list->insert_end()); 1.205 + set_remove_end(list->remove_end()); 1.206 + set_length(list_length); 1.207 + } else { 1.208 + // Prepend argument list to our queue. 1.209 + list->remove_end()->set_older(insert_end()); 1.210 + insert_end()->set_newer(list->remove_end()); 1.211 + set_insert_end(list->insert_end()); 1.212 + // empty the argument list. 1.213 + } 1.214 + set_length(length() + list_length); 1.215 + list->initialize(); 1.216 + if (TraceGCTaskQueue) { 1.217 + print("after:"); 1.218 + list->print("list:"); 1.219 + } 1.220 +} 1.221 + 1.222 +// Dequeue one task. 1.223 +GCTask* GCTaskQueue::dequeue() { 1.224 + if (TraceGCTaskQueue) { 1.225 + tty->print_cr("[" INTPTR_FORMAT "]" 1.226 + " GCTaskQueue::dequeue()", this); 1.227 + print("before:"); 1.228 + } 1.229 + assert(!is_empty(), "shouldn't dequeue from empty list"); 1.230 + GCTask* result = remove(); 1.231 + assert(result != NULL, "shouldn't have NULL task"); 1.232 + if (TraceGCTaskQueue) { 1.233 + tty->print_cr(" return: " INTPTR_FORMAT, result); 1.234 + print("after:"); 1.235 + } 1.236 + return result; 1.237 +} 1.238 + 1.239 +// Dequeue one task, preferring one with affinity. 1.240 +GCTask* GCTaskQueue::dequeue(uint affinity) { 1.241 + if (TraceGCTaskQueue) { 1.242 + tty->print_cr("[" INTPTR_FORMAT "]" 1.243 + " GCTaskQueue::dequeue(%u)", this, affinity); 1.244 + print("before:"); 1.245 + } 1.246 + assert(!is_empty(), "shouldn't dequeue from empty list"); 1.247 + // Look down to the next barrier for a task with this affinity. 1.248 + GCTask* result = NULL; 1.249 + for (GCTask* element = remove_end(); 1.250 + element != NULL; 1.251 + element = element->newer()) { 1.252 + if (element->is_barrier_task()) { 1.253 + // Don't consider barrier tasks, nor past them. 1.254 + result = NULL; 1.255 + break; 1.256 + } 1.257 + if (element->affinity() == affinity) { 1.258 + result = remove(element); 1.259 + break; 1.260 + } 1.261 + } 1.262 + // If we didn't find anything with affinity, just take the next task. 1.263 + if (result == NULL) { 1.264 + result = remove(); 1.265 + } 1.266 + if (TraceGCTaskQueue) { 1.267 + tty->print_cr(" return: " INTPTR_FORMAT, result); 1.268 + print("after:"); 1.269 + } 1.270 + return result; 1.271 +} 1.272 + 1.273 +GCTask* GCTaskQueue::remove() { 1.274 + // Dequeue from remove end. 1.275 + GCTask* result = remove_end(); 1.276 + assert(result != NULL, "shouldn't have null task"); 1.277 + assert(result->older() == NULL, "not the remove_end"); 1.278 + set_remove_end(result->newer()); 1.279 + if (remove_end() == NULL) { 1.280 + assert(insert_end() == result, "not a singleton"); 1.281 + set_insert_end(NULL); 1.282 + } else { 1.283 + remove_end()->set_older(NULL); 1.284 + } 1.285 + result->set_newer(NULL); 1.286 + decrement_length(); 1.287 + assert(result->newer() == NULL, "shouldn't be on queue"); 1.288 + assert(result->older() == NULL, "shouldn't be on queue"); 1.289 + return result; 1.290 +} 1.291 + 1.292 +GCTask* GCTaskQueue::remove(GCTask* task) { 1.293 + // This is slightly more work, and has slightly fewer asserts 1.294 + // than removing from the remove end. 1.295 + assert(task != NULL, "shouldn't have null task"); 1.296 + GCTask* result = task; 1.297 + if (result->newer() != NULL) { 1.298 + result->newer()->set_older(result->older()); 1.299 + } else { 1.300 + assert(insert_end() == result, "not youngest"); 1.301 + set_insert_end(result->older()); 1.302 + } 1.303 + if (result->older() != NULL) { 1.304 + result->older()->set_newer(result->newer()); 1.305 + } else { 1.306 + assert(remove_end() == result, "not oldest"); 1.307 + set_remove_end(result->newer()); 1.308 + } 1.309 + result->set_newer(NULL); 1.310 + result->set_older(NULL); 1.311 + decrement_length(); 1.312 + return result; 1.313 +} 1.314 + 1.315 +NOT_PRODUCT( 1.316 +void GCTaskQueue::print(const char* message) const { 1.317 + tty->print_cr("[" INTPTR_FORMAT "] GCTaskQueue:" 1.318 + " insert_end: " INTPTR_FORMAT 1.319 + " remove_end: " INTPTR_FORMAT 1.320 + " %s", 1.321 + this, insert_end(), remove_end(), message); 1.322 + for (GCTask* element = insert_end(); 1.323 + element != NULL; 1.324 + element = element->older()) { 1.325 + element->print(" "); 1.326 + tty->cr(); 1.327 + } 1.328 +} 1.329 +) 1.330 + 1.331 +// 1.332 +// SynchronizedGCTaskQueue 1.333 +// 1.334 + 1.335 +SynchronizedGCTaskQueue::SynchronizedGCTaskQueue(GCTaskQueue* queue_arg, 1.336 + Monitor * lock_arg) : 1.337 + _unsynchronized_queue(queue_arg), 1.338 + _lock(lock_arg) { 1.339 + assert(unsynchronized_queue() != NULL, "null queue"); 1.340 + assert(lock() != NULL, "null lock"); 1.341 +} 1.342 + 1.343 +SynchronizedGCTaskQueue::~SynchronizedGCTaskQueue() { 1.344 + // Nothing to do. 1.345 +} 1.346 + 1.347 +// 1.348 +// GCTaskManager 1.349 +// 1.350 +GCTaskManager::GCTaskManager(uint workers) : 1.351 + _workers(workers), 1.352 + _ndc(NULL) { 1.353 + initialize(); 1.354 +} 1.355 + 1.356 +GCTaskManager::GCTaskManager(uint workers, NotifyDoneClosure* ndc) : 1.357 + _workers(workers), 1.358 + _ndc(ndc) { 1.359 + initialize(); 1.360 +} 1.361 + 1.362 +void GCTaskManager::initialize() { 1.363 + if (TraceGCTaskManager) { 1.364 + tty->print_cr("GCTaskManager::initialize: workers: %u", workers()); 1.365 + } 1.366 + assert(workers() != 0, "no workers"); 1.367 + _monitor = new Monitor(Mutex::barrier, // rank 1.368 + "GCTaskManager monitor", // name 1.369 + Mutex::_allow_vm_block_flag); // allow_vm_block 1.370 + // The queue for the GCTaskManager must be a CHeapObj. 1.371 + GCTaskQueue* unsynchronized_queue = GCTaskQueue::create_on_c_heap(); 1.372 + _queue = SynchronizedGCTaskQueue::create(unsynchronized_queue, lock()); 1.373 + _noop_task = NoopGCTask::create_on_c_heap(); 1.374 + _resource_flag = NEW_C_HEAP_ARRAY(bool, workers()); 1.375 + { 1.376 + // Set up worker threads. 1.377 + // Distribute the workers among the available processors, 1.378 + // unless we were told not to, or if the os doesn't want to. 1.379 + uint* processor_assignment = NEW_C_HEAP_ARRAY(uint, workers()); 1.380 + if (!BindGCTaskThreadsToCPUs || 1.381 + !os::distribute_processes(workers(), processor_assignment)) { 1.382 + for (uint a = 0; a < workers(); a += 1) { 1.383 + processor_assignment[a] = sentinel_worker(); 1.384 + } 1.385 + } 1.386 + _thread = NEW_C_HEAP_ARRAY(GCTaskThread*, workers()); 1.387 + for (uint t = 0; t < workers(); t += 1) { 1.388 + set_thread(t, GCTaskThread::create(this, t, processor_assignment[t])); 1.389 + } 1.390 + if (TraceGCTaskThread) { 1.391 + tty->print("GCTaskManager::initialize: distribution:"); 1.392 + for (uint t = 0; t < workers(); t += 1) { 1.393 + tty->print(" %u", processor_assignment[t]); 1.394 + } 1.395 + tty->cr(); 1.396 + } 1.397 + FREE_C_HEAP_ARRAY(uint, processor_assignment); 1.398 + } 1.399 + reset_busy_workers(); 1.400 + set_unblocked(); 1.401 + for (uint w = 0; w < workers(); w += 1) { 1.402 + set_resource_flag(w, false); 1.403 + } 1.404 + reset_delivered_tasks(); 1.405 + reset_completed_tasks(); 1.406 + reset_noop_tasks(); 1.407 + reset_barriers(); 1.408 + reset_emptied_queue(); 1.409 + for (uint s = 0; s < workers(); s += 1) { 1.410 + thread(s)->start(); 1.411 + } 1.412 +} 1.413 + 1.414 +GCTaskManager::~GCTaskManager() { 1.415 + assert(busy_workers() == 0, "still have busy workers"); 1.416 + assert(queue()->is_empty(), "still have queued work"); 1.417 + NoopGCTask::destroy(_noop_task); 1.418 + _noop_task = NULL; 1.419 + if (_thread != NULL) { 1.420 + for (uint i = 0; i < workers(); i += 1) { 1.421 + GCTaskThread::destroy(thread(i)); 1.422 + set_thread(i, NULL); 1.423 + } 1.424 + FREE_C_HEAP_ARRAY(GCTaskThread*, _thread); 1.425 + _thread = NULL; 1.426 + } 1.427 + if (_resource_flag != NULL) { 1.428 + FREE_C_HEAP_ARRAY(bool, _resource_flag); 1.429 + _resource_flag = NULL; 1.430 + } 1.431 + if (queue() != NULL) { 1.432 + GCTaskQueue* unsynchronized_queue = queue()->unsynchronized_queue(); 1.433 + GCTaskQueue::destroy(unsynchronized_queue); 1.434 + SynchronizedGCTaskQueue::destroy(queue()); 1.435 + _queue = NULL; 1.436 + } 1.437 + if (monitor() != NULL) { 1.438 + delete monitor(); 1.439 + _monitor = NULL; 1.440 + } 1.441 +} 1.442 + 1.443 +void GCTaskManager::print_task_time_stamps() { 1.444 + for(uint i=0; i<ParallelGCThreads; i++) { 1.445 + GCTaskThread* t = thread(i); 1.446 + t->print_task_time_stamps(); 1.447 + } 1.448 +} 1.449 + 1.450 +void GCTaskManager::print_threads_on(outputStream* st) { 1.451 + uint num_thr = workers(); 1.452 + for (uint i = 0; i < num_thr; i++) { 1.453 + thread(i)->print_on(st); 1.454 + st->cr(); 1.455 + } 1.456 +} 1.457 + 1.458 +void GCTaskManager::threads_do(ThreadClosure* tc) { 1.459 + assert(tc != NULL, "Null ThreadClosure"); 1.460 + uint num_thr = workers(); 1.461 + for (uint i = 0; i < num_thr; i++) { 1.462 + tc->do_thread(thread(i)); 1.463 + } 1.464 +} 1.465 + 1.466 +GCTaskThread* GCTaskManager::thread(uint which) { 1.467 + assert(which < workers(), "index out of bounds"); 1.468 + assert(_thread[which] != NULL, "shouldn't have null thread"); 1.469 + return _thread[which]; 1.470 +} 1.471 + 1.472 +void GCTaskManager::set_thread(uint which, GCTaskThread* value) { 1.473 + assert(which < workers(), "index out of bounds"); 1.474 + assert(value != NULL, "shouldn't have null thread"); 1.475 + _thread[which] = value; 1.476 +} 1.477 + 1.478 +void GCTaskManager::add_task(GCTask* task) { 1.479 + assert(task != NULL, "shouldn't have null task"); 1.480 + MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); 1.481 + if (TraceGCTaskManager) { 1.482 + tty->print_cr("GCTaskManager::add_task(" INTPTR_FORMAT " [%s])", 1.483 + task, GCTask::Kind::to_string(task->kind())); 1.484 + } 1.485 + queue()->enqueue(task); 1.486 + // Notify with the lock held to avoid missed notifies. 1.487 + if (TraceGCTaskManager) { 1.488 + tty->print_cr(" GCTaskManager::add_task (%s)->notify_all", 1.489 + monitor()->name()); 1.490 + } 1.491 + (void) monitor()->notify_all(); 1.492 + // Release monitor(). 1.493 +} 1.494 + 1.495 +void GCTaskManager::add_list(GCTaskQueue* list) { 1.496 + assert(list != NULL, "shouldn't have null task"); 1.497 + MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); 1.498 + if (TraceGCTaskManager) { 1.499 + tty->print_cr("GCTaskManager::add_list(%u)", list->length()); 1.500 + } 1.501 + queue()->enqueue(list); 1.502 + // Notify with the lock held to avoid missed notifies. 1.503 + if (TraceGCTaskManager) { 1.504 + tty->print_cr(" GCTaskManager::add_list (%s)->notify_all", 1.505 + monitor()->name()); 1.506 + } 1.507 + (void) monitor()->notify_all(); 1.508 + // Release monitor(). 1.509 +} 1.510 + 1.511 +GCTask* GCTaskManager::get_task(uint which) { 1.512 + GCTask* result = NULL; 1.513 + // Grab the queue lock. 1.514 + MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); 1.515 + // Wait while the queue is block or 1.516 + // there is nothing to do, except maybe release resources. 1.517 + while (is_blocked() || 1.518 + (queue()->is_empty() && !should_release_resources(which))) { 1.519 + if (TraceGCTaskManager) { 1.520 + tty->print_cr("GCTaskManager::get_task(%u)" 1.521 + " blocked: %s" 1.522 + " empty: %s" 1.523 + " release: %s", 1.524 + which, 1.525 + is_blocked() ? "true" : "false", 1.526 + queue()->is_empty() ? "true" : "false", 1.527 + should_release_resources(which) ? "true" : "false"); 1.528 + tty->print_cr(" => (%s)->wait()", 1.529 + monitor()->name()); 1.530 + } 1.531 + monitor()->wait(Mutex::_no_safepoint_check_flag, 0); 1.532 + } 1.533 + // We've reacquired the queue lock here. 1.534 + // Figure out which condition caused us to exit the loop above. 1.535 + if (!queue()->is_empty()) { 1.536 + if (UseGCTaskAffinity) { 1.537 + result = queue()->dequeue(which); 1.538 + } else { 1.539 + result = queue()->dequeue(); 1.540 + } 1.541 + if (result->is_barrier_task()) { 1.542 + assert(which != sentinel_worker(), 1.543 + "blocker shouldn't be bogus"); 1.544 + set_blocking_worker(which); 1.545 + } 1.546 + } else { 1.547 + // The queue is empty, but we were woken up. 1.548 + // Just hand back a Noop task, 1.549 + // in case someone wanted us to release resources, or whatever. 1.550 + result = noop_task(); 1.551 + increment_noop_tasks(); 1.552 + } 1.553 + assert(result != NULL, "shouldn't have null task"); 1.554 + if (TraceGCTaskManager) { 1.555 + tty->print_cr("GCTaskManager::get_task(%u) => " INTPTR_FORMAT " [%s]", 1.556 + which, result, GCTask::Kind::to_string(result->kind())); 1.557 + tty->print_cr(" %s", result->name()); 1.558 + } 1.559 + increment_busy_workers(); 1.560 + increment_delivered_tasks(); 1.561 + return result; 1.562 + // Release monitor(). 1.563 +} 1.564 + 1.565 +void GCTaskManager::note_completion(uint which) { 1.566 + MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); 1.567 + if (TraceGCTaskManager) { 1.568 + tty->print_cr("GCTaskManager::note_completion(%u)", which); 1.569 + } 1.570 + // If we are blocked, check if the completing thread is the blocker. 1.571 + if (blocking_worker() == which) { 1.572 + assert(blocking_worker() != sentinel_worker(), 1.573 + "blocker shouldn't be bogus"); 1.574 + increment_barriers(); 1.575 + set_unblocked(); 1.576 + } 1.577 + increment_completed_tasks(); 1.578 + uint active = decrement_busy_workers(); 1.579 + if ((active == 0) && (queue()->is_empty())) { 1.580 + increment_emptied_queue(); 1.581 + if (TraceGCTaskManager) { 1.582 + tty->print_cr(" GCTaskManager::note_completion(%u) done", which); 1.583 + } 1.584 + // Notify client that we are done. 1.585 + NotifyDoneClosure* ndc = notify_done_closure(); 1.586 + if (ndc != NULL) { 1.587 + ndc->notify(this); 1.588 + } 1.589 + } 1.590 + if (TraceGCTaskManager) { 1.591 + tty->print_cr(" GCTaskManager::note_completion(%u) (%s)->notify_all", 1.592 + which, monitor()->name()); 1.593 + tty->print_cr(" " 1.594 + " blocked: %s" 1.595 + " empty: %s" 1.596 + " release: %s", 1.597 + is_blocked() ? "true" : "false", 1.598 + queue()->is_empty() ? "true" : "false", 1.599 + should_release_resources(which) ? "true" : "false"); 1.600 + tty->print_cr(" " 1.601 + " delivered: %u" 1.602 + " completed: %u" 1.603 + " barriers: %u" 1.604 + " emptied: %u", 1.605 + delivered_tasks(), 1.606 + completed_tasks(), 1.607 + barriers(), 1.608 + emptied_queue()); 1.609 + } 1.610 + // Tell everyone that a task has completed. 1.611 + (void) monitor()->notify_all(); 1.612 + // Release monitor(). 1.613 +} 1.614 + 1.615 +uint GCTaskManager::increment_busy_workers() { 1.616 + assert(queue()->own_lock(), "don't own the lock"); 1.617 + _busy_workers += 1; 1.618 + return _busy_workers; 1.619 +} 1.620 + 1.621 +uint GCTaskManager::decrement_busy_workers() { 1.622 + assert(queue()->own_lock(), "don't own the lock"); 1.623 + _busy_workers -= 1; 1.624 + return _busy_workers; 1.625 +} 1.626 + 1.627 +void GCTaskManager::release_all_resources() { 1.628 + // If you want this to be done atomically, do it in a BarrierGCTask. 1.629 + for (uint i = 0; i < workers(); i += 1) { 1.630 + set_resource_flag(i, true); 1.631 + } 1.632 +} 1.633 + 1.634 +bool GCTaskManager::should_release_resources(uint which) { 1.635 + // This can be done without a lock because each thread reads one element. 1.636 + return resource_flag(which); 1.637 +} 1.638 + 1.639 +void GCTaskManager::note_release(uint which) { 1.640 + // This can be done without a lock because each thread writes one element. 1.641 + set_resource_flag(which, false); 1.642 +} 1.643 + 1.644 +void GCTaskManager::execute_and_wait(GCTaskQueue* list) { 1.645 + WaitForBarrierGCTask* fin = WaitForBarrierGCTask::create(); 1.646 + list->enqueue(fin); 1.647 + add_list(list); 1.648 + fin->wait_for(); 1.649 + // We have to release the barrier tasks! 1.650 + WaitForBarrierGCTask::destroy(fin); 1.651 +} 1.652 + 1.653 +bool GCTaskManager::resource_flag(uint which) { 1.654 + assert(which < workers(), "index out of bounds"); 1.655 + return _resource_flag[which]; 1.656 +} 1.657 + 1.658 +void GCTaskManager::set_resource_flag(uint which, bool value) { 1.659 + assert(which < workers(), "index out of bounds"); 1.660 + _resource_flag[which] = value; 1.661 +} 1.662 + 1.663 +// 1.664 +// NoopGCTask 1.665 +// 1.666 + 1.667 +NoopGCTask* NoopGCTask::create() { 1.668 + NoopGCTask* result = new NoopGCTask(false); 1.669 + return result; 1.670 +} 1.671 + 1.672 +NoopGCTask* NoopGCTask::create_on_c_heap() { 1.673 + NoopGCTask* result = new(ResourceObj::C_HEAP) NoopGCTask(true); 1.674 + return result; 1.675 +} 1.676 + 1.677 +void NoopGCTask::destroy(NoopGCTask* that) { 1.678 + if (that != NULL) { 1.679 + that->destruct(); 1.680 + if (that->is_c_heap_obj()) { 1.681 + FreeHeap(that); 1.682 + } 1.683 + } 1.684 +} 1.685 + 1.686 +void NoopGCTask::destruct() { 1.687 + // This has to know it's superclass structure, just like the constructor. 1.688 + this->GCTask::destruct(); 1.689 + // Nothing else to do. 1.690 +} 1.691 + 1.692 +// 1.693 +// BarrierGCTask 1.694 +// 1.695 + 1.696 +void BarrierGCTask::do_it(GCTaskManager* manager, uint which) { 1.697 + // Wait for this to be the only busy worker. 1.698 + // ??? I thought of having a StackObj class 1.699 + // whose constructor would grab the lock and come to the barrier, 1.700 + // and whose destructor would release the lock, 1.701 + // but that seems like too much mechanism for two lines of code. 1.702 + MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); 1.703 + do_it_internal(manager, which); 1.704 + // Release manager->lock(). 1.705 +} 1.706 + 1.707 +void BarrierGCTask::do_it_internal(GCTaskManager* manager, uint which) { 1.708 + // Wait for this to be the only busy worker. 1.709 + assert(manager->monitor()->owned_by_self(), "don't own the lock"); 1.710 + assert(manager->is_blocked(), "manager isn't blocked"); 1.711 + while (manager->busy_workers() > 1) { 1.712 + if (TraceGCTaskManager) { 1.713 + tty->print_cr("BarrierGCTask::do_it(%u) waiting on %u workers", 1.714 + which, manager->busy_workers()); 1.715 + } 1.716 + manager->monitor()->wait(Mutex::_no_safepoint_check_flag, 0); 1.717 + } 1.718 +} 1.719 + 1.720 +void BarrierGCTask::destruct() { 1.721 + this->GCTask::destruct(); 1.722 + // Nothing else to do. 1.723 +} 1.724 + 1.725 +// 1.726 +// ReleasingBarrierGCTask 1.727 +// 1.728 + 1.729 +void ReleasingBarrierGCTask::do_it(GCTaskManager* manager, uint which) { 1.730 + MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); 1.731 + do_it_internal(manager, which); 1.732 + manager->release_all_resources(); 1.733 + // Release manager->lock(). 1.734 +} 1.735 + 1.736 +void ReleasingBarrierGCTask::destruct() { 1.737 + this->BarrierGCTask::destruct(); 1.738 + // Nothing else to do. 1.739 +} 1.740 + 1.741 +// 1.742 +// NotifyingBarrierGCTask 1.743 +// 1.744 + 1.745 +void NotifyingBarrierGCTask::do_it(GCTaskManager* manager, uint which) { 1.746 + MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); 1.747 + do_it_internal(manager, which); 1.748 + NotifyDoneClosure* ndc = notify_done_closure(); 1.749 + if (ndc != NULL) { 1.750 + ndc->notify(manager); 1.751 + } 1.752 + // Release manager->lock(). 1.753 +} 1.754 + 1.755 +void NotifyingBarrierGCTask::destruct() { 1.756 + this->BarrierGCTask::destruct(); 1.757 + // Nothing else to do. 1.758 +} 1.759 + 1.760 +// 1.761 +// WaitForBarrierGCTask 1.762 +// 1.763 +WaitForBarrierGCTask* WaitForBarrierGCTask::create() { 1.764 + WaitForBarrierGCTask* result = new WaitForBarrierGCTask(false); 1.765 + return result; 1.766 +} 1.767 + 1.768 +WaitForBarrierGCTask* WaitForBarrierGCTask::create_on_c_heap() { 1.769 + WaitForBarrierGCTask* result = new WaitForBarrierGCTask(true); 1.770 + return result; 1.771 +} 1.772 + 1.773 +WaitForBarrierGCTask::WaitForBarrierGCTask(bool on_c_heap) : 1.774 + _is_c_heap_obj(on_c_heap) { 1.775 + _monitor = MonitorSupply::reserve(); 1.776 + set_should_wait(true); 1.777 + if (TraceGCTaskManager) { 1.778 + tty->print_cr("[" INTPTR_FORMAT "]" 1.779 + " WaitForBarrierGCTask::WaitForBarrierGCTask()" 1.780 + " monitor: " INTPTR_FORMAT, 1.781 + this, monitor()); 1.782 + } 1.783 +} 1.784 + 1.785 +void WaitForBarrierGCTask::destroy(WaitForBarrierGCTask* that) { 1.786 + if (that != NULL) { 1.787 + if (TraceGCTaskManager) { 1.788 + tty->print_cr("[" INTPTR_FORMAT "]" 1.789 + " WaitForBarrierGCTask::destroy()" 1.790 + " is_c_heap_obj: %s" 1.791 + " monitor: " INTPTR_FORMAT, 1.792 + that, 1.793 + that->is_c_heap_obj() ? "true" : "false", 1.794 + that->monitor()); 1.795 + } 1.796 + that->destruct(); 1.797 + if (that->is_c_heap_obj()) { 1.798 + FreeHeap(that); 1.799 + } 1.800 + } 1.801 +} 1.802 + 1.803 +void WaitForBarrierGCTask::destruct() { 1.804 + assert(monitor() != NULL, "monitor should not be NULL"); 1.805 + if (TraceGCTaskManager) { 1.806 + tty->print_cr("[" INTPTR_FORMAT "]" 1.807 + " WaitForBarrierGCTask::destruct()" 1.808 + " monitor: " INTPTR_FORMAT, 1.809 + this, monitor()); 1.810 + } 1.811 + this->BarrierGCTask::destruct(); 1.812 + // Clean up that should be in the destructor, 1.813 + // except that ResourceMarks don't call destructors. 1.814 + if (monitor() != NULL) { 1.815 + MonitorSupply::release(monitor()); 1.816 + } 1.817 + _monitor = (Monitor*) 0xDEAD000F; 1.818 +} 1.819 + 1.820 +void WaitForBarrierGCTask::do_it(GCTaskManager* manager, uint which) { 1.821 + if (TraceGCTaskManager) { 1.822 + tty->print_cr("[" INTPTR_FORMAT "]" 1.823 + " WaitForBarrierGCTask::do_it() waiting for idle" 1.824 + " monitor: " INTPTR_FORMAT, 1.825 + this, monitor()); 1.826 + } 1.827 + { 1.828 + // First, wait for the barrier to arrive. 1.829 + MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); 1.830 + do_it_internal(manager, which); 1.831 + // Release manager->lock(). 1.832 + } 1.833 + { 1.834 + // Then notify the waiter. 1.835 + MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); 1.836 + set_should_wait(false); 1.837 + // Waiter doesn't miss the notify in the wait_for method 1.838 + // since it checks the flag after grabbing the monitor. 1.839 + if (TraceGCTaskManager) { 1.840 + tty->print_cr("[" INTPTR_FORMAT "]" 1.841 + " WaitForBarrierGCTask::do_it()" 1.842 + " [" INTPTR_FORMAT "] (%s)->notify_all()", 1.843 + this, monitor(), monitor()->name()); 1.844 + } 1.845 + monitor()->notify_all(); 1.846 + // Release monitor(). 1.847 + } 1.848 +} 1.849 + 1.850 +void WaitForBarrierGCTask::wait_for() { 1.851 + if (TraceGCTaskManager) { 1.852 + tty->print_cr("[" INTPTR_FORMAT "]" 1.853 + " WaitForBarrierGCTask::wait_for()" 1.854 + " should_wait: %s", 1.855 + this, should_wait() ? "true" : "false"); 1.856 + } 1.857 + { 1.858 + // Grab the lock and check again. 1.859 + MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); 1.860 + while (should_wait()) { 1.861 + if (TraceGCTaskManager) { 1.862 + tty->print_cr("[" INTPTR_FORMAT "]" 1.863 + " WaitForBarrierGCTask::wait_for()" 1.864 + " [" INTPTR_FORMAT "] (%s)->wait()", 1.865 + this, monitor(), monitor()->name()); 1.866 + } 1.867 + monitor()->wait(Mutex::_no_safepoint_check_flag, 0); 1.868 + } 1.869 + // Reset the flag in case someone reuses this task. 1.870 + set_should_wait(true); 1.871 + if (TraceGCTaskManager) { 1.872 + tty->print_cr("[" INTPTR_FORMAT "]" 1.873 + " WaitForBarrierGCTask::wait_for() returns" 1.874 + " should_wait: %s", 1.875 + this, should_wait() ? "true" : "false"); 1.876 + } 1.877 + // Release monitor(). 1.878 + } 1.879 +} 1.880 + 1.881 +Mutex* MonitorSupply::_lock = NULL; 1.882 +GrowableArray<Monitor*>* MonitorSupply::_freelist = NULL; 1.883 + 1.884 +Monitor* MonitorSupply::reserve() { 1.885 + Monitor* result = NULL; 1.886 + // Lazy initialization: possible race. 1.887 + if (lock() == NULL) { 1.888 + _lock = new Mutex(Mutex::barrier, // rank 1.889 + "MonitorSupply mutex", // name 1.890 + Mutex::_allow_vm_block_flag); // allow_vm_block 1.891 + } 1.892 + { 1.893 + MutexLockerEx ml(lock()); 1.894 + // Lazy initialization. 1.895 + if (freelist() == NULL) { 1.896 + _freelist = 1.897 + new(ResourceObj::C_HEAP) GrowableArray<Monitor*>(ParallelGCThreads, 1.898 + true); 1.899 + } 1.900 + if (! freelist()->is_empty()) { 1.901 + result = freelist()->pop(); 1.902 + } else { 1.903 + result = new Monitor(Mutex::barrier, // rank 1.904 + "MonitorSupply monitor", // name 1.905 + Mutex::_allow_vm_block_flag); // allow_vm_block 1.906 + } 1.907 + guarantee(result != NULL, "shouldn't return NULL"); 1.908 + assert(!result->is_locked(), "shouldn't be locked"); 1.909 + // release lock(). 1.910 + } 1.911 + return result; 1.912 +} 1.913 + 1.914 +void MonitorSupply::release(Monitor* instance) { 1.915 + assert(instance != NULL, "shouldn't release NULL"); 1.916 + assert(!instance->is_locked(), "shouldn't be locked"); 1.917 + { 1.918 + MutexLockerEx ml(lock()); 1.919 + freelist()->push(instance); 1.920 + // release lock(). 1.921 + } 1.922 +}