duke@435: duke@435: /* mikael@4153: * Copyright (c) 2002, 2012, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: stefank@2314: #include "precompiled.hpp" stefank@2314: #include "gc_implementation/parallelScavenge/gcTaskManager.hpp" stefank@2314: #include "gc_implementation/parallelScavenge/gcTaskThread.hpp" stefank@2314: #include "memory/allocation.hpp" stefank@2314: #include "memory/allocation.inline.hpp" stefank@2314: #include "memory/resourceArea.hpp" stefank@2314: #include "runtime/handles.hpp" stefank@2314: #include "runtime/handles.inline.hpp" stefank@2314: #include "runtime/os.hpp" stefank@2314: #include "runtime/thread.hpp" duke@435: duke@435: GCTaskThread::GCTaskThread(GCTaskManager* manager, duke@435: uint which, duke@435: uint processor_id) : duke@435: _manager(manager), duke@435: _processor_id(processor_id), duke@435: _time_stamps(NULL), duke@435: _time_stamp_index(0) duke@435: { duke@435: if (!os::create_thread(this, os::pgc_thread)) ccheung@4993: vm_exit_out_of_memory(0, OOM_MALLOC_ERROR, "Cannot create GC thread. Out of system resources."); duke@435: duke@435: if (PrintGCTaskTimeStamps) { zgu@3900: _time_stamps = NEW_C_HEAP_ARRAY(GCTaskTimeStamp, GCTaskTimeStampEntries, mtGC); duke@435: duke@435: guarantee(_time_stamps != NULL, "Sanity"); duke@435: } duke@435: set_id(which); duke@435: set_name("GC task thread#%d (ParallelGC)", which); duke@435: } duke@435: duke@435: GCTaskThread::~GCTaskThread() { duke@435: if (_time_stamps != NULL) { zgu@3900: FREE_C_HEAP_ARRAY(GCTaskTimeStamp, _time_stamps, mtGC); duke@435: } duke@435: } duke@435: duke@435: void GCTaskThread::start() { duke@435: os::start_thread(this); duke@435: } duke@435: duke@435: GCTaskTimeStamp* GCTaskThread::time_stamp_at(uint index) { duke@435: guarantee(index < GCTaskTimeStampEntries, "increase GCTaskTimeStampEntries"); duke@435: duke@435: return &(_time_stamps[index]); duke@435: } duke@435: duke@435: void GCTaskThread::print_task_time_stamps() { duke@435: assert(PrintGCTaskTimeStamps, "Sanity"); duke@435: assert(_time_stamps != NULL, "Sanity (Probably set PrintGCTaskTimeStamps late)"); duke@435: duke@435: tty->print_cr("GC-Thread %u entries: %d", id(), _time_stamp_index); duke@435: for(uint i=0; i<_time_stamp_index; i++) { duke@435: GCTaskTimeStamp* time_stamp = time_stamp_at(i); duke@435: tty->print_cr("\t[ %s " INT64_FORMAT " " INT64_FORMAT " ]", duke@435: time_stamp->name(), duke@435: time_stamp->entry_time(), duke@435: time_stamp->exit_time()); duke@435: } duke@435: duke@435: // Reset after dumping the data duke@435: _time_stamp_index = 0; duke@435: } duke@435: duke@435: void GCTaskThread::print_on(outputStream* st) const { duke@435: st->print("\"%s\" ", name()); duke@435: Thread::print_on(st); duke@435: st->cr(); duke@435: } duke@435: jmasa@3294: // GC workers get tasks from the GCTaskManager and execute jmasa@3294: // them in this method. If there are no tasks to execute, jmasa@3294: // the GC workers wait in the GCTaskManager's get_task() jmasa@3294: // for tasks to be enqueued for execution. jmasa@3294: duke@435: void GCTaskThread::run() { duke@435: // Set up the thread for stack overflow support duke@435: this->record_stack_base_and_size(); duke@435: this->initialize_thread_local_storage(); duke@435: // Bind yourself to your processor. duke@435: if (processor_id() != GCTaskManager::sentinel_worker()) { duke@435: if (TraceGCTaskThread) { duke@435: tty->print_cr("GCTaskThread::run: " duke@435: " binding to processor %u", processor_id()); duke@435: } duke@435: if (!os::bind_to_processor(processor_id())) { duke@435: DEBUG_ONLY( duke@435: warning("Couldn't bind GCTaskThread %u to processor %u", duke@435: which(), processor_id()); duke@435: ) duke@435: } duke@435: } duke@435: // Part of thread setup. duke@435: // ??? Are these set up once here to make subsequent ones fast? duke@435: HandleMark hm_outer; duke@435: ResourceMark rm_outer; duke@435: duke@435: TimeStamp timer; duke@435: duke@435: for (;/* ever */;) { duke@435: // These are so we can flush the resources allocated in the inner loop. duke@435: HandleMark hm_inner; duke@435: ResourceMark rm_inner; duke@435: for (; /* break */; ) { duke@435: // This will block until there is a task to be gotten. duke@435: GCTask* task = manager()->get_task(which()); jmasa@3328: // Record if this is an idle task for later use. jmasa@3328: bool is_idle_task = task->is_idle_task(); duke@435: // In case the update is costly duke@435: if (PrintGCTaskTimeStamps) { duke@435: timer.update(); duke@435: } duke@435: duke@435: jlong entry_time = timer.ticks(); duke@435: char* name = task->name(); duke@435: jmasa@3328: // If this is the barrier task, it can be destroyed jmasa@3328: // by the GC task manager once the do_it() executes. duke@435: task->do_it(manager(), which()); duke@435: jmasa@3328: // Use the saved value of is_idle_task because references jmasa@3328: // using "task" are not reliable for the barrier task. jmasa@3328: if (!is_idle_task) { jmasa@3294: manager()->note_completion(which()); duke@435: jmasa@3294: if (PrintGCTaskTimeStamps) { jmasa@3294: assert(_time_stamps != NULL, jmasa@3294: "Sanity (PrintGCTaskTimeStamps set late?)"); duke@435: jmasa@3294: timer.update(); duke@435: jmasa@3294: GCTaskTimeStamp* time_stamp = time_stamp_at(_time_stamp_index++); jmasa@3294: jmasa@3294: time_stamp->set_name(name); jmasa@3294: time_stamp->set_entry_time(entry_time); jmasa@3294: time_stamp->set_exit_time(timer.ticks()); jmasa@3294: } jmasa@3294: } else { jmasa@3294: // idle tasks complete outside the normal accounting jmasa@3294: // so that a task can complete without waiting for idle tasks. jmasa@3294: // They have to be terminated separately. jmasa@3294: IdleGCTask::destroy((IdleGCTask*)task); jmasa@3294: set_is_working(true); duke@435: } duke@435: duke@435: // Check if we should release our inner resources. duke@435: if (manager()->should_release_resources(which())) { duke@435: manager()->note_release(which()); duke@435: break; duke@435: } duke@435: } duke@435: } duke@435: }