aoqi@0: /* aoqi@0: * Copyright (c) 2005, 2014, Oracle and/or its affiliates. All rights reserved. aoqi@0: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. aoqi@0: * aoqi@0: * This code is free software; you can redistribute it and/or modify it aoqi@0: * under the terms of the GNU General Public License version 2 only, as aoqi@0: * published by the Free Software Foundation. aoqi@0: * aoqi@0: * This code is distributed in the hope that it will be useful, but WITHOUT aoqi@0: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or aoqi@0: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License aoqi@0: * version 2 for more details (a copy is included in the LICENSE file that aoqi@0: * accompanied this code). aoqi@0: * aoqi@0: * You should have received a copy of the GNU General Public License version aoqi@0: * 2 along with this work; if not, write to the Free Software Foundation, aoqi@0: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. aoqi@0: * aoqi@0: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA aoqi@0: * or visit www.oracle.com if you need additional information or have any aoqi@0: * questions. aoqi@0: * aoqi@0: */ aoqi@0: aoqi@0: #include "precompiled.hpp" aoqi@0: #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.inline.hpp" aoqi@0: #include "gc_implementation/concurrentMarkSweep/concurrentMarkSweepThread.hpp" aoqi@0: #include "gc_implementation/concurrentMarkSweep/vmCMSOperations.hpp" aoqi@0: #include "gc_implementation/shared/gcTimer.hpp" aoqi@0: #include "gc_implementation/shared/gcTraceTime.hpp" aoqi@0: #include "gc_implementation/shared/isGCActiveMark.hpp" aoqi@0: #include "memory/gcLocker.inline.hpp" aoqi@0: #include "runtime/interfaceSupport.hpp" aoqi@0: #include "runtime/os.hpp" aoqi@0: #include "utilities/dtrace.hpp" aoqi@0: aoqi@0: PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC aoqi@0: aoqi@0: #ifndef USDT2 aoqi@0: HS_DTRACE_PROBE_DECL(hs_private, cms__initmark__begin); aoqi@0: HS_DTRACE_PROBE_DECL(hs_private, cms__initmark__end); aoqi@0: aoqi@0: HS_DTRACE_PROBE_DECL(hs_private, cms__remark__begin); aoqi@0: HS_DTRACE_PROBE_DECL(hs_private, cms__remark__end); aoqi@0: #endif /* !USDT2 */ aoqi@0: aoqi@0: ////////////////////////////////////////////////////////// aoqi@0: // Methods in abstract class VM_CMS_Operation aoqi@0: ////////////////////////////////////////////////////////// aoqi@0: void VM_CMS_Operation::acquire_pending_list_lock() { aoqi@0: // The caller may block while communicating aoqi@0: // with the SLT thread in order to acquire/release the PLL. aoqi@0: ConcurrentMarkSweepThread::slt()-> aoqi@0: manipulatePLL(SurrogateLockerThread::acquirePLL); aoqi@0: } aoqi@0: aoqi@0: void VM_CMS_Operation::release_and_notify_pending_list_lock() { aoqi@0: // The caller may block while communicating aoqi@0: // with the SLT thread in order to acquire/release the PLL. aoqi@0: ConcurrentMarkSweepThread::slt()-> aoqi@0: manipulatePLL(SurrogateLockerThread::releaseAndNotifyPLL); aoqi@0: } aoqi@0: aoqi@0: void VM_CMS_Operation::verify_before_gc() { aoqi@0: if (VerifyBeforeGC && aoqi@0: GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { aoqi@0: GCTraceTime tm("Verify Before", false, false, _collector->_gc_timer_cm); aoqi@0: HandleMark hm; aoqi@0: FreelistLocker x(_collector); aoqi@0: MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); aoqi@0: Universe::heap()->prepare_for_verify(); aoqi@0: Universe::verify(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: void VM_CMS_Operation::verify_after_gc() { aoqi@0: if (VerifyAfterGC && aoqi@0: GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { aoqi@0: GCTraceTime tm("Verify After", false, false, _collector->_gc_timer_cm); aoqi@0: HandleMark hm; aoqi@0: FreelistLocker x(_collector); aoqi@0: MutexLockerEx y(_collector->bitMapLock(), Mutex::_no_safepoint_check_flag); aoqi@0: Universe::verify(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: bool VM_CMS_Operation::lost_race() const { aoqi@0: if (CMSCollector::abstract_state() == CMSCollector::Idling) { aoqi@0: // We lost a race to a foreground collection aoqi@0: // -- there's nothing to do aoqi@0: return true; aoqi@0: } aoqi@0: assert(CMSCollector::abstract_state() == legal_state(), aoqi@0: "Inconsistent collector state?"); aoqi@0: return false; aoqi@0: } aoqi@0: aoqi@0: bool VM_CMS_Operation::doit_prologue() { aoqi@0: assert(Thread::current()->is_ConcurrentGC_thread(), "just checking"); aoqi@0: assert(!CMSCollector::foregroundGCShouldWait(), "Possible deadlock"); aoqi@0: assert(!ConcurrentMarkSweepThread::cms_thread_has_cms_token(), aoqi@0: "Possible deadlock"); aoqi@0: aoqi@0: if (needs_pll()) { aoqi@0: acquire_pending_list_lock(); aoqi@0: } aoqi@0: // Get the Heap_lock after the pending_list_lock. aoqi@0: Heap_lock->lock(); aoqi@0: if (lost_race()) { aoqi@0: assert(_prologue_succeeded == false, "Initialized in c'tor"); aoqi@0: Heap_lock->unlock(); aoqi@0: if (needs_pll()) { aoqi@0: release_and_notify_pending_list_lock(); aoqi@0: } aoqi@0: } else { aoqi@0: _prologue_succeeded = true; aoqi@0: } aoqi@0: return _prologue_succeeded; aoqi@0: } aoqi@0: aoqi@0: void VM_CMS_Operation::doit_epilogue() { aoqi@0: assert(Thread::current()->is_ConcurrentGC_thread(), "just checking"); aoqi@0: assert(!CMSCollector::foregroundGCShouldWait(), "Possible deadlock"); aoqi@0: assert(!ConcurrentMarkSweepThread::cms_thread_has_cms_token(), aoqi@0: "Possible deadlock"); aoqi@0: aoqi@0: // Release the Heap_lock first. aoqi@0: Heap_lock->unlock(); aoqi@0: if (needs_pll()) { aoqi@0: release_and_notify_pending_list_lock(); aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: ////////////////////////////////////////////////////////// aoqi@0: // Methods in class VM_CMS_Initial_Mark aoqi@0: ////////////////////////////////////////////////////////// aoqi@0: void VM_CMS_Initial_Mark::doit() { aoqi@0: if (lost_race()) { aoqi@0: // Nothing to do. aoqi@0: return; aoqi@0: } aoqi@0: #ifndef USDT2 aoqi@0: HS_DTRACE_PROBE(hs_private, cms__initmark__begin); aoqi@0: #else /* USDT2 */ aoqi@0: HS_PRIVATE_CMS_INITMARK_BEGIN( aoqi@0: ); aoqi@0: #endif /* USDT2 */ aoqi@0: aoqi@0: _collector->_gc_timer_cm->register_gc_pause_start("Initial Mark"); aoqi@0: aoqi@0: GenCollectedHeap* gch = GenCollectedHeap::heap(); aoqi@0: GCCauseSetter gccs(gch, GCCause::_cms_initial_mark); aoqi@0: aoqi@0: VM_CMS_Operation::verify_before_gc(); aoqi@0: aoqi@0: IsGCActiveMark x; // stop-world GC active aoqi@0: _collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsInitial, gch->gc_cause()); aoqi@0: aoqi@0: VM_CMS_Operation::verify_after_gc(); aoqi@0: aoqi@0: _collector->_gc_timer_cm->register_gc_pause_end(); aoqi@0: aoqi@0: #ifndef USDT2 aoqi@0: HS_DTRACE_PROBE(hs_private, cms__initmark__end); aoqi@0: #else /* USDT2 */ aoqi@0: HS_PRIVATE_CMS_INITMARK_END( aoqi@0: ); aoqi@0: #endif /* USDT2 */ aoqi@0: } aoqi@0: aoqi@0: ////////////////////////////////////////////////////////// aoqi@0: // Methods in class VM_CMS_Final_Remark_Operation aoqi@0: ////////////////////////////////////////////////////////// aoqi@0: void VM_CMS_Final_Remark::doit() { aoqi@0: if (lost_race()) { aoqi@0: // Nothing to do. aoqi@0: return; aoqi@0: } aoqi@0: #ifndef USDT2 aoqi@0: HS_DTRACE_PROBE(hs_private, cms__remark__begin); aoqi@0: #else /* USDT2 */ aoqi@0: HS_PRIVATE_CMS_REMARK_BEGIN( aoqi@0: ); aoqi@0: #endif /* USDT2 */ aoqi@0: aoqi@0: _collector->_gc_timer_cm->register_gc_pause_start("Final Mark"); aoqi@0: aoqi@0: GenCollectedHeap* gch = GenCollectedHeap::heap(); aoqi@0: GCCauseSetter gccs(gch, GCCause::_cms_final_remark); aoqi@0: aoqi@0: VM_CMS_Operation::verify_before_gc(); aoqi@0: aoqi@0: IsGCActiveMark x; // stop-world GC active aoqi@0: _collector->do_CMS_operation(CMSCollector::CMS_op_checkpointRootsFinal, gch->gc_cause()); aoqi@0: aoqi@0: VM_CMS_Operation::verify_after_gc(); aoqi@0: aoqi@0: _collector->save_heap_summary(); aoqi@0: _collector->_gc_timer_cm->register_gc_pause_end(); aoqi@0: aoqi@0: #ifndef USDT2 aoqi@0: HS_DTRACE_PROBE(hs_private, cms__remark__end); aoqi@0: #else /* USDT2 */ aoqi@0: HS_PRIVATE_CMS_REMARK_END( aoqi@0: ); aoqi@0: #endif /* USDT2 */ aoqi@0: } aoqi@0: aoqi@0: // VM operation to invoke a concurrent collection of a aoqi@0: // GenCollectedHeap heap. aoqi@0: void VM_GenCollectFullConcurrent::doit() { aoqi@0: assert(Thread::current()->is_VM_thread(), "Should be VM thread"); aoqi@0: assert(GCLockerInvokesConcurrent || ExplicitGCInvokesConcurrent, "Unexpected"); aoqi@0: aoqi@0: GenCollectedHeap* gch = GenCollectedHeap::heap(); aoqi@0: if (_gc_count_before == gch->total_collections()) { aoqi@0: // The "full" of do_full_collection call below "forces" aoqi@0: // a collection; the second arg, 0, below ensures that aoqi@0: // only the young gen is collected. XXX In the future, aoqi@0: // we'll probably need to have something in this interface aoqi@0: // to say do this only if we are sure we will not bail aoqi@0: // out to a full collection in this attempt, but that's aoqi@0: // for the future. aoqi@0: assert(SafepointSynchronize::is_at_safepoint(), aoqi@0: "We can only be executing this arm of if at a safepoint"); aoqi@0: GCCauseSetter gccs(gch, _gc_cause); aoqi@0: gch->do_full_collection(gch->must_clear_all_soft_refs(), aoqi@0: 0 /* collect only youngest gen */); aoqi@0: } // Else no need for a foreground young gc aoqi@0: assert((_gc_count_before < gch->total_collections()) || aoqi@0: (GC_locker::is_active() /* gc may have been skipped */ aoqi@0: && (_gc_count_before == gch->total_collections())), aoqi@0: "total_collections() should be monotonically increasing"); aoqi@0: aoqi@0: MutexLockerEx x(FullGCCount_lock, Mutex::_no_safepoint_check_flag); aoqi@0: assert(_full_gc_count_before <= gch->total_full_collections(), "Error"); aoqi@0: if (gch->total_full_collections() == _full_gc_count_before) { aoqi@0: // Disable iCMS until the full collection is done, and aoqi@0: // remember that we did so. aoqi@0: CMSCollector::disable_icms(); aoqi@0: _disabled_icms = true; aoqi@0: // In case CMS thread was in icms_wait(), wake it up. aoqi@0: CMSCollector::start_icms(); aoqi@0: // Nudge the CMS thread to start a concurrent collection. aoqi@0: CMSCollector::request_full_gc(_full_gc_count_before, _gc_cause); aoqi@0: } else { aoqi@0: assert(_full_gc_count_before < gch->total_full_collections(), "Error"); aoqi@0: FullGCCount_lock->notify_all(); // Inform the Java thread its work is done aoqi@0: } aoqi@0: } aoqi@0: aoqi@0: bool VM_GenCollectFullConcurrent::evaluate_at_safepoint() const { aoqi@0: Thread* thr = Thread::current(); aoqi@0: assert(thr != NULL, "Unexpected tid"); aoqi@0: if (!thr->is_Java_thread()) { aoqi@0: assert(thr->is_VM_thread(), "Expected to be evaluated by VM thread"); aoqi@0: GenCollectedHeap* gch = GenCollectedHeap::heap(); aoqi@0: if (_gc_count_before != gch->total_collections()) { aoqi@0: // No need to do a young gc, we'll just nudge the CMS thread aoqi@0: // in the doit() method above, to be executed soon. aoqi@0: assert(_gc_count_before < gch->total_collections(), aoqi@0: "total_collections() should be monotnically increasing"); aoqi@0: return false; // no need for foreground young gc aoqi@0: } aoqi@0: } aoqi@0: return true; // may still need foreground young gc aoqi@0: } aoqi@0: aoqi@0: aoqi@0: void VM_GenCollectFullConcurrent::doit_epilogue() { aoqi@0: Thread* thr = Thread::current(); aoqi@0: assert(thr->is_Java_thread(), "just checking"); aoqi@0: JavaThread* jt = (JavaThread*)thr; aoqi@0: // Release the Heap_lock first. aoqi@0: Heap_lock->unlock(); aoqi@0: release_and_notify_pending_list_lock(); aoqi@0: aoqi@0: // It is fine to test whether completed collections has aoqi@0: // exceeded our request count without locking because aoqi@0: // the completion count is monotonically increasing; aoqi@0: // this will break for very long-running apps when the aoqi@0: // count overflows and wraps around. XXX fix me !!! aoqi@0: // e.g. at the rate of 1 full gc per ms, this could aoqi@0: // overflow in about 1000 years. aoqi@0: GenCollectedHeap* gch = GenCollectedHeap::heap(); aoqi@0: if (_gc_cause != GCCause::_gc_locker && aoqi@0: gch->total_full_collections_completed() <= _full_gc_count_before) { aoqi@0: // maybe we should change the condition to test _gc_cause == aoqi@0: // GCCause::_java_lang_system_gc, instead of aoqi@0: // _gc_cause != GCCause::_gc_locker aoqi@0: assert(_gc_cause == GCCause::_java_lang_system_gc, aoqi@0: "the only way to get here if this was a System.gc()-induced GC"); aoqi@0: assert(ExplicitGCInvokesConcurrent, "Error"); aoqi@0: // Now, wait for witnessing concurrent gc cycle to complete, aoqi@0: // but do so in native mode, because we want to lock the aoqi@0: // FullGCEvent_lock, which may be needed by the VM thread aoqi@0: // or by the CMS thread, so we do not want to be suspended aoqi@0: // while holding that lock. aoqi@0: ThreadToNativeFromVM native(jt); aoqi@0: MutexLockerEx ml(FullGCCount_lock, Mutex::_no_safepoint_check_flag); aoqi@0: // Either a concurrent or a stop-world full gc is sufficient aoqi@0: // witness to our request. aoqi@0: while (gch->total_full_collections_completed() <= _full_gc_count_before) { aoqi@0: FullGCCount_lock->wait(Mutex::_no_safepoint_check_flag); aoqi@0: } aoqi@0: } aoqi@0: // Enable iCMS back if we disabled it earlier. aoqi@0: if (_disabled_icms) { aoqi@0: CMSCollector::enable_icms(); aoqi@0: } aoqi@0: }