0N/A/*
2975N/A * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
0N/A * published by the Free Software Foundation.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
1472N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
1472N/A * or visit www.oracle.com if you need additional information or have any
1472N/A * questions.
0N/A *
0N/A */
0N/A
1879N/A#include "precompiled.hpp"
1879N/A#include "gc_implementation/parallelScavenge/gcTaskManager.hpp"
1879N/A#include "gc_implementation/parallelScavenge/gcTaskThread.hpp"
2941N/A#include "gc_implementation/shared/adaptiveSizePolicy.hpp"
1879N/A#include "memory/allocation.hpp"
1879N/A#include "memory/allocation.inline.hpp"
1879N/A#include "runtime/mutex.hpp"
1879N/A#include "runtime/mutexLocker.hpp"
0N/A
0N/A//
0N/A// GCTask
0N/A//
0N/A
0N/Aconst char* GCTask::Kind::to_string(kind value) {
0N/A const char* result = "unknown GCTask kind";
0N/A switch (value) {
0N/A default:
0N/A result = "unknown GCTask kind";
0N/A break;
0N/A case unknown_task:
0N/A result = "unknown task";
0N/A break;
0N/A case ordinary_task:
0N/A result = "ordinary task";
0N/A break;
0N/A case barrier_task:
0N/A result = "barrier task";
0N/A break;
0N/A case noop_task:
0N/A result = "noop task";
0N/A break;
2975N/A case idle_task:
2975N/A result = "idle task";
2975N/A break;
0N/A }
0N/A return result;
0N/A};
0N/A
0N/AGCTask::GCTask() :
0N/A _kind(Kind::ordinary_task),
0N/A _affinity(GCTaskManager::sentinel_worker()){
0N/A initialize();
0N/A}
0N/A
0N/AGCTask::GCTask(Kind::kind kind) :
0N/A _kind(kind),
0N/A _affinity(GCTaskManager::sentinel_worker()) {
0N/A initialize();
0N/A}
0N/A
0N/AGCTask::GCTask(uint affinity) :
0N/A _kind(Kind::ordinary_task),
0N/A _affinity(affinity) {
0N/A initialize();
0N/A}
0N/A
0N/AGCTask::GCTask(Kind::kind kind, uint affinity) :
0N/A _kind(kind),
0N/A _affinity(affinity) {
0N/A initialize();
0N/A}
0N/A
0N/Avoid GCTask::initialize() {
0N/A _older = NULL;
0N/A _newer = NULL;
0N/A}
0N/A
0N/Avoid GCTask::destruct() {
0N/A assert(older() == NULL, "shouldn't have an older task");
0N/A assert(newer() == NULL, "shouldn't have a newer task");
0N/A // Nothing to do.
0N/A}
0N/A
0N/ANOT_PRODUCT(
0N/Avoid GCTask::print(const char* message) const {
0N/A tty->print(INTPTR_FORMAT " <- " INTPTR_FORMAT "(%u) -> " INTPTR_FORMAT,
0N/A newer(), this, affinity(), older());
0N/A}
0N/A)
0N/A
0N/A//
0N/A// GCTaskQueue
0N/A//
0N/A
0N/AGCTaskQueue* GCTaskQueue::create() {
0N/A GCTaskQueue* result = new GCTaskQueue(false);
0N/A if (TraceGCTaskQueue) {
0N/A tty->print_cr("GCTaskQueue::create()"
0N/A " returns " INTPTR_FORMAT, result);
0N/A }
0N/A return result;
0N/A}
0N/A
0N/AGCTaskQueue* GCTaskQueue::create_on_c_heap() {
3863N/A GCTaskQueue* result = new(ResourceObj::C_HEAP, mtGC) GCTaskQueue(true);
0N/A if (TraceGCTaskQueue) {
0N/A tty->print_cr("GCTaskQueue::create_on_c_heap()"
0N/A " returns " INTPTR_FORMAT,
0N/A result);
0N/A }
0N/A return result;
0N/A}
0N/A
0N/AGCTaskQueue::GCTaskQueue(bool on_c_heap) :
0N/A _is_c_heap_obj(on_c_heap) {
0N/A initialize();
0N/A if (TraceGCTaskQueue) {
0N/A tty->print_cr("[" INTPTR_FORMAT "]"
0N/A " GCTaskQueue::GCTaskQueue() constructor",
0N/A this);
0N/A }
0N/A}
0N/A
0N/Avoid GCTaskQueue::destruct() {
0N/A // Nothing to do.
0N/A}
0N/A
0N/Avoid GCTaskQueue::destroy(GCTaskQueue* that) {
0N/A if (TraceGCTaskQueue) {
0N/A tty->print_cr("[" INTPTR_FORMAT "]"
0N/A " GCTaskQueue::destroy()"
0N/A " is_c_heap_obj: %s",
0N/A that,
0N/A that->is_c_heap_obj() ? "true" : "false");
0N/A }
0N/A // That instance may have been allocated as a CHeapObj,
0N/A // in which case we have to free it explicitly.
0N/A if (that != NULL) {
0N/A that->destruct();
0N/A assert(that->is_empty(), "should be empty");
0N/A if (that->is_c_heap_obj()) {
0N/A FreeHeap(that);
0N/A }
0N/A }
0N/A}
0N/A
0N/Avoid GCTaskQueue::initialize() {
0N/A set_insert_end(NULL);
0N/A set_remove_end(NULL);
0N/A set_length(0);
0N/A}
0N/A
0N/A// Enqueue one task.
0N/Avoid GCTaskQueue::enqueue(GCTask* task) {
0N/A if (TraceGCTaskQueue) {
0N/A tty->print_cr("[" INTPTR_FORMAT "]"
0N/A " GCTaskQueue::enqueue(task: "
0N/A INTPTR_FORMAT ")",
0N/A this, task);
0N/A print("before:");
0N/A }
0N/A assert(task != NULL, "shouldn't have null task");
0N/A assert(task->older() == NULL, "shouldn't be on queue");
0N/A assert(task->newer() == NULL, "shouldn't be on queue");
0N/A task->set_newer(NULL);
0N/A task->set_older(insert_end());
0N/A if (is_empty()) {
0N/A set_remove_end(task);
0N/A } else {
0N/A insert_end()->set_newer(task);
0N/A }
0N/A set_insert_end(task);
0N/A increment_length();
2941N/A verify_length();
0N/A if (TraceGCTaskQueue) {
0N/A print("after:");
0N/A }
0N/A}
0N/A
0N/A// Enqueue a whole list of tasks. Empties the argument list.
0N/Avoid GCTaskQueue::enqueue(GCTaskQueue* list) {
0N/A if (TraceGCTaskQueue) {
0N/A tty->print_cr("[" INTPTR_FORMAT "]"
0N/A " GCTaskQueue::enqueue(list: "
0N/A INTPTR_FORMAT ")",
2941N/A this, list);
0N/A print("before:");
0N/A list->print("list:");
0N/A }
0N/A if (list->is_empty()) {
0N/A // Enqueuing the empty list: nothing to do.
0N/A return;
0N/A }
0N/A uint list_length = list->length();
0N/A if (is_empty()) {
0N/A // Enqueuing to empty list: just acquire elements.
0N/A set_insert_end(list->insert_end());
0N/A set_remove_end(list->remove_end());
0N/A set_length(list_length);
0N/A } else {
0N/A // Prepend argument list to our queue.
0N/A list->remove_end()->set_older(insert_end());
0N/A insert_end()->set_newer(list->remove_end());
0N/A set_insert_end(list->insert_end());
2941N/A set_length(length() + list_length);
0N/A // empty the argument list.
0N/A }
0N/A list->initialize();
0N/A if (TraceGCTaskQueue) {
0N/A print("after:");
0N/A list->print("list:");
0N/A }
2941N/A verify_length();
0N/A}
0N/A
0N/A// Dequeue one task.
0N/AGCTask* GCTaskQueue::dequeue() {
0N/A if (TraceGCTaskQueue) {
0N/A tty->print_cr("[" INTPTR_FORMAT "]"
0N/A " GCTaskQueue::dequeue()", this);
0N/A print("before:");
0N/A }
0N/A assert(!is_empty(), "shouldn't dequeue from empty list");
0N/A GCTask* result = remove();
0N/A assert(result != NULL, "shouldn't have NULL task");
0N/A if (TraceGCTaskQueue) {
0N/A tty->print_cr(" return: " INTPTR_FORMAT, result);
0N/A print("after:");
0N/A }
0N/A return result;
0N/A}
0N/A
0N/A// Dequeue one task, preferring one with affinity.
0N/AGCTask* GCTaskQueue::dequeue(uint affinity) {
0N/A if (TraceGCTaskQueue) {
0N/A tty->print_cr("[" INTPTR_FORMAT "]"
0N/A " GCTaskQueue::dequeue(%u)", this, affinity);
0N/A print("before:");
0N/A }
0N/A assert(!is_empty(), "shouldn't dequeue from empty list");
0N/A // Look down to the next barrier for a task with this affinity.
0N/A GCTask* result = NULL;
0N/A for (GCTask* element = remove_end();
0N/A element != NULL;
0N/A element = element->newer()) {
0N/A if (element->is_barrier_task()) {
0N/A // Don't consider barrier tasks, nor past them.
0N/A result = NULL;
0N/A break;
0N/A }
0N/A if (element->affinity() == affinity) {
0N/A result = remove(element);
0N/A break;
0N/A }
0N/A }
0N/A // If we didn't find anything with affinity, just take the next task.
0N/A if (result == NULL) {
0N/A result = remove();
0N/A }
0N/A if (TraceGCTaskQueue) {
0N/A tty->print_cr(" return: " INTPTR_FORMAT, result);
0N/A print("after:");
0N/A }
0N/A return result;
0N/A}
0N/A
0N/AGCTask* GCTaskQueue::remove() {
0N/A // Dequeue from remove end.
0N/A GCTask* result = remove_end();
0N/A assert(result != NULL, "shouldn't have null task");
0N/A assert(result->older() == NULL, "not the remove_end");
0N/A set_remove_end(result->newer());
0N/A if (remove_end() == NULL) {
0N/A assert(insert_end() == result, "not a singleton");
0N/A set_insert_end(NULL);
0N/A } else {
0N/A remove_end()->set_older(NULL);
0N/A }
0N/A result->set_newer(NULL);
0N/A decrement_length();
0N/A assert(result->newer() == NULL, "shouldn't be on queue");
0N/A assert(result->older() == NULL, "shouldn't be on queue");
2941N/A verify_length();
0N/A return result;
0N/A}
0N/A
0N/AGCTask* GCTaskQueue::remove(GCTask* task) {
0N/A // This is slightly more work, and has slightly fewer asserts
0N/A // than removing from the remove end.
0N/A assert(task != NULL, "shouldn't have null task");
0N/A GCTask* result = task;
0N/A if (result->newer() != NULL) {
0N/A result->newer()->set_older(result->older());
0N/A } else {
0N/A assert(insert_end() == result, "not youngest");
0N/A set_insert_end(result->older());
0N/A }
0N/A if (result->older() != NULL) {
0N/A result->older()->set_newer(result->newer());
0N/A } else {
0N/A assert(remove_end() == result, "not oldest");
0N/A set_remove_end(result->newer());
0N/A }
0N/A result->set_newer(NULL);
0N/A result->set_older(NULL);
0N/A decrement_length();
2941N/A verify_length();
0N/A return result;
0N/A}
0N/A
0N/ANOT_PRODUCT(
2941N/A// Count the elements in the queue and verify the length against
2941N/A// that count.
2941N/Avoid GCTaskQueue::verify_length() const {
2941N/A uint count = 0;
2941N/A for (GCTask* element = insert_end();
2941N/A element != NULL;
2941N/A element = element->older()) {
2941N/A
2941N/A count++;
2941N/A }
2941N/A assert(count == length(), "Length does not match queue");
2941N/A}
2941N/A
0N/Avoid GCTaskQueue::print(const char* message) const {
0N/A tty->print_cr("[" INTPTR_FORMAT "] GCTaskQueue:"
0N/A " insert_end: " INTPTR_FORMAT
0N/A " remove_end: " INTPTR_FORMAT
2941N/A " length: %d"
0N/A " %s",
2941N/A this, insert_end(), remove_end(), length(), message);
2941N/A uint count = 0;
0N/A for (GCTask* element = insert_end();
0N/A element != NULL;
0N/A element = element->older()) {
0N/A element->print(" ");
2941N/A count++;
0N/A tty->cr();
0N/A }
2941N/A tty->print("Total tasks: %d", count);
0N/A}
0N/A)
0N/A
0N/A//
0N/A// SynchronizedGCTaskQueue
0N/A//
0N/A
0N/ASynchronizedGCTaskQueue::SynchronizedGCTaskQueue(GCTaskQueue* queue_arg,
0N/A Monitor * lock_arg) :
0N/A _unsynchronized_queue(queue_arg),
0N/A _lock(lock_arg) {
0N/A assert(unsynchronized_queue() != NULL, "null queue");
0N/A assert(lock() != NULL, "null lock");
0N/A}
0N/A
0N/ASynchronizedGCTaskQueue::~SynchronizedGCTaskQueue() {
0N/A // Nothing to do.
0N/A}
0N/A
0N/A//
0N/A// GCTaskManager
0N/A//
0N/AGCTaskManager::GCTaskManager(uint workers) :
0N/A _workers(workers),
2941N/A _active_workers(0),
2941N/A _idle_workers(0),
0N/A _ndc(NULL) {
0N/A initialize();
0N/A}
0N/A
0N/AGCTaskManager::GCTaskManager(uint workers, NotifyDoneClosure* ndc) :
0N/A _workers(workers),
2941N/A _active_workers(0),
2941N/A _idle_workers(0),
0N/A _ndc(ndc) {
0N/A initialize();
0N/A}
0N/A
0N/Avoid GCTaskManager::initialize() {
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr("GCTaskManager::initialize: workers: %u", workers());
0N/A }
0N/A assert(workers() != 0, "no workers");
0N/A _monitor = new Monitor(Mutex::barrier, // rank
0N/A "GCTaskManager monitor", // name
0N/A Mutex::_allow_vm_block_flag); // allow_vm_block
0N/A // The queue for the GCTaskManager must be a CHeapObj.
0N/A GCTaskQueue* unsynchronized_queue = GCTaskQueue::create_on_c_heap();
0N/A _queue = SynchronizedGCTaskQueue::create(unsynchronized_queue, lock());
0N/A _noop_task = NoopGCTask::create_on_c_heap();
2941N/A _idle_inactive_task = WaitForBarrierGCTask::create_on_c_heap();
3863N/A _resource_flag = NEW_C_HEAP_ARRAY(bool, workers(), mtGC);
0N/A {
0N/A // Set up worker threads.
0N/A // Distribute the workers among the available processors,
0N/A // unless we were told not to, or if the os doesn't want to.
3863N/A uint* processor_assignment = NEW_C_HEAP_ARRAY(uint, workers(), mtGC);
0N/A if (!BindGCTaskThreadsToCPUs ||
0N/A !os::distribute_processes(workers(), processor_assignment)) {
0N/A for (uint a = 0; a < workers(); a += 1) {
0N/A processor_assignment[a] = sentinel_worker();
0N/A }
0N/A }
3863N/A _thread = NEW_C_HEAP_ARRAY(GCTaskThread*, workers(), mtGC);
0N/A for (uint t = 0; t < workers(); t += 1) {
0N/A set_thread(t, GCTaskThread::create(this, t, processor_assignment[t]));
0N/A }
0N/A if (TraceGCTaskThread) {
0N/A tty->print("GCTaskManager::initialize: distribution:");
0N/A for (uint t = 0; t < workers(); t += 1) {
0N/A tty->print(" %u", processor_assignment[t]);
0N/A }
0N/A tty->cr();
0N/A }
3863N/A FREE_C_HEAP_ARRAY(uint, processor_assignment, mtGC);
0N/A }
0N/A reset_busy_workers();
0N/A set_unblocked();
0N/A for (uint w = 0; w < workers(); w += 1) {
0N/A set_resource_flag(w, false);
0N/A }
0N/A reset_delivered_tasks();
0N/A reset_completed_tasks();
0N/A reset_noop_tasks();
0N/A reset_barriers();
0N/A reset_emptied_queue();
0N/A for (uint s = 0; s < workers(); s += 1) {
0N/A thread(s)->start();
0N/A }
0N/A}
0N/A
0N/AGCTaskManager::~GCTaskManager() {
0N/A assert(busy_workers() == 0, "still have busy workers");
0N/A assert(queue()->is_empty(), "still have queued work");
0N/A NoopGCTask::destroy(_noop_task);
0N/A _noop_task = NULL;
2941N/A WaitForBarrierGCTask::destroy(_idle_inactive_task);
2941N/A _idle_inactive_task = NULL;
0N/A if (_thread != NULL) {
0N/A for (uint i = 0; i < workers(); i += 1) {
0N/A GCTaskThread::destroy(thread(i));
0N/A set_thread(i, NULL);
0N/A }
3863N/A FREE_C_HEAP_ARRAY(GCTaskThread*, _thread, mtGC);
0N/A _thread = NULL;
0N/A }
0N/A if (_resource_flag != NULL) {
3863N/A FREE_C_HEAP_ARRAY(bool, _resource_flag, mtGC);
0N/A _resource_flag = NULL;
0N/A }
0N/A if (queue() != NULL) {
0N/A GCTaskQueue* unsynchronized_queue = queue()->unsynchronized_queue();
0N/A GCTaskQueue::destroy(unsynchronized_queue);
0N/A SynchronizedGCTaskQueue::destroy(queue());
0N/A _queue = NULL;
0N/A }
0N/A if (monitor() != NULL) {
0N/A delete monitor();
0N/A _monitor = NULL;
0N/A }
0N/A}
0N/A
2941N/Avoid GCTaskManager::set_active_gang() {
2941N/A _active_workers =
2941N/A AdaptiveSizePolicy::calc_active_workers(workers(),
2941N/A active_workers(),
2941N/A Threads::number_of_non_daemon_threads());
2941N/A
2941N/A assert(!all_workers_active() || active_workers() == ParallelGCThreads,
2941N/A err_msg("all_workers_active() is incorrect: "
2941N/A "active %d ParallelGCThreads %d", active_workers(),
2941N/A ParallelGCThreads));
2941N/A if (TraceDynamicGCThreads) {
2941N/A gclog_or_tty->print_cr("GCTaskManager::set_active_gang(): "
2941N/A "all_workers_active() %d workers %d "
2941N/A "active %d ParallelGCThreads %d ",
2941N/A all_workers_active(), workers(), active_workers(),
2941N/A ParallelGCThreads);
2941N/A }
2941N/A}
2941N/A
2941N/A// Create IdleGCTasks for inactive workers.
2941N/A// Creates tasks in a ResourceArea and assumes
2941N/A// an appropriate ResourceMark.
2941N/Avoid GCTaskManager::task_idle_workers() {
2941N/A {
2941N/A int more_inactive_workers = 0;
2941N/A {
2941N/A // Stop any idle tasks from exiting their IdleGCTask's
2941N/A // and get the count for additional IdleGCTask's under
2941N/A // the GCTaskManager's monitor so that the "more_inactive_workers"
2941N/A // count is correct.
2941N/A MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
2941N/A _idle_inactive_task->set_should_wait(true);
2941N/A // active_workers are a number being requested. idle_workers
2941N/A // are the number currently idle. If all the workers are being
2941N/A // requested to be active but some are already idle, reduce
2941N/A // the number of active_workers to be consistent with the
2941N/A // number of idle_workers. The idle_workers are stuck in
2941N/A // idle tasks and will no longer be release (since a new GC
2941N/A // is starting). Try later to release enough idle_workers
2941N/A // to allow the desired number of active_workers.
2941N/A more_inactive_workers =
2941N/A workers() - active_workers() - idle_workers();
2941N/A if (more_inactive_workers < 0) {
2941N/A int reduced_active_workers = active_workers() + more_inactive_workers;
2941N/A set_active_workers(reduced_active_workers);
2941N/A more_inactive_workers = 0;
2941N/A }
2941N/A if (TraceDynamicGCThreads) {
2941N/A gclog_or_tty->print_cr("JT: %d workers %d active %d "
2941N/A "idle %d more %d",
2941N/A Threads::number_of_non_daemon_threads(),
2941N/A workers(),
2941N/A active_workers(),
2941N/A idle_workers(),
2941N/A more_inactive_workers);
2941N/A }
2941N/A }
2941N/A GCTaskQueue* q = GCTaskQueue::create();
2941N/A for(uint i = 0; i < (uint) more_inactive_workers; i++) {
2941N/A q->enqueue(IdleGCTask::create_on_c_heap());
2941N/A increment_idle_workers();
2941N/A }
2941N/A assert(workers() == active_workers() + idle_workers(),
2941N/A "total workers should equal active + inactive");
2941N/A add_list(q);
2941N/A // GCTaskQueue* q was created in a ResourceArea so a
2941N/A // destroy() call is not needed.
2941N/A }
2941N/A}
2941N/A
2941N/Avoid GCTaskManager::release_idle_workers() {
2941N/A {
2941N/A MutexLockerEx ml(monitor(),
2941N/A Mutex::_no_safepoint_check_flag);
2941N/A _idle_inactive_task->set_should_wait(false);
2941N/A monitor()->notify_all();
2941N/A // Release monitor
2941N/A }
2941N/A}
2941N/A
0N/Avoid GCTaskManager::print_task_time_stamps() {
0N/A for(uint i=0; i<ParallelGCThreads; i++) {
0N/A GCTaskThread* t = thread(i);
0N/A t->print_task_time_stamps();
0N/A }
0N/A}
0N/A
0N/Avoid GCTaskManager::print_threads_on(outputStream* st) {
0N/A uint num_thr = workers();
0N/A for (uint i = 0; i < num_thr; i++) {
0N/A thread(i)->print_on(st);
0N/A st->cr();
0N/A }
0N/A}
0N/A
0N/Avoid GCTaskManager::threads_do(ThreadClosure* tc) {
0N/A assert(tc != NULL, "Null ThreadClosure");
0N/A uint num_thr = workers();
0N/A for (uint i = 0; i < num_thr; i++) {
0N/A tc->do_thread(thread(i));
0N/A }
0N/A}
0N/A
0N/AGCTaskThread* GCTaskManager::thread(uint which) {
0N/A assert(which < workers(), "index out of bounds");
0N/A assert(_thread[which] != NULL, "shouldn't have null thread");
0N/A return _thread[which];
0N/A}
0N/A
0N/Avoid GCTaskManager::set_thread(uint which, GCTaskThread* value) {
0N/A assert(which < workers(), "index out of bounds");
0N/A assert(value != NULL, "shouldn't have null thread");
0N/A _thread[which] = value;
0N/A}
0N/A
0N/Avoid GCTaskManager::add_task(GCTask* task) {
0N/A assert(task != NULL, "shouldn't have null task");
0N/A MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr("GCTaskManager::add_task(" INTPTR_FORMAT " [%s])",
0N/A task, GCTask::Kind::to_string(task->kind()));
0N/A }
0N/A queue()->enqueue(task);
0N/A // Notify with the lock held to avoid missed notifies.
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr(" GCTaskManager::add_task (%s)->notify_all",
0N/A monitor()->name());
0N/A }
0N/A (void) monitor()->notify_all();
0N/A // Release monitor().
0N/A}
0N/A
0N/Avoid GCTaskManager::add_list(GCTaskQueue* list) {
0N/A assert(list != NULL, "shouldn't have null task");
0N/A MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr("GCTaskManager::add_list(%u)", list->length());
0N/A }
0N/A queue()->enqueue(list);
0N/A // Notify with the lock held to avoid missed notifies.
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr(" GCTaskManager::add_list (%s)->notify_all",
0N/A monitor()->name());
0N/A }
0N/A (void) monitor()->notify_all();
0N/A // Release monitor().
0N/A}
0N/A
2941N/A// GC workers wait in get_task() for new work to be added
2941N/A// to the GCTaskManager's queue. When new work is added,
2941N/A// a notify is sent to the waiting GC workers which then
2941N/A// compete to get tasks. If a GC worker wakes up and there
2941N/A// is no work on the queue, it is given a noop_task to execute
2941N/A// and then loops to find more work.
2941N/A
0N/AGCTask* GCTaskManager::get_task(uint which) {
0N/A GCTask* result = NULL;
0N/A // Grab the queue lock.
0N/A MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
0N/A // Wait while the queue is block or
0N/A // there is nothing to do, except maybe release resources.
0N/A while (is_blocked() ||
0N/A (queue()->is_empty() && !should_release_resources(which))) {
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr("GCTaskManager::get_task(%u)"
0N/A " blocked: %s"
0N/A " empty: %s"
0N/A " release: %s",
0N/A which,
0N/A is_blocked() ? "true" : "false",
0N/A queue()->is_empty() ? "true" : "false",
0N/A should_release_resources(which) ? "true" : "false");
0N/A tty->print_cr(" => (%s)->wait()",
0N/A monitor()->name());
0N/A }
0N/A monitor()->wait(Mutex::_no_safepoint_check_flag, 0);
0N/A }
0N/A // We've reacquired the queue lock here.
0N/A // Figure out which condition caused us to exit the loop above.
0N/A if (!queue()->is_empty()) {
0N/A if (UseGCTaskAffinity) {
0N/A result = queue()->dequeue(which);
0N/A } else {
0N/A result = queue()->dequeue();
0N/A }
0N/A if (result->is_barrier_task()) {
0N/A assert(which != sentinel_worker(),
0N/A "blocker shouldn't be bogus");
0N/A set_blocking_worker(which);
0N/A }
0N/A } else {
0N/A // The queue is empty, but we were woken up.
0N/A // Just hand back a Noop task,
0N/A // in case someone wanted us to release resources, or whatever.
0N/A result = noop_task();
0N/A increment_noop_tasks();
0N/A }
0N/A assert(result != NULL, "shouldn't have null task");
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr("GCTaskManager::get_task(%u) => " INTPTR_FORMAT " [%s]",
0N/A which, result, GCTask::Kind::to_string(result->kind()));
0N/A tty->print_cr(" %s", result->name());
0N/A }
2941N/A if (!result->is_idle_task()) {
2941N/A increment_busy_workers();
2941N/A increment_delivered_tasks();
2941N/A }
0N/A return result;
0N/A // Release monitor().
0N/A}
0N/A
0N/Avoid GCTaskManager::note_completion(uint which) {
0N/A MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr("GCTaskManager::note_completion(%u)", which);
0N/A }
0N/A // If we are blocked, check if the completing thread is the blocker.
0N/A if (blocking_worker() == which) {
0N/A assert(blocking_worker() != sentinel_worker(),
0N/A "blocker shouldn't be bogus");
0N/A increment_barriers();
0N/A set_unblocked();
0N/A }
0N/A increment_completed_tasks();
0N/A uint active = decrement_busy_workers();
0N/A if ((active == 0) && (queue()->is_empty())) {
0N/A increment_emptied_queue();
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr(" GCTaskManager::note_completion(%u) done", which);
0N/A }
0N/A // Notify client that we are done.
0N/A NotifyDoneClosure* ndc = notify_done_closure();
0N/A if (ndc != NULL) {
0N/A ndc->notify(this);
0N/A }
0N/A }
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr(" GCTaskManager::note_completion(%u) (%s)->notify_all",
0N/A which, monitor()->name());
0N/A tty->print_cr(" "
0N/A " blocked: %s"
0N/A " empty: %s"
0N/A " release: %s",
0N/A is_blocked() ? "true" : "false",
0N/A queue()->is_empty() ? "true" : "false",
0N/A should_release_resources(which) ? "true" : "false");
0N/A tty->print_cr(" "
0N/A " delivered: %u"
0N/A " completed: %u"
0N/A " barriers: %u"
0N/A " emptied: %u",
0N/A delivered_tasks(),
0N/A completed_tasks(),
0N/A barriers(),
0N/A emptied_queue());
0N/A }
0N/A // Tell everyone that a task has completed.
0N/A (void) monitor()->notify_all();
0N/A // Release monitor().
0N/A}
0N/A
0N/Auint GCTaskManager::increment_busy_workers() {
0N/A assert(queue()->own_lock(), "don't own the lock");
0N/A _busy_workers += 1;
0N/A return _busy_workers;
0N/A}
0N/A
0N/Auint GCTaskManager::decrement_busy_workers() {
0N/A assert(queue()->own_lock(), "don't own the lock");
2941N/A assert(_busy_workers > 0, "About to make a mistake");
0N/A _busy_workers -= 1;
0N/A return _busy_workers;
0N/A}
0N/A
0N/Avoid GCTaskManager::release_all_resources() {
0N/A // If you want this to be done atomically, do it in a BarrierGCTask.
0N/A for (uint i = 0; i < workers(); i += 1) {
0N/A set_resource_flag(i, true);
0N/A }
0N/A}
0N/A
0N/Abool GCTaskManager::should_release_resources(uint which) {
0N/A // This can be done without a lock because each thread reads one element.
0N/A return resource_flag(which);
0N/A}
0N/A
0N/Avoid GCTaskManager::note_release(uint which) {
0N/A // This can be done without a lock because each thread writes one element.
0N/A set_resource_flag(which, false);
0N/A}
0N/A
2941N/A// "list" contains tasks that are ready to execute. Those
2941N/A// tasks are added to the GCTaskManager's queue of tasks and
2941N/A// then the GC workers are notified that there is new work to
2941N/A// do.
2941N/A//
2941N/A// Typically different types of tasks can be added to the "list".
2941N/A// For example in PSScavenge OldToYoungRootsTask, SerialOldToYoungRootsTask,
2941N/A// ScavengeRootsTask, and StealTask tasks are all added to the list
2941N/A// and then the GC workers are notified of new work. The tasks are
2941N/A// handed out in the order in which they are added to the list
2941N/A// (although execution is not necessarily in that order). As long
2941N/A// as any tasks are running the GCTaskManager will wait for execution
2941N/A// to complete. GC workers that execute a stealing task remain in
2941N/A// the stealing task until all stealing tasks have completed. The load
2941N/A// balancing afforded by the stealing tasks work best if the stealing
2941N/A// tasks are added last to the list.
2941N/A
0N/Avoid GCTaskManager::execute_and_wait(GCTaskQueue* list) {
0N/A WaitForBarrierGCTask* fin = WaitForBarrierGCTask::create();
0N/A list->enqueue(fin);
2975N/A // The barrier task will be read by one of the GC
2975N/A // workers once it is added to the list of tasks.
2975N/A // Be sure that is globally visible before the
2975N/A // GC worker reads it (which is after the task is added
2975N/A // to the list of tasks below).
2975N/A OrderAccess::storestore();
0N/A add_list(list);
2941N/A fin->wait_for(true /* reset */);
0N/A // We have to release the barrier tasks!
0N/A WaitForBarrierGCTask::destroy(fin);
0N/A}
0N/A
0N/Abool GCTaskManager::resource_flag(uint which) {
0N/A assert(which < workers(), "index out of bounds");
0N/A return _resource_flag[which];
0N/A}
0N/A
0N/Avoid GCTaskManager::set_resource_flag(uint which, bool value) {
0N/A assert(which < workers(), "index out of bounds");
0N/A _resource_flag[which] = value;
0N/A}
0N/A
0N/A//
0N/A// NoopGCTask
0N/A//
0N/A
0N/ANoopGCTask* NoopGCTask::create() {
0N/A NoopGCTask* result = new NoopGCTask(false);
0N/A return result;
0N/A}
0N/A
0N/ANoopGCTask* NoopGCTask::create_on_c_heap() {
3863N/A NoopGCTask* result = new(ResourceObj::C_HEAP, mtGC) NoopGCTask(true);
0N/A return result;
0N/A}
0N/A
0N/Avoid NoopGCTask::destroy(NoopGCTask* that) {
0N/A if (that != NULL) {
0N/A that->destruct();
0N/A if (that->is_c_heap_obj()) {
0N/A FreeHeap(that);
0N/A }
0N/A }
0N/A}
0N/A
0N/Avoid NoopGCTask::destruct() {
0N/A // This has to know it's superclass structure, just like the constructor.
0N/A this->GCTask::destruct();
0N/A // Nothing else to do.
0N/A}
0N/A
0N/A//
2941N/A// IdleGCTask
2941N/A//
2941N/A
2941N/AIdleGCTask* IdleGCTask::create() {
2941N/A IdleGCTask* result = new IdleGCTask(false);
2975N/A assert(UseDynamicNumberOfGCThreads,
2975N/A "Should only be used with dynamic GC thread");
2941N/A return result;
2941N/A}
2941N/A
2941N/AIdleGCTask* IdleGCTask::create_on_c_heap() {
3863N/A IdleGCTask* result = new(ResourceObj::C_HEAP, mtGC) IdleGCTask(true);
2975N/A assert(UseDynamicNumberOfGCThreads,
2975N/A "Should only be used with dynamic GC thread");
2941N/A return result;
2941N/A}
2941N/A
2941N/Avoid IdleGCTask::do_it(GCTaskManager* manager, uint which) {
2941N/A WaitForBarrierGCTask* wait_for_task = manager->idle_inactive_task();
2941N/A if (TraceGCTaskManager) {
2941N/A tty->print_cr("[" INTPTR_FORMAT "]"
2941N/A " IdleGCTask:::do_it()"
2941N/A " should_wait: %s",
2941N/A this, wait_for_task->should_wait() ? "true" : "false");
2941N/A }
2941N/A MutexLockerEx ml(manager->monitor(), Mutex::_no_safepoint_check_flag);
2941N/A if (TraceDynamicGCThreads) {
2941N/A gclog_or_tty->print_cr("--- idle %d", which);
2941N/A }
2941N/A // Increment has to be done when the idle tasks are created.
2941N/A // manager->increment_idle_workers();
2941N/A manager->monitor()->notify_all();
2941N/A while (wait_for_task->should_wait()) {
2941N/A if (TraceGCTaskManager) {
2941N/A tty->print_cr("[" INTPTR_FORMAT "]"
2941N/A " IdleGCTask::do_it()"
2941N/A " [" INTPTR_FORMAT "] (%s)->wait()",
2941N/A this, manager->monitor(), manager->monitor()->name());
2941N/A }
2941N/A manager->monitor()->wait(Mutex::_no_safepoint_check_flag, 0);
2941N/A }
2941N/A manager->decrement_idle_workers();
2941N/A if (TraceDynamicGCThreads) {
2941N/A gclog_or_tty->print_cr("--- release %d", which);
2941N/A }
2941N/A if (TraceGCTaskManager) {
2941N/A tty->print_cr("[" INTPTR_FORMAT "]"
2941N/A " IdleGCTask::do_it() returns"
2941N/A " should_wait: %s",
2941N/A this, wait_for_task->should_wait() ? "true" : "false");
2941N/A }
2941N/A // Release monitor().
2941N/A}
2941N/A
2941N/Avoid IdleGCTask::destroy(IdleGCTask* that) {
2941N/A if (that != NULL) {
2941N/A that->destruct();
2941N/A if (that->is_c_heap_obj()) {
2941N/A FreeHeap(that);
2941N/A }
2941N/A }
2941N/A}
2941N/A
2941N/Avoid IdleGCTask::destruct() {
2941N/A // This has to know it's superclass structure, just like the constructor.
2941N/A this->GCTask::destruct();
2941N/A // Nothing else to do.
2941N/A}
2941N/A
2941N/A//
0N/A// BarrierGCTask
0N/A//
0N/A
0N/Avoid BarrierGCTask::do_it(GCTaskManager* manager, uint which) {
0N/A // Wait for this to be the only busy worker.
0N/A // ??? I thought of having a StackObj class
0N/A // whose constructor would grab the lock and come to the barrier,
0N/A // and whose destructor would release the lock,
0N/A // but that seems like too much mechanism for two lines of code.
0N/A MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag);
0N/A do_it_internal(manager, which);
0N/A // Release manager->lock().
0N/A}
0N/A
0N/Avoid BarrierGCTask::do_it_internal(GCTaskManager* manager, uint which) {
0N/A // Wait for this to be the only busy worker.
0N/A assert(manager->monitor()->owned_by_self(), "don't own the lock");
0N/A assert(manager->is_blocked(), "manager isn't blocked");
0N/A while (manager->busy_workers() > 1) {
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr("BarrierGCTask::do_it(%u) waiting on %u workers",
0N/A which, manager->busy_workers());
0N/A }
0N/A manager->monitor()->wait(Mutex::_no_safepoint_check_flag, 0);
0N/A }
0N/A}
0N/A
0N/Avoid BarrierGCTask::destruct() {
0N/A this->GCTask::destruct();
0N/A // Nothing else to do.
0N/A}
0N/A
0N/A//
0N/A// ReleasingBarrierGCTask
0N/A//
0N/A
0N/Avoid ReleasingBarrierGCTask::do_it(GCTaskManager* manager, uint which) {
0N/A MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag);
0N/A do_it_internal(manager, which);
0N/A manager->release_all_resources();
0N/A // Release manager->lock().
0N/A}
0N/A
0N/Avoid ReleasingBarrierGCTask::destruct() {
0N/A this->BarrierGCTask::destruct();
0N/A // Nothing else to do.
0N/A}
0N/A
0N/A//
0N/A// NotifyingBarrierGCTask
0N/A//
0N/A
0N/Avoid NotifyingBarrierGCTask::do_it(GCTaskManager* manager, uint which) {
0N/A MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag);
0N/A do_it_internal(manager, which);
0N/A NotifyDoneClosure* ndc = notify_done_closure();
0N/A if (ndc != NULL) {
0N/A ndc->notify(manager);
0N/A }
0N/A // Release manager->lock().
0N/A}
0N/A
0N/Avoid NotifyingBarrierGCTask::destruct() {
0N/A this->BarrierGCTask::destruct();
0N/A // Nothing else to do.
0N/A}
0N/A
0N/A//
0N/A// WaitForBarrierGCTask
0N/A//
0N/AWaitForBarrierGCTask* WaitForBarrierGCTask::create() {
0N/A WaitForBarrierGCTask* result = new WaitForBarrierGCTask(false);
0N/A return result;
0N/A}
0N/A
0N/AWaitForBarrierGCTask* WaitForBarrierGCTask::create_on_c_heap() {
2941N/A WaitForBarrierGCTask* result =
3863N/A new (ResourceObj::C_HEAP, mtGC) WaitForBarrierGCTask(true);
0N/A return result;
0N/A}
0N/A
0N/AWaitForBarrierGCTask::WaitForBarrierGCTask(bool on_c_heap) :
0N/A _is_c_heap_obj(on_c_heap) {
0N/A _monitor = MonitorSupply::reserve();
0N/A set_should_wait(true);
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr("[" INTPTR_FORMAT "]"
0N/A " WaitForBarrierGCTask::WaitForBarrierGCTask()"
0N/A " monitor: " INTPTR_FORMAT,
0N/A this, monitor());
0N/A }
0N/A}
0N/A
0N/Avoid WaitForBarrierGCTask::destroy(WaitForBarrierGCTask* that) {
0N/A if (that != NULL) {
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr("[" INTPTR_FORMAT "]"
0N/A " WaitForBarrierGCTask::destroy()"
0N/A " is_c_heap_obj: %s"
0N/A " monitor: " INTPTR_FORMAT,
0N/A that,
0N/A that->is_c_heap_obj() ? "true" : "false",
0N/A that->monitor());
0N/A }
0N/A that->destruct();
0N/A if (that->is_c_heap_obj()) {
0N/A FreeHeap(that);
0N/A }
0N/A }
0N/A}
0N/A
0N/Avoid WaitForBarrierGCTask::destruct() {
0N/A assert(monitor() != NULL, "monitor should not be NULL");
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr("[" INTPTR_FORMAT "]"
0N/A " WaitForBarrierGCTask::destruct()"
0N/A " monitor: " INTPTR_FORMAT,
0N/A this, monitor());
0N/A }
0N/A this->BarrierGCTask::destruct();
0N/A // Clean up that should be in the destructor,
0N/A // except that ResourceMarks don't call destructors.
0N/A if (monitor() != NULL) {
0N/A MonitorSupply::release(monitor());
0N/A }
0N/A _monitor = (Monitor*) 0xDEAD000F;
0N/A}
0N/A
0N/Avoid WaitForBarrierGCTask::do_it(GCTaskManager* manager, uint which) {
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr("[" INTPTR_FORMAT "]"
0N/A " WaitForBarrierGCTask::do_it() waiting for idle"
0N/A " monitor: " INTPTR_FORMAT,
0N/A this, monitor());
0N/A }
0N/A {
0N/A // First, wait for the barrier to arrive.
0N/A MutexLockerEx ml(manager->lock(), Mutex::_no_safepoint_check_flag);
0N/A do_it_internal(manager, which);
0N/A // Release manager->lock().
0N/A }
0N/A {
0N/A // Then notify the waiter.
0N/A MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
0N/A set_should_wait(false);
0N/A // Waiter doesn't miss the notify in the wait_for method
0N/A // since it checks the flag after grabbing the monitor.
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr("[" INTPTR_FORMAT "]"
0N/A " WaitForBarrierGCTask::do_it()"
0N/A " [" INTPTR_FORMAT "] (%s)->notify_all()",
0N/A this, monitor(), monitor()->name());
0N/A }
0N/A monitor()->notify_all();
0N/A // Release monitor().
0N/A }
0N/A}
0N/A
2941N/Avoid WaitForBarrierGCTask::wait_for(bool reset) {
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr("[" INTPTR_FORMAT "]"
0N/A " WaitForBarrierGCTask::wait_for()"
0N/A " should_wait: %s",
0N/A this, should_wait() ? "true" : "false");
0N/A }
0N/A {
0N/A // Grab the lock and check again.
0N/A MutexLockerEx ml(monitor(), Mutex::_no_safepoint_check_flag);
0N/A while (should_wait()) {
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr("[" INTPTR_FORMAT "]"
0N/A " WaitForBarrierGCTask::wait_for()"
0N/A " [" INTPTR_FORMAT "] (%s)->wait()",
0N/A this, monitor(), monitor()->name());
0N/A }
0N/A monitor()->wait(Mutex::_no_safepoint_check_flag, 0);
0N/A }
0N/A // Reset the flag in case someone reuses this task.
2941N/A if (reset) {
2941N/A set_should_wait(true);
2941N/A }
0N/A if (TraceGCTaskManager) {
0N/A tty->print_cr("[" INTPTR_FORMAT "]"
0N/A " WaitForBarrierGCTask::wait_for() returns"
0N/A " should_wait: %s",
0N/A this, should_wait() ? "true" : "false");
0N/A }
0N/A // Release monitor().
0N/A }
0N/A}
0N/A
0N/AMutex* MonitorSupply::_lock = NULL;
0N/AGrowableArray<Monitor*>* MonitorSupply::_freelist = NULL;
0N/A
0N/AMonitor* MonitorSupply::reserve() {
0N/A Monitor* result = NULL;
0N/A // Lazy initialization: possible race.
0N/A if (lock() == NULL) {
0N/A _lock = new Mutex(Mutex::barrier, // rank
0N/A "MonitorSupply mutex", // name
0N/A Mutex::_allow_vm_block_flag); // allow_vm_block
0N/A }
0N/A {
0N/A MutexLockerEx ml(lock());
0N/A // Lazy initialization.
0N/A if (freelist() == NULL) {
0N/A _freelist =
3863N/A new(ResourceObj::C_HEAP, mtGC) GrowableArray<Monitor*>(ParallelGCThreads,
0N/A true);
0N/A }
0N/A if (! freelist()->is_empty()) {
0N/A result = freelist()->pop();
0N/A } else {
0N/A result = new Monitor(Mutex::barrier, // rank
0N/A "MonitorSupply monitor", // name
0N/A Mutex::_allow_vm_block_flag); // allow_vm_block
0N/A }
0N/A guarantee(result != NULL, "shouldn't return NULL");
0N/A assert(!result->is_locked(), "shouldn't be locked");
0N/A // release lock().
0N/A }
0N/A return result;
0N/A}
0N/A
0N/Avoid MonitorSupply::release(Monitor* instance) {
0N/A assert(instance != NULL, "shouldn't release NULL");
0N/A assert(!instance->is_locked(), "shouldn't be locked");
0N/A {
0N/A MutexLockerEx ml(lock());
0N/A freelist()->push(instance);
0N/A // release lock().
0N/A }
0N/A}