1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/vm/gc_implementation/parallelScavenge/gcTaskManager.cpp Wed Apr 27 01:25:04 2016 +0800 1.3 @@ -0,0 +1,1144 @@ 1.4 +/* 1.5 + * Copyright (c) 2002, 2014, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 1.23 + * or visit www.oracle.com if you need additional information or have any 1.24 + * questions. 1.25 + * 1.26 + */ 1.27 + 1.28 +#include "precompiled.hpp" 1.29 +#include "gc_implementation/parallelScavenge/gcTaskManager.hpp" 1.30 +#include "gc_implementation/parallelScavenge/gcTaskThread.hpp" 1.31 +#include "gc_implementation/shared/adaptiveSizePolicy.hpp" 1.32 +#include "memory/allocation.hpp" 1.33 +#include "memory/allocation.inline.hpp" 1.34 +#include "runtime/mutex.hpp" 1.35 +#include "runtime/mutexLocker.hpp" 1.36 + 1.37 +PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC 1.38 + 1.39 +// 1.40 +// GCTask 1.41 +// 1.42 + 1.43 +const char* GCTask::Kind::to_string(kind value) { 1.44 + const char* result = "unknown GCTask kind"; 1.45 + switch (value) { 1.46 + default: 1.47 + result = "unknown GCTask kind"; 1.48 + break; 1.49 + case unknown_task: 1.50 + result = "unknown task"; 1.51 + break; 1.52 + case ordinary_task: 1.53 + result = "ordinary task"; 1.54 + break; 1.55 + case barrier_task: 1.56 + result = "barrier task"; 1.57 + break; 1.58 + case noop_task: 1.59 + result = "noop task"; 1.60 + break; 1.61 + case idle_task: 1.62 + result = "idle task"; 1.63 + break; 1.64 + } 1.65 + return result; 1.66 +}; 1.67 + 1.68 +GCTask::GCTask() : 1.69 + _kind(Kind::ordinary_task), 1.70 + _affinity(GCTaskManager::sentinel_worker()){ 1.71 + initialize(); 1.72 +} 1.73 + 1.74 +GCTask::GCTask(Kind::kind kind) : 1.75 + _kind(kind), 1.76 + _affinity(GCTaskManager::sentinel_worker()) { 1.77 + initialize(); 1.78 +} 1.79 + 1.80 +GCTask::GCTask(uint affinity) : 1.81 + _kind(Kind::ordinary_task), 1.82 + _affinity(affinity) { 1.83 + initialize(); 1.84 +} 1.85 + 1.86 +GCTask::GCTask(Kind::kind kind, uint affinity) : 1.87 + _kind(kind), 1.88 + _affinity(affinity) { 1.89 + initialize(); 1.90 +} 1.91 + 1.92 +void GCTask::initialize() { 1.93 + _older = NULL; 1.94 + _newer = NULL; 1.95 +} 1.96 + 1.97 +void GCTask::destruct() { 1.98 + assert(older() == NULL, "shouldn't have an older task"); 1.99 + assert(newer() == NULL, "shouldn't have a newer task"); 1.100 + // Nothing to do. 1.101 +} 1.102 + 1.103 +NOT_PRODUCT( 1.104 +void GCTask::print(const char* message) const { 1.105 + tty->print(INTPTR_FORMAT " <- " INTPTR_FORMAT "(%u) -> " INTPTR_FORMAT, 1.106 + newer(), this, affinity(), older()); 1.107 +} 1.108 +) 1.109 + 1.110 +// 1.111 +// GCTaskQueue 1.112 +// 1.113 + 1.114 +GCTaskQueue* GCTaskQueue::create() { 1.115 + GCTaskQueue* result = new GCTaskQueue(false); 1.116 + if (TraceGCTaskQueue) { 1.117 + tty->print_cr("GCTaskQueue::create()" 1.118 + " returns " INTPTR_FORMAT, result); 1.119 + } 1.120 + return result; 1.121 +} 1.122 + 1.123 +GCTaskQueue* GCTaskQueue::create_on_c_heap() { 1.124 + GCTaskQueue* result = new(ResourceObj::C_HEAP, mtGC) GCTaskQueue(true); 1.125 + if (TraceGCTaskQueue) { 1.126 + tty->print_cr("GCTaskQueue::create_on_c_heap()" 1.127 + " returns " INTPTR_FORMAT, 1.128 + result); 1.129 + } 1.130 + return result; 1.131 +} 1.132 + 1.133 +GCTaskQueue::GCTaskQueue(bool on_c_heap) : 1.134 + _is_c_heap_obj(on_c_heap) { 1.135 + initialize(); 1.136 + if (TraceGCTaskQueue) { 1.137 + tty->print_cr("[" INTPTR_FORMAT "]" 1.138 + " GCTaskQueue::GCTaskQueue() constructor", 1.139 + this); 1.140 + } 1.141 +} 1.142 + 1.143 +void GCTaskQueue::destruct() { 1.144 + // Nothing to do. 1.145 +} 1.146 + 1.147 +void GCTaskQueue::destroy(GCTaskQueue* that) { 1.148 + if (TraceGCTaskQueue) { 1.149 + tty->print_cr("[" INTPTR_FORMAT "]" 1.150 + " GCTaskQueue::destroy()" 1.151 + " is_c_heap_obj: %s", 1.152 + that, 1.153 + that->is_c_heap_obj() ? "true" : "false"); 1.154 + } 1.155 + // That instance may have been allocated as a CHeapObj, 1.156 + // in which case we have to free it explicitly. 1.157 + if (that != NULL) { 1.158 + that->destruct(); 1.159 + assert(that->is_empty(), "should be empty"); 1.160 + if (that->is_c_heap_obj()) { 1.161 + FreeHeap(that); 1.162 + } 1.163 + } 1.164 +} 1.165 + 1.166 +void GCTaskQueue::initialize() { 1.167 + set_insert_end(NULL); 1.168 + set_remove_end(NULL); 1.169 + set_length(0); 1.170 +} 1.171 + 1.172 +// Enqueue one task. 1.173 +void GCTaskQueue::enqueue(GCTask* task) { 1.174 + if (TraceGCTaskQueue) { 1.175 + tty->print_cr("[" INTPTR_FORMAT "]" 1.176 + " GCTaskQueue::enqueue(task: " 1.177 + INTPTR_FORMAT ")", 1.178 + this, task); 1.179 + print("before:"); 1.180 + } 1.181 + assert(task != NULL, "shouldn't have null task"); 1.182 + assert(task->older() == NULL, "shouldn't be on queue"); 1.183 + assert(task->newer() == NULL, "shouldn't be on queue"); 1.184 + task->set_newer(NULL); 1.185 + task->set_older(insert_end()); 1.186 + if (is_empty()) { 1.187 + set_remove_end(task); 1.188 + } else { 1.189 + insert_end()->set_newer(task); 1.190 + } 1.191 + set_insert_end(task); 1.192 + increment_length(); 1.193 + verify_length(); 1.194 + if (TraceGCTaskQueue) { 1.195 + print("after:"); 1.196 + } 1.197 +} 1.198 + 1.199 +// Enqueue a whole list of tasks. Empties the argument list. 1.200 +void GCTaskQueue::enqueue(GCTaskQueue* list) { 1.201 + if (TraceGCTaskQueue) { 1.202 + tty->print_cr("[" INTPTR_FORMAT "]" 1.203 + " GCTaskQueue::enqueue(list: " 1.204 + INTPTR_FORMAT ")", 1.205 + this, list); 1.206 + print("before:"); 1.207 + list->print("list:"); 1.208 + } 1.209 + if (list->is_empty()) { 1.210 + // Enqueuing the empty list: nothing to do. 1.211 + return; 1.212 + } 1.213 + uint list_length = list->length(); 1.214 + if (is_empty()) { 1.215 + // Enqueuing to empty list: just acquire elements. 1.216 + set_insert_end(list->insert_end()); 1.217 + set_remove_end(list->remove_end()); 1.218 + set_length(list_length); 1.219 + } else { 1.220 + // Prepend argument list to our queue. 1.221 + list->remove_end()->set_older(insert_end()); 1.222 + insert_end()->set_newer(list->remove_end()); 1.223 + set_insert_end(list->insert_end()); 1.224 + set_length(length() + list_length); 1.225 + // empty the argument list. 1.226 + } 1.227 + list->initialize(); 1.228 + if (TraceGCTaskQueue) { 1.229 + print("after:"); 1.230 + list->print("list:"); 1.231 + } 1.232 + verify_length(); 1.233 +} 1.234 + 1.235 +// Dequeue one task. 1.236 +GCTask* GCTaskQueue::dequeue() { 1.237 + if (TraceGCTaskQueue) { 1.238 + tty->print_cr("[" INTPTR_FORMAT "]" 1.239 + " GCTaskQueue::dequeue()", this); 1.240 + print("before:"); 1.241 + } 1.242 + assert(!is_empty(), "shouldn't dequeue from empty list"); 1.243 + GCTask* result = remove(); 1.244 + assert(result != NULL, "shouldn't have NULL task"); 1.245 + if (TraceGCTaskQueue) { 1.246 + tty->print_cr(" return: " INTPTR_FORMAT, result); 1.247 + print("after:"); 1.248 + } 1.249 + return result; 1.250 +} 1.251 + 1.252 +// Dequeue one task, preferring one with affinity. 1.253 +GCTask* GCTaskQueue::dequeue(uint affinity) { 1.254 + if (TraceGCTaskQueue) { 1.255 + tty->print_cr("[" INTPTR_FORMAT "]" 1.256 + " GCTaskQueue::dequeue(%u)", this, affinity); 1.257 + print("before:"); 1.258 + } 1.259 + assert(!is_empty(), "shouldn't dequeue from empty list"); 1.260 + // Look down to the next barrier for a task with this affinity. 1.261 + GCTask* result = NULL; 1.262 + for (GCTask* element = remove_end(); 1.263 + element != NULL; 1.264 + element = element->newer()) { 1.265 + if (element->is_barrier_task()) { 1.266 + // Don't consider barrier tasks, nor past them. 1.267 + result = NULL; 1.268 + break; 1.269 + } 1.270 + if (element->affinity() == affinity) { 1.271 + result = remove(element); 1.272 + break; 1.273 + } 1.274 + } 1.275 + // If we didn't find anything with affinity, just take the next task. 1.276 + if (result == NULL) { 1.277 + result = remove(); 1.278 + } 1.279 + if (TraceGCTaskQueue) { 1.280 + tty->print_cr(" return: " INTPTR_FORMAT, result); 1.281 + print("after:"); 1.282 + } 1.283 + return result; 1.284 +} 1.285 + 1.286 +GCTask* GCTaskQueue::remove() { 1.287 + // Dequeue from remove end. 1.288 + GCTask* result = remove_end(); 1.289 + assert(result != NULL, "shouldn't have null task"); 1.290 + assert(result->older() == NULL, "not the remove_end"); 1.291 + set_remove_end(result->newer()); 1.292 + if (remove_end() == NULL) { 1.293 + assert(insert_end() == result, "not a singleton"); 1.294 + set_insert_end(NULL); 1.295 + } else { 1.296 + remove_end()->set_older(NULL); 1.297 + } 1.298 + result->set_newer(NULL); 1.299 + decrement_length(); 1.300 + assert(result->newer() == NULL, "shouldn't be on queue"); 1.301 + assert(result->older() == NULL, "shouldn't be on queue"); 1.302 + verify_length(); 1.303 + return result; 1.304 +} 1.305 + 1.306 +GCTask* GCTaskQueue::remove(GCTask* task) { 1.307 + // This is slightly more work, and has slightly fewer asserts 1.308 + // than removing from the remove end. 1.309 + assert(task != NULL, "shouldn't have null task"); 1.310 + GCTask* result = task; 1.311 + if (result->newer() != NULL) { 1.312 + result->newer()->set_older(result->older()); 1.313 + } else { 1.314 + assert(insert_end() == result, "not youngest"); 1.315 + set_insert_end(result->older()); 1.316 + } 1.317 + if (result->older() != NULL) { 1.318 + result->older()->set_newer(result->newer()); 1.319 + } else { 1.320 + assert(remove_end() == result, "not oldest"); 1.321 + set_remove_end(result->newer()); 1.322 + } 1.323 + result->set_newer(NULL); 1.324 + result->set_older(NULL); 1.325 + decrement_length(); 1.326 + verify_length(); 1.327 + return result; 1.328 +} 1.329 + 1.330 +NOT_PRODUCT( 1.331 +// Count the elements in the queue and verify the length against 1.332 +// that count. 1.333 +void GCTaskQueue::verify_length() const { 1.334 + uint count = 0; 1.335 + for (GCTask* element = insert_end(); 1.336 + element != NULL; 1.337 + element = element->older()) { 1.338 + 1.339 + count++; 1.340 + } 1.341 + assert(count == length(), "Length does not match queue"); 1.342 +} 1.343 + 1.344 +void GCTaskQueue::print(const char* message) const { 1.345 + tty->print_cr("[" INTPTR_FORMAT "] GCTaskQueue:" 1.346 + " insert_end: " INTPTR_FORMAT 1.347 + " remove_end: " INTPTR_FORMAT 1.348 + " length: %d" 1.349 + " %s", 1.350 + this, insert_end(), remove_end(), length(), message); 1.351 + uint count = 0; 1.352 + for (GCTask* element = insert_end(); 1.353 + element != NULL; 1.354 + element = element->older()) { 1.355 + element->print(" "); 1.356 + count++; 1.357 + tty->cr(); 1.358 + } 1.359 + tty->print("Total tasks: %d", count); 1.360 +} 1.361 +) 1.362 + 1.363 +// 1.364 +// SynchronizedGCTaskQueue 1.365 +// 1.366 + 1.367 +SynchronizedGCTaskQueue::SynchronizedGCTaskQueue(GCTaskQueue* queue_arg, 1.368 + Monitor * lock_arg) : 1.369 + _unsynchronized_queue(queue_arg), 1.370 + _lock(lock_arg) { 1.371 + assert(unsynchronized_queue() != NULL, "null queue"); 1.372 + assert(lock() != NULL, "null lock"); 1.373 +} 1.374 + 1.375 +SynchronizedGCTaskQueue::~SynchronizedGCTaskQueue() { 1.376 + // Nothing to do. 1.377 +} 1.378 + 1.379 +// 1.380 +// GCTaskManager 1.381 +// 1.382 +GCTaskManager::GCTaskManager(uint workers) : 1.383 + _workers(workers), 1.384 + _active_workers(0), 1.385 + _idle_workers(0), 1.386 + _ndc(NULL) { 1.387 + initialize(); 1.388 +} 1.389 + 1.390 +GCTaskManager::GCTaskManager(uint workers, NotifyDoneClosure* ndc) : 1.391 + _workers(workers), 1.392 + _active_workers(0), 1.393 + _idle_workers(0), 1.394 + _ndc(ndc) { 1.395 + initialize(); 1.396 +} 1.397 + 1.398 +void GCTaskManager::initialize() { 1.399 + if (TraceGCTaskManager) { 1.400 + tty->print_cr("GCTaskManager::initialize: workers: %u", workers()); 1.401 + } 1.402 + assert(workers() != 0, "no workers"); 1.403 + _monitor = new Monitor(Mutex::barrier, // rank 1.404 + "GCTaskManager monitor", // name 1.405 + Mutex::_allow_vm_block_flag); // allow_vm_block 1.406 + // The queue for the GCTaskManager must be a CHeapObj. 1.407 + GCTaskQueue* unsynchronized_queue = GCTaskQueue::create_on_c_heap(); 1.408 + _queue = SynchronizedGCTaskQueue::create(unsynchronized_queue, lock()); 1.409 + _noop_task = NoopGCTask::create_on_c_heap(); 1.410 + _idle_inactive_task = WaitForBarrierGCTask::create_on_c_heap(); 1.411 + _resource_flag = NEW_C_HEAP_ARRAY(bool, workers(), mtGC); 1.412 + { 1.413 + // Set up worker threads. 1.414 + // Distribute the workers among the available processors, 1.415 + // unless we were told not to, or if the os doesn't want to. 1.416 + uint* processor_assignment = NEW_C_HEAP_ARRAY(uint, workers(), mtGC); 1.417 + if (!BindGCTaskThreadsToCPUs || 1.418 + !os::distribute_processes(workers(), processor_assignment)) { 1.419 + for (uint a = 0; a < workers(); a += 1) { 1.420 + processor_assignment[a] = sentinel_worker(); 1.421 + } 1.422 + } 1.423 + _thread = NEW_C_HEAP_ARRAY(GCTaskThread*, workers(), mtGC); 1.424 + for (uint t = 0; t < workers(); t += 1) { 1.425 + set_thread(t, GCTaskThread::create(this, t, processor_assignment[t])); 1.426 + } 1.427 + if (TraceGCTaskThread) { 1.428 + tty->print("GCTaskManager::initialize: distribution:"); 1.429 + for (uint t = 0; t < workers(); t += 1) { 1.430 + tty->print(" %u", processor_assignment[t]); 1.431 + } 1.432 + tty->cr(); 1.433 + } 1.434 + FREE_C_HEAP_ARRAY(uint, processor_assignment, mtGC); 1.435 + } 1.436 + reset_busy_workers(); 1.437 + set_unblocked(); 1.438 + for (uint w = 0; w < workers(); w += 1) { 1.439 + set_resource_flag(w, false); 1.440 + } 1.441 + reset_delivered_tasks(); 1.442 + reset_completed_tasks(); 1.443 + reset_noop_tasks(); 1.444 + reset_barriers(); 1.445 + reset_emptied_queue(); 1.446 + for (uint s = 0; s < workers(); s += 1) { 1.447 + thread(s)->start(); 1.448 + } 1.449 +} 1.450 + 1.451 +GCTaskManager::~GCTaskManager() { 1.452 + assert(busy_workers() == 0, "still have busy workers"); 1.453 + assert(queue()->is_empty(), "still have queued work"); 1.454 + NoopGCTask::destroy(_noop_task); 1.455 + _noop_task = NULL; 1.456 + WaitForBarrierGCTask::destroy(_idle_inactive_task); 1.457 + _idle_inactive_task = NULL; 1.458 + if (_thread != NULL) { 1.459 + for (uint i = 0; i < workers(); i += 1) { 1.460 + GCTaskThread::destroy(thread(i)); 1.461 + set_thread(i, NULL); 1.462 + } 1.463 + FREE_C_HEAP_ARRAY(GCTaskThread*, _thread, mtGC); 1.464 + _thread = NULL; 1.465 + } 1.466 + if (_resource_flag != NULL) { 1.467 + FREE_C_HEAP_ARRAY(bool, _resource_flag, mtGC); 1.468 + _resource_flag = NULL; 1.469 + } 1.470 + if (queue() != NULL) { 1.471 + GCTaskQueue* unsynchronized_queue = queue()->unsynchronized_queue(); 1.472 + GCTaskQueue::destroy(unsynchronized_queue); 1.473 + SynchronizedGCTaskQueue::destroy(queue()); 1.474 + _queue = NULL; 1.475 + } 1.476 + if (monitor() != NULL) { 1.477 + delete monitor(); 1.478 + _monitor = NULL; 1.479 + } 1.480 +} 1.481 + 1.482 +void GCTaskManager::set_active_gang() { 1.483 + _active_workers = 1.484 + AdaptiveSizePolicy::calc_active_workers(workers(), 1.485 + active_workers(), 1.486 + Threads::number_of_non_daemon_threads()); 1.487 + 1.488 + assert(!all_workers_active() || active_workers() == ParallelGCThreads, 1.489 + err_msg("all_workers_active() is incorrect: " 1.490 + "active %d ParallelGCThreads %d", active_workers(), 1.491 + ParallelGCThreads)); 1.492 + if (TraceDynamicGCThreads) { 1.493 + gclog_or_tty->print_cr("GCTaskManager::set_active_gang(): " 1.494 + "all_workers_active() %d workers %d " 1.495 + "active %d ParallelGCThreads %d ", 1.496 + all_workers_active(), workers(), active_workers(), 1.497 + ParallelGCThreads); 1.498 + } 1.499 +} 1.500 + 1.501 +// Create IdleGCTasks for inactive workers. 1.502 +// Creates tasks in a ResourceArea and assumes 1.503 +// an appropriate ResourceMark. 1.504 +void GCTaskManager::task_idle_workers() { 1.505 + { 1.506 + int more_inactive_workers = 0; 1.507 + { 1.508 + // Stop any idle tasks from exiting their IdleGCTask's 1.509 + // and get the count for additional IdleGCTask's under 1.510 + // the GCTaskManager's monitor so that the "more_inactive_workers" 1.511 + // count is correct. 1.512 + MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); 1.513 + _idle_inactive_task->set_should_wait(true); 1.514 + // active_workers are a number being requested. idle_workers 1.515 + // are the number currently idle. If all the workers are being 1.516 + // requested to be active but some are already idle, reduce 1.517 + // the number of active_workers to be consistent with the 1.518 + // number of idle_workers. The idle_workers are stuck in 1.519 + // idle tasks and will no longer be release (since a new GC 1.520 + // is starting). Try later to release enough idle_workers 1.521 + // to allow the desired number of active_workers. 1.522 + more_inactive_workers = 1.523 + workers() - active_workers() - idle_workers(); 1.524 + if (more_inactive_workers < 0) { 1.525 + int reduced_active_workers = active_workers() + more_inactive_workers; 1.526 + set_active_workers(reduced_active_workers); 1.527 + more_inactive_workers = 0; 1.528 + } 1.529 + if (TraceDynamicGCThreads) { 1.530 + gclog_or_tty->print_cr("JT: %d workers %d active %d " 1.531 + "idle %d more %d", 1.532 + Threads::number_of_non_daemon_threads(), 1.533 + workers(), 1.534 + active_workers(), 1.535 + idle_workers(), 1.536 + more_inactive_workers); 1.537 + } 1.538 + } 1.539 + GCTaskQueue* q = GCTaskQueue::create(); 1.540 + for(uint i = 0; i < (uint) more_inactive_workers; i++) { 1.541 + q->enqueue(IdleGCTask::create_on_c_heap()); 1.542 + increment_idle_workers(); 1.543 + } 1.544 + assert(workers() == active_workers() + idle_workers(), 1.545 + "total workers should equal active + inactive"); 1.546 + add_list(q); 1.547 + // GCTaskQueue* q was created in a ResourceArea so a 1.548 + // destroy() call is not needed. 1.549 + } 1.550 +} 1.551 + 1.552 +void GCTaskManager::release_idle_workers() { 1.553 + { 1.554 + MutexLockerEx ml(monitor(), 1.555 + Mutex::_no_safepoint_check_flag); 1.556 + _idle_inactive_task->set_should_wait(false); 1.557 + monitor()->notify_all(); 1.558 + // Release monitor 1.559 + } 1.560 +} 1.561 + 1.562 +void GCTaskManager::print_task_time_stamps() { 1.563 + for(uint i=0; i<ParallelGCThreads; i++) { 1.564 + GCTaskThread* t = thread(i); 1.565 + t->print_task_time_stamps(); 1.566 + } 1.567 +} 1.568 + 1.569 +void GCTaskManager::print_threads_on(outputStream* st) { 1.570 + uint num_thr = workers(); 1.571 + for (uint i = 0; i < num_thr; i++) { 1.572 + thread(i)->print_on(st); 1.573 + st->cr(); 1.574 + } 1.575 +} 1.576 + 1.577 +void GCTaskManager::threads_do(ThreadClosure* tc) { 1.578 + assert(tc != NULL, "Null ThreadClosure"); 1.579 + uint num_thr = workers(); 1.580 + for (uint i = 0; i < num_thr; i++) { 1.581 + tc->do_thread(thread(i)); 1.582 + } 1.583 +} 1.584 + 1.585 +GCTaskThread* GCTaskManager::thread(uint which) { 1.586 + assert(which < workers(), "index out of bounds"); 1.587 + assert(_thread[which] != NULL, "shouldn't have null thread"); 1.588 + return _thread[which]; 1.589 +} 1.590 + 1.591 +void GCTaskManager::set_thread(uint which, GCTaskThread* value) { 1.592 + assert(which < workers(), "index out of bounds"); 1.593 + assert(value != NULL, "shouldn't have null thread"); 1.594 + _thread[which] = value; 1.595 +} 1.596 + 1.597 +void GCTaskManager::add_task(GCTask* task) { 1.598 + assert(task != NULL, "shouldn't have null task"); 1.599 + MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); 1.600 + if (TraceGCTaskManager) { 1.601 + tty->print_cr("GCTaskManager::add_task(" INTPTR_FORMAT " [%s])", 1.602 + task, GCTask::Kind::to_string(task->kind())); 1.603 + } 1.604 + queue()->enqueue(task); 1.605 + // Notify with the lock held to avoid missed notifies. 1.606 + if (TraceGCTaskManager) { 1.607 + tty->print_cr(" GCTaskManager::add_task (%s)->notify_all", 1.608 + monitor()->name()); 1.609 + } 1.610 + (void) monitor()->notify_all(); 1.611 + // Release monitor(). 1.612 +} 1.613 + 1.614 +void GCTaskManager::add_list(GCTaskQueue* list) { 1.615 + assert(list != NULL, "shouldn't have null task"); 1.616 + MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); 1.617 + if (TraceGCTaskManager) { 1.618 + tty->print_cr("GCTaskManager::add_list(%u)", list->length()); 1.619 + } 1.620 + queue()->enqueue(list); 1.621 + // Notify with the lock held to avoid missed notifies. 1.622 + if (TraceGCTaskManager) { 1.623 + tty->print_cr(" GCTaskManager::add_list (%s)->notify_all", 1.624 + monitor()->name()); 1.625 + } 1.626 + (void) monitor()->notify_all(); 1.627 + // Release monitor(). 1.628 +} 1.629 + 1.630 +// GC workers wait in get_task() for new work to be added 1.631 +// to the GCTaskManager's queue. When new work is added, 1.632 +// a notify is sent to the waiting GC workers which then 1.633 +// compete to get tasks. If a GC worker wakes up and there 1.634 +// is no work on the queue, it is given a noop_task to execute 1.635 +// and then loops to find more work. 1.636 + 1.637 +GCTask* GCTaskManager::get_task(uint which) { 1.638 + GCTask* result = NULL; 1.639 + // Grab the queue lock. 1.640 + MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); 1.641 + // Wait while the queue is block or 1.642 + // there is nothing to do, except maybe release resources. 1.643 + while (is_blocked() || 1.644 + (queue()->is_empty() && !should_release_resources(which))) { 1.645 + if (TraceGCTaskManager) { 1.646 + tty->print_cr("GCTaskManager::get_task(%u)" 1.647 + " blocked: %s" 1.648 + " empty: %s" 1.649 + " release: %s", 1.650 + which, 1.651 + is_blocked() ? "true" : "false", 1.652 + queue()->is_empty() ? "true" : "false", 1.653 + should_release_resources(which) ? "true" : "false"); 1.654 + tty->print_cr(" => (%s)->wait()", 1.655 + monitor()->name()); 1.656 + } 1.657 + monitor()->wait(Mutex::_no_safepoint_check_flag, 0); 1.658 + } 1.659 + // We've reacquired the queue lock here. 1.660 + // Figure out which condition caused us to exit the loop above. 1.661 + if (!queue()->is_empty()) { 1.662 + if (UseGCTaskAffinity) { 1.663 + result = queue()->dequeue(which); 1.664 + } else { 1.665 + result = queue()->dequeue(); 1.666 + } 1.667 + if (result->is_barrier_task()) { 1.668 + assert(which != sentinel_worker(), 1.669 + "blocker shouldn't be bogus"); 1.670 + set_blocking_worker(which); 1.671 + } 1.672 + } else { 1.673 + // The queue is empty, but we were woken up. 1.674 + // Just hand back a Noop task, 1.675 + // in case someone wanted us to release resources, or whatever. 1.676 + result = noop_task(); 1.677 + increment_noop_tasks(); 1.678 + } 1.679 + assert(result != NULL, "shouldn't have null task"); 1.680 + if (TraceGCTaskManager) { 1.681 + tty->print_cr("GCTaskManager::get_task(%u) => " INTPTR_FORMAT " [%s]", 1.682 + which, result, GCTask::Kind::to_string(result->kind())); 1.683 + tty->print_cr(" %s", result->name()); 1.684 + } 1.685 + if (!result->is_idle_task()) { 1.686 + increment_busy_workers(); 1.687 + increment_delivered_tasks(); 1.688 + } 1.689 + return result; 1.690 + // Release monitor(). 1.691 +} 1.692 + 1.693 +void GCTaskManager::note_completion(uint which) { 1.694 + MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); 1.695 + if (TraceGCTaskManager) { 1.696 + tty->print_cr("GCTaskManager::note_completion(%u)", which); 1.697 + } 1.698 + // If we are blocked, check if the completing thread is the blocker. 1.699 + if (blocking_worker() == which) { 1.700 + assert(blocking_worker() != sentinel_worker(), 1.701 + "blocker shouldn't be bogus"); 1.702 + increment_barriers(); 1.703 + set_unblocked(); 1.704 + } 1.705 + increment_completed_tasks(); 1.706 + uint active = decrement_busy_workers(); 1.707 + if ((active == 0) && (queue()->is_empty())) { 1.708 + increment_emptied_queue(); 1.709 + if (TraceGCTaskManager) { 1.710 + tty->print_cr(" GCTaskManager::note_completion(%u) done", which); 1.711 + } 1.712 + // Notify client that we are done. 1.713 + NotifyDoneClosure* ndc = notify_done_closure(); 1.714 + if (ndc != NULL) { 1.715 + ndc->notify(this); 1.716 + } 1.717 + } 1.718 + if (TraceGCTaskManager) { 1.719 + tty->print_cr(" GCTaskManager::note_completion(%u) (%s)->notify_all", 1.720 + which, monitor()->name()); 1.721 + tty->print_cr(" " 1.722 + " blocked: %s" 1.723 + " empty: %s" 1.724 + " release: %s", 1.725 + is_blocked() ? "true" : "false", 1.726 + queue()->is_empty() ? "true" : "false", 1.727 + should_release_resources(which) ? "true" : "false"); 1.728 + tty->print_cr(" " 1.729 + " delivered: %u" 1.730 + " completed: %u" 1.731 + " barriers: %u" 1.732 + " emptied: %u", 1.733 + delivered_tasks(), 1.734 + completed_tasks(), 1.735 + barriers(), 1.736 + emptied_queue()); 1.737 + } 1.738 + // Tell everyone that a task has completed. 1.739 + (void) monitor()->notify_all(); 1.740 + // Release monitor(). 1.741 +} 1.742 + 1.743 +uint GCTaskManager::increment_busy_workers() { 1.744 + assert(queue()->own_lock(), "don't own the lock"); 1.745 + _busy_workers += 1; 1.746 + return _busy_workers; 1.747 +} 1.748 + 1.749 +uint GCTaskManager::decrement_busy_workers() { 1.750 + assert(queue()->own_lock(), "don't own the lock"); 1.751 + assert(_busy_workers > 0, "About to make a mistake"); 1.752 + _busy_workers -= 1; 1.753 + return _busy_workers; 1.754 +} 1.755 + 1.756 +void GCTaskManager::release_all_resources() { 1.757 + // If you want this to be done atomically, do it in a BarrierGCTask. 1.758 + for (uint i = 0; i < workers(); i += 1) { 1.759 + set_resource_flag(i, true); 1.760 + } 1.761 +} 1.762 + 1.763 +bool GCTaskManager::should_release_resources(uint which) { 1.764 + // This can be done without a lock because each thread reads one element. 1.765 + return resource_flag(which); 1.766 +} 1.767 + 1.768 +void GCTaskManager::note_release(uint which) { 1.769 + // This can be done without a lock because each thread writes one element. 1.770 + set_resource_flag(which, false); 1.771 +} 1.772 + 1.773 +// "list" contains tasks that are ready to execute. Those 1.774 +// tasks are added to the GCTaskManager's queue of tasks and 1.775 +// then the GC workers are notified that there is new work to 1.776 +// do. 1.777 +// 1.778 +// Typically different types of tasks can be added to the "list". 1.779 +// For example in PSScavenge OldToYoungRootsTask, SerialOldToYoungRootsTask, 1.780 +// ScavengeRootsTask, and StealTask tasks are all added to the list 1.781 +// and then the GC workers are notified of new work. The tasks are 1.782 +// handed out in the order in which they are added to the list 1.783 +// (although execution is not necessarily in that order). As long 1.784 +// as any tasks are running the GCTaskManager will wait for execution 1.785 +// to complete. GC workers that execute a stealing task remain in 1.786 +// the stealing task until all stealing tasks have completed. The load 1.787 +// balancing afforded by the stealing tasks work best if the stealing 1.788 +// tasks are added last to the list. 1.789 + 1.790 +void GCTaskManager::execute_and_wait(GCTaskQueue* list) { 1.791 + WaitForBarrierGCTask* fin = WaitForBarrierGCTask::create(); 1.792 + list->enqueue(fin); 1.793 + // The barrier task will be read by one of the GC 1.794 + // workers once it is added to the list of tasks. 1.795 + // Be sure that is globally visible before the 1.796 + // GC worker reads it (which is after the task is added 1.797 + // to the list of tasks below). 1.798 + OrderAccess::storestore(); 1.799 + add_list(list); 1.800 + fin->wait_for(true /* reset */); 1.801 + // We have to release the barrier tasks! 1.802 + WaitForBarrierGCTask::destroy(fin); 1.803 +} 1.804 + 1.805 +bool GCTaskManager::resource_flag(uint which) { 1.806 + assert(which < workers(), "index out of bounds"); 1.807 + return _resource_flag[which]; 1.808 +} 1.809 + 1.810 +void GCTaskManager::set_resource_flag(uint which, bool value) { 1.811 + assert(which < workers(), "index out of bounds"); 1.812 + _resource_flag[which] = value; 1.813 +} 1.814 + 1.815 +// 1.816 +// NoopGCTask 1.817 +// 1.818 + 1.819 +NoopGCTask* NoopGCTask::create() { 1.820 + NoopGCTask* result = new NoopGCTask(false); 1.821 + return result; 1.822 +} 1.823 + 1.824 +NoopGCTask* NoopGCTask::create_on_c_heap() { 1.825 + NoopGCTask* result = new(ResourceObj::C_HEAP, mtGC) NoopGCTask(true); 1.826 + return result; 1.827 +} 1.828 + 1.829 +void NoopGCTask::destroy(NoopGCTask* that) { 1.830 + if (that != NULL) { 1.831 + that->destruct(); 1.832 + if (that->is_c_heap_obj()) { 1.833 + FreeHeap(that); 1.834 + } 1.835 + } 1.836 +} 1.837 + 1.838 +void NoopGCTask::destruct() { 1.839 + // This has to know it's superclass structure, just like the constructor. 1.840 + this->GCTask::destruct(); 1.841 + // Nothing else to do. 1.842 +} 1.843 + 1.844 +// 1.845 +// IdleGCTask 1.846 +// 1.847 + 1.848 +IdleGCTask* IdleGCTask::create() { 1.849 + IdleGCTask* result = new IdleGCTask(false); 1.850 + assert(UseDynamicNumberOfGCThreads, 1.851 + "Should only be used with dynamic GC thread"); 1.852 + return result; 1.853 +} 1.854 + 1.855 +IdleGCTask* IdleGCTask::create_on_c_heap() { 1.856 + IdleGCTask* result = new(ResourceObj::C_HEAP, mtGC) IdleGCTask(true); 1.857 + assert(UseDynamicNumberOfGCThreads, 1.858 + "Should only be used with dynamic GC thread"); 1.859 + return result; 1.860 +} 1.861 + 1.862 +void IdleGCTask::do_it(GCTaskManager* manager, uint which) { 1.863 + WaitForBarrierGCTask* wait_for_task = manager->idle_inactive_task(); 1.864 + if (TraceGCTaskManager) { 1.865 + tty->print_cr("[" INTPTR_FORMAT "]" 1.866 + " IdleGCTask:::do_it()" 1.867 + " should_wait: %s", 1.868 + this, wait_for_task->should_wait() ? "true" : "false"); 1.869 + } 1.870 + MutexLockerEx ml(manager->monitor(), Mutex::_no_safepoint_check_flag); 1.871 + if (TraceDynamicGCThreads) { 1.872 + gclog_or_tty->print_cr("--- idle %d", which); 1.873 + } 1.874 + // Increment has to be done when the idle tasks are created. 1.875 + // manager->increment_idle_workers(); 1.876 + manager->monitor()->notify_all(); 1.877 + while (wait_for_task->should_wait()) { 1.878 + if (TraceGCTaskManager) { 1.879 + tty->print_cr("[" INTPTR_FORMAT "]" 1.880 + " IdleGCTask::do_it()" 1.881 + " [" INTPTR_FORMAT "] (%s)->wait()", 1.882 + this, manager->monitor(), manager->monitor()->name()); 1.883 + } 1.884 + manager->monitor()->wait(Mutex::_no_safepoint_check_flag, 0); 1.885 + } 1.886 + manager->decrement_idle_workers(); 1.887 + if (TraceDynamicGCThreads) { 1.888 + gclog_or_tty->print_cr("--- release %d", which); 1.889 + } 1.890 + if (TraceGCTaskManager) { 1.891 + tty->print_cr("[" INTPTR_FORMAT "]" 1.892 + " IdleGCTask::do_it() returns" 1.893 + " should_wait: %s", 1.894 + this, wait_for_task->should_wait() ? "true" : "false"); 1.895 + } 1.896 + // Release monitor(). 1.897 +} 1.898 + 1.899 +void IdleGCTask::destroy(IdleGCTask* that) { 1.900 + if (that != NULL) { 1.901 + that->destruct(); 1.902 + if (that->is_c_heap_obj()) { 1.903 + FreeHeap(that); 1.904 + } 1.905 + } 1.906 +} 1.907 + 1.908 +void IdleGCTask::destruct() { 1.909 + // This has to know it's superclass structure, just like the constructor. 1.910 + this->GCTask::destruct(); 1.911 + // Nothing else to do. 1.912 +} 1.913 + 1.914 +// 1.915 +// BarrierGCTask 1.916 +// 1.917 + 1.918 +void BarrierGCTask::do_it(GCTaskManager* manager, uint which) { 1.919 + // Wait for this to be the only busy worker. 1.920 + // ??? I thought of having a StackObj class 1.921 + // whose constructor would grab the lock and come to the barrier, 1.922 + // and whose destructor would release the lock, 1.923 + // but that seems like too much mechanism for two lines of code. 1.924 + MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); 1.925 + do_it_internal(manager, which); 1.926 + // Release manager->lock(). 1.927 +} 1.928 + 1.929 +void BarrierGCTask::do_it_internal(GCTaskManager* manager, uint which) { 1.930 + // Wait for this to be the only busy worker. 1.931 + assert(manager->monitor()->owned_by_self(), "don't own the lock"); 1.932 + assert(manager->is_blocked(), "manager isn't blocked"); 1.933 + while (manager->busy_workers() > 1) { 1.934 + if (TraceGCTaskManager) { 1.935 + tty->print_cr("BarrierGCTask::do_it(%u) waiting on %u workers", 1.936 + which, manager->busy_workers()); 1.937 + } 1.938 + manager->monitor()->wait(Mutex::_no_safepoint_check_flag, 0); 1.939 + } 1.940 +} 1.941 + 1.942 +void BarrierGCTask::destruct() { 1.943 + this->GCTask::destruct(); 1.944 + // Nothing else to do. 1.945 +} 1.946 + 1.947 +// 1.948 +// ReleasingBarrierGCTask 1.949 +// 1.950 + 1.951 +void ReleasingBarrierGCTask::do_it(GCTaskManager* manager, uint which) { 1.952 + MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); 1.953 + do_it_internal(manager, which); 1.954 + manager->release_all_resources(); 1.955 + // Release manager->lock(). 1.956 +} 1.957 + 1.958 +void ReleasingBarrierGCTask::destruct() { 1.959 + this->BarrierGCTask::destruct(); 1.960 + // Nothing else to do. 1.961 +} 1.962 + 1.963 +// 1.964 +// NotifyingBarrierGCTask 1.965 +// 1.966 + 1.967 +void NotifyingBarrierGCTask::do_it(GCTaskManager* manager, uint which) { 1.968 + MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); 1.969 + do_it_internal(manager, which); 1.970 + NotifyDoneClosure* ndc = notify_done_closure(); 1.971 + if (ndc != NULL) { 1.972 + ndc->notify(manager); 1.973 + } 1.974 + // Release manager->lock(). 1.975 +} 1.976 + 1.977 +void NotifyingBarrierGCTask::destruct() { 1.978 + this->BarrierGCTask::destruct(); 1.979 + // Nothing else to do. 1.980 +} 1.981 + 1.982 +// 1.983 +// WaitForBarrierGCTask 1.984 +// 1.985 +WaitForBarrierGCTask* WaitForBarrierGCTask::create() { 1.986 + WaitForBarrierGCTask* result = new WaitForBarrierGCTask(false); 1.987 + return result; 1.988 +} 1.989 + 1.990 +WaitForBarrierGCTask* WaitForBarrierGCTask::create_on_c_heap() { 1.991 + WaitForBarrierGCTask* result = 1.992 + new (ResourceObj::C_HEAP, mtGC) WaitForBarrierGCTask(true); 1.993 + return result; 1.994 +} 1.995 + 1.996 +WaitForBarrierGCTask::WaitForBarrierGCTask(bool on_c_heap) : 1.997 + _is_c_heap_obj(on_c_heap) { 1.998 + _monitor = MonitorSupply::reserve(); 1.999 + set_should_wait(true); 1.1000 + if (TraceGCTaskManager) { 1.1001 + tty->print_cr("[" INTPTR_FORMAT "]" 1.1002 + " WaitForBarrierGCTask::WaitForBarrierGCTask()" 1.1003 + " monitor: " INTPTR_FORMAT, 1.1004 + this, monitor()); 1.1005 + } 1.1006 +} 1.1007 + 1.1008 +void WaitForBarrierGCTask::destroy(WaitForBarrierGCTask* that) { 1.1009 + if (that != NULL) { 1.1010 + if (TraceGCTaskManager) { 1.1011 + tty->print_cr("[" INTPTR_FORMAT "]" 1.1012 + " WaitForBarrierGCTask::destroy()" 1.1013 + " is_c_heap_obj: %s" 1.1014 + " monitor: " INTPTR_FORMAT, 1.1015 + that, 1.1016 + that->is_c_heap_obj() ? "true" : "false", 1.1017 + that->monitor()); 1.1018 + } 1.1019 + that->destruct(); 1.1020 + if (that->is_c_heap_obj()) { 1.1021 + FreeHeap(that); 1.1022 + } 1.1023 + } 1.1024 +} 1.1025 + 1.1026 +void WaitForBarrierGCTask::destruct() { 1.1027 + assert(monitor() != NULL, "monitor should not be NULL"); 1.1028 + if (TraceGCTaskManager) { 1.1029 + tty->print_cr("[" INTPTR_FORMAT "]" 1.1030 + " WaitForBarrierGCTask::destruct()" 1.1031 + " monitor: " INTPTR_FORMAT, 1.1032 + this, monitor()); 1.1033 + } 1.1034 + this->BarrierGCTask::destruct(); 1.1035 + // Clean up that should be in the destructor, 1.1036 + // except that ResourceMarks don't call destructors. 1.1037 + if (monitor() != NULL) { 1.1038 + MonitorSupply::release(monitor()); 1.1039 + } 1.1040 + _monitor = (Monitor*) 0xDEAD000F; 1.1041 +} 1.1042 + 1.1043 +void WaitForBarrierGCTask::do_it(GCTaskManager* manager, uint which) { 1.1044 + if (TraceGCTaskManager) { 1.1045 + tty->print_cr("[" INTPTR_FORMAT "]" 1.1046 + " WaitForBarrierGCTask::do_it() waiting for idle" 1.1047 + " monitor: " INTPTR_FORMAT, 1.1048 + this, monitor()); 1.1049 + } 1.1050 + { 1.1051 + // First, wait for the barrier to arrive. 1.1052 + MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag); 1.1053 + do_it_internal(manager, which); 1.1054 + // Release manager->lock(). 1.1055 + } 1.1056 + { 1.1057 + // Then notify the waiter. 1.1058 + MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); 1.1059 + set_should_wait(false); 1.1060 + // Waiter doesn't miss the notify in the wait_for method 1.1061 + // since it checks the flag after grabbing the monitor. 1.1062 + if (TraceGCTaskManager) { 1.1063 + tty->print_cr("[" INTPTR_FORMAT "]" 1.1064 + " WaitForBarrierGCTask::do_it()" 1.1065 + " [" INTPTR_FORMAT "] (%s)->notify_all()", 1.1066 + this, monitor(), monitor()->name()); 1.1067 + } 1.1068 + monitor()->notify_all(); 1.1069 + // Release monitor(). 1.1070 + } 1.1071 +} 1.1072 + 1.1073 +void WaitForBarrierGCTask::wait_for(bool reset) { 1.1074 + if (TraceGCTaskManager) { 1.1075 + tty->print_cr("[" INTPTR_FORMAT "]" 1.1076 + " WaitForBarrierGCTask::wait_for()" 1.1077 + " should_wait: %s", 1.1078 + this, should_wait() ? "true" : "false"); 1.1079 + } 1.1080 + { 1.1081 + // Grab the lock and check again. 1.1082 + MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag); 1.1083 + while (should_wait()) { 1.1084 + if (TraceGCTaskManager) { 1.1085 + tty->print_cr("[" INTPTR_FORMAT "]" 1.1086 + " WaitForBarrierGCTask::wait_for()" 1.1087 + " [" INTPTR_FORMAT "] (%s)->wait()", 1.1088 + this, monitor(), monitor()->name()); 1.1089 + } 1.1090 + monitor()->wait(Mutex::_no_safepoint_check_flag, 0); 1.1091 + } 1.1092 + // Reset the flag in case someone reuses this task. 1.1093 + if (reset) { 1.1094 + set_should_wait(true); 1.1095 + } 1.1096 + if (TraceGCTaskManager) { 1.1097 + tty->print_cr("[" INTPTR_FORMAT "]" 1.1098 + " WaitForBarrierGCTask::wait_for() returns" 1.1099 + " should_wait: %s", 1.1100 + this, should_wait() ? "true" : "false"); 1.1101 + } 1.1102 + // Release monitor(). 1.1103 + } 1.1104 +} 1.1105 + 1.1106 +Mutex* MonitorSupply::_lock = NULL; 1.1107 +GrowableArray<Monitor*>* MonitorSupply::_freelist = NULL; 1.1108 + 1.1109 +Monitor* MonitorSupply::reserve() { 1.1110 + Monitor* result = NULL; 1.1111 + // Lazy initialization: possible race. 1.1112 + if (lock() == NULL) { 1.1113 + _lock = new Mutex(Mutex::barrier, // rank 1.1114 + "MonitorSupply mutex", // name 1.1115 + Mutex::_allow_vm_block_flag); // allow_vm_block 1.1116 + } 1.1117 + { 1.1118 + MutexLockerEx ml(lock()); 1.1119 + // Lazy initialization. 1.1120 + if (freelist() == NULL) { 1.1121 + _freelist = 1.1122 + new(ResourceObj::C_HEAP, mtGC) GrowableArray<Monitor*>(ParallelGCThreads, 1.1123 + true); 1.1124 + } 1.1125 + if (! freelist()->is_empty()) { 1.1126 + result = freelist()->pop(); 1.1127 + } else { 1.1128 + result = new Monitor(Mutex::barrier, // rank 1.1129 + "MonitorSupply monitor", // name 1.1130 + Mutex::_allow_vm_block_flag); // allow_vm_block 1.1131 + } 1.1132 + guarantee(result != NULL, "shouldn't return NULL"); 1.1133 + assert(!result->is_locked(), "shouldn't be locked"); 1.1134 + // release lock(). 1.1135 + } 1.1136 + return result; 1.1137 +} 1.1138 + 1.1139 +void MonitorSupply::release(Monitor* instance) { 1.1140 + assert(instance != NULL, "shouldn't release NULL"); 1.1141 + assert(!instance->is_locked(), "shouldn't be locked"); 1.1142 + { 1.1143 + MutexLockerEx ml(lock()); 1.1144 + freelist()->push(instance); 1.1145 + // release lock(). 1.1146 + } 1.1147 +}