void GC_locker::jni_unlock_slow() { MutexLocker mu(JNICritical_lock); jni_unlock(); if (needs_gc() && !is_jni_active()) { // We're the last thread out. Cause a GC to occur. // GC will also check is_active, so this check is not // strictly needed. It's added here to make it clear that // the GC will NOT be performed if any other caller // of GC_locker::lock() still needs GC locked. if (!is_active()) { _doing_gc = true; { // Must give up the lock while at a safepoint MutexUnlocker munlock(JNICritical_lock); Universe::heap()->collect(GCCause::_gc_locker); } _doing_gc = false; } clear_needs_gc(); JNICritical_lock->notify_all(); } }
void GC_locker::jni_unlock_slow() { // There isn't a slow path jni_unlock with GPGC or PGC. assert0((!UseGenPauselessGC)); MutexLocker mu(JNICritical_lock); jlong old_state; jlong new_state; bool do_a_gc; bool do_a_notify; while (1) { do_a_gc = false; do_a_notify = false; old_state = lock_state(); new_state = decrement_lock_count(old_state); if ( needs_gc(new_state) && !is_jni_active(new_state) ) { do_a_notify = true; // GC will also check is_active, so this check is not // strictly needed. It's added here to make it clear that // the GC will NOT be performed if any other caller // of GC_locker::lock() still needs GC locked. if ( (!doing_gc(new_state)) && (!is_active()) ) { do_a_gc = true; new_state = set_doing_gc(new_state); } else { new_state = clear_needs_gc(new_state); } } if ((old_state = Atomic::cmpxchg(new_state, state_addr(), old_state))) { // unlocked successful break; } // unlock failed, loop around and try again. } if ( do_a_gc ) { { // Must give up the lock while at a safepoint MutexUnlocker munlock(JNICritical_lock); Universe::heap()->collect(GCCause::_gc_locker); } // Now that the lock is reaquired, unset _doing_gc and _needs_gc: while (1) { old_state = lock_state(); new_state = clear_needs_gc(clear_doing_gc(old_state)); if ((old_state = Atomic::cmpxchg(new_state, state_addr(), old_state))) { // clear successful break; } // clear failed, loop around and try again. } } if ( do_a_notify ) { JNICritical_lock.notify_all(); } }