duke@435: /* never@3494: * Copyright (c) 1997, 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 "memory/gcLocker.inline.hpp" stefank@2314: #include "memory/resourceArea.hpp" stefank@2314: #include "memory/sharedHeap.hpp" duke@435: duke@435: volatile jint GC_locker::_jni_lock_count = 0; duke@435: volatile jint GC_locker::_lock_count = 0; duke@435: volatile bool GC_locker::_needs_gc = false; duke@435: volatile bool GC_locker::_doing_gc = false; never@3494: never@3494: #ifdef ASSERT never@3494: volatile jint GC_locker::_debug_jni_lock_count = 0; never@3494: #endif never@3494: never@3494: never@3494: #ifdef ASSERT never@3494: void GC_locker::verify_critical_count() { never@3494: if (SafepointSynchronize::is_at_safepoint()) { never@3494: assert(!needs_gc() || _debug_jni_lock_count == _jni_lock_count, "must agree"); never@3494: int count = 0; never@3494: // Count the number of threads with critical operations in progress never@3494: for (JavaThread* thr = Threads::first(); thr; thr = thr->next()) { never@3494: if (thr->in_critical()) { never@3494: count++; never@3494: } never@3494: } never@3494: if (_jni_lock_count != count) { never@3494: tty->print_cr("critical counts don't match: %d != %d", _jni_lock_count, count); never@3494: for (JavaThread* thr = Threads::first(); thr; thr = thr->next()) { never@3494: if (thr->in_critical()) { never@3494: tty->print_cr(INTPTR_FORMAT " in_critical %d", thr, thr->in_critical()); never@3494: } never@3494: } never@3494: } never@3494: assert(_jni_lock_count == count, "must be equal"); never@3494: } never@3494: } never@3494: #endif never@3494: never@3494: bool GC_locker::check_active_before_gc() { never@3494: assert(SafepointSynchronize::is_at_safepoint(), "only read at safepoint"); never@3494: if (is_active() && !_needs_gc) { never@3494: verify_critical_count(); never@3494: _needs_gc = true; never@3494: if (PrintJNIGCStalls && PrintGCDetails) { never@3494: ResourceMark rm; // JavaThread::name() allocates to convert to UTF8 never@3571: gclog_or_tty->print_cr("%.3f: Setting _needs_gc. Thread \"%s\" %d locked.", never@3571: gclog_or_tty->time_stamp().seconds(), Thread::current()->name(), _jni_lock_count); never@3494: } never@3494: never@3494: } never@3494: return is_active(); never@3494: } duke@435: duke@435: void GC_locker::stall_until_clear() { duke@435: assert(!JavaThread::current()->in_critical(), "Would deadlock"); never@3494: MutexLocker ml(JNICritical_lock); never@3494: never@3494: if (needs_gc()) { never@3494: if (PrintJNIGCStalls && PrintGCDetails) { never@3494: ResourceMark rm; // JavaThread::name() allocates to convert to UTF8 never@3571: gclog_or_tty->print_cr("%.3f: Allocation failed. Thread \"%s\" is stalled by JNI critical section, %d locked.", never@3571: gclog_or_tty->time_stamp().seconds(), Thread::current()->name(), _jni_lock_count); never@3494: } apetrusenko@574: } never@3494: duke@435: // Wait for _needs_gc to be cleared never@3494: while (needs_gc()) { duke@435: JNICritical_lock->wait(); duke@435: } duke@435: } duke@435: never@3494: void GC_locker::jni_lock(JavaThread* thread) { never@3494: assert(!thread->in_critical(), "shouldn't currently be in a critical region"); duke@435: MutexLocker mu(JNICritical_lock); duke@435: // Block entering threads if we know at least one thread is in a duke@435: // JNI critical region and we need a GC. duke@435: // We check that at least one thread is in a critical region before duke@435: // blocking because blocked threads are woken up by a thread exiting duke@435: // a JNI critical region. never@3494: while ((needs_gc() && is_jni_active()) || _doing_gc) { duke@435: JNICritical_lock->wait(); duke@435: } never@3494: thread->enter_critical(); never@3494: _jni_lock_count++; never@3494: increment_debug_jni_lock_count(); duke@435: } duke@435: never@3494: void GC_locker::jni_unlock(JavaThread* thread) { never@3494: assert(thread->in_last_critical(), "should be exiting critical region"); duke@435: MutexLocker mu(JNICritical_lock); never@3494: _jni_lock_count--; never@3494: decrement_debug_jni_lock_count(); never@3494: thread->exit_critical(); duke@435: if (needs_gc() && !is_jni_active()) { duke@435: // We're the last thread out. Cause a GC to occur. duke@435: // GC will also check is_active, so this check is not duke@435: // strictly needed. It's added here to make it clear that duke@435: // the GC will NOT be performed if any other caller duke@435: // of GC_locker::lock() still needs GC locked. stefank@5769: if (!is_active_internal()) { duke@435: _doing_gc = true; duke@435: { duke@435: // Must give up the lock while at a safepoint duke@435: MutexUnlocker munlock(JNICritical_lock); never@3494: if (PrintJNIGCStalls && PrintGCDetails) { never@3494: ResourceMark rm; // JavaThread::name() allocates to convert to UTF8 never@3571: gclog_or_tty->print_cr("%.3f: Thread \"%s\" is performing GC after exiting critical section, %d locked", never@3571: gclog_or_tty->time_stamp().seconds(), Thread::current()->name(), _jni_lock_count); never@3494: } duke@435: Universe::heap()->collect(GCCause::_gc_locker); duke@435: } duke@435: _doing_gc = false; duke@435: } never@3494: never@3494: _needs_gc = false; duke@435: JNICritical_lock->notify_all(); duke@435: } duke@435: } duke@435: duke@435: // Implementation of No_GC_Verifier duke@435: duke@435: #ifdef ASSERT duke@435: duke@435: No_GC_Verifier::No_GC_Verifier(bool verifygc) { duke@435: _verifygc = verifygc; duke@435: if (_verifygc) { duke@435: CollectedHeap* h = Universe::heap(); duke@435: assert(!h->is_gc_active(), "GC active during No_GC_Verifier"); duke@435: _old_invocations = h->total_collections(); duke@435: } duke@435: } duke@435: duke@435: duke@435: No_GC_Verifier::~No_GC_Verifier() { duke@435: if (_verifygc) { duke@435: CollectedHeap* h = Universe::heap(); duke@435: assert(!h->is_gc_active(), "GC active during No_GC_Verifier"); duke@435: if (_old_invocations != h->total_collections()) { duke@435: fatal("collection in a No_GC_Verifier secured function"); duke@435: } duke@435: } duke@435: } duke@435: duke@435: Pause_No_GC_Verifier::Pause_No_GC_Verifier(No_GC_Verifier * ngcv) { duke@435: _ngcv = ngcv; duke@435: if (_ngcv->_verifygc) { duke@435: // if we were verifying, then make sure that nothing is duke@435: // wrong before we "pause" verification duke@435: CollectedHeap* h = Universe::heap(); duke@435: assert(!h->is_gc_active(), "GC active during No_GC_Verifier"); duke@435: if (_ngcv->_old_invocations != h->total_collections()) { duke@435: fatal("collection in a No_GC_Verifier secured function"); duke@435: } duke@435: } duke@435: } duke@435: duke@435: duke@435: Pause_No_GC_Verifier::~Pause_No_GC_Verifier() { duke@435: if (_ngcv->_verifygc) { duke@435: // if we were verifying before, then reenable verification duke@435: CollectedHeap* h = Universe::heap(); duke@435: assert(!h->is_gc_active(), "GC active during No_GC_Verifier"); duke@435: _ngcv->_old_invocations = h->total_collections(); duke@435: } duke@435: } duke@435: duke@435: duke@435: // JRT_LEAF rules: duke@435: // A JRT_LEAF method may not interfere with safepointing by duke@435: // 1) acquiring or blocking on a Mutex or JavaLock - checked duke@435: // 2) allocating heap memory - checked duke@435: // 3) executing a VM operation - checked duke@435: // 4) executing a system call (including malloc) that could block or grab a lock duke@435: // 5) invoking GC duke@435: // 6) reaching a safepoint duke@435: // 7) running too long duke@435: // Nor may any method it calls. duke@435: JRT_Leaf_Verifier::JRT_Leaf_Verifier() duke@435: : No_Safepoint_Verifier(true, JRT_Leaf_Verifier::should_verify_GC()) duke@435: { duke@435: } duke@435: duke@435: JRT_Leaf_Verifier::~JRT_Leaf_Verifier() duke@435: { duke@435: } duke@435: duke@435: bool JRT_Leaf_Verifier::should_verify_GC() { duke@435: switch (JavaThread::current()->thread_state()) { duke@435: case _thread_in_Java: duke@435: // is in a leaf routine, there must be no safepoint. duke@435: return true; duke@435: case _thread_in_native: duke@435: // A native thread is not subject to safepoints. duke@435: // Even while it is in a leaf routine, GC is ok duke@435: return false; duke@435: default: duke@435: // Leaf routines cannot be called from other contexts. duke@435: ShouldNotReachHere(); duke@435: return false; duke@435: } duke@435: } duke@435: #endif