Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/gc_implementation/shenandoah/shenandoahEvacOOMHandler.cpp
38920 views
/*1* Copyright (c) 2018, Red Hat, Inc. All rights reserved.2*3* This code is free software; you can redistribute it and/or modify it4* under the terms of the GNU General Public License version 2 only, as5* published by the Free Software Foundation.6*7* This code is distributed in the hope that it will be useful, but WITHOUT8* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or9* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License10* version 2 for more details (a copy is included in the LICENSE file that11* accompanied this code).12*13* You should have received a copy of the GNU General Public License version14* 2 along with this work; if not, write to the Free Software Foundation,15* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.16*17* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA18* or visit www.oracle.com if you need additional information or have any19* questions.20*21*/2223#include "precompiled.hpp"2425#include "gc_implementation/shenandoah/shenandoahHeap.inline.hpp"26#include "gc_implementation/shenandoah/shenandoahUtils.hpp"27#include "gc_implementation/shenandoah/shenandoahEvacOOMHandler.hpp"2829const jint ShenandoahEvacOOMHandler::OOM_MARKER_MASK = 0x80000000;3031ShenandoahEvacOOMHandler::ShenandoahEvacOOMHandler() :32_threads_in_evac(0) {33}3435void ShenandoahEvacOOMHandler::wait_for_no_evac_threads() {36while ((OrderAccess::load_acquire(&_threads_in_evac) & ~OOM_MARKER_MASK) != 0) {37os::naked_short_sleep(1);38}39// At this point we are sure that no threads can evacuate anything. Raise40// the thread-local oom_during_evac flag to indicate that any attempt41// to evacuate should simply return the forwarding pointer instead (which is safe now).42Thread::current()->set_oom_during_evac(true);43}4445void ShenandoahEvacOOMHandler::enter_evacuation() {46jint threads_in_evac = OrderAccess::load_acquire(&_threads_in_evac);4748assert(!Thread::current()->is_evac_allowed(), "sanity");49assert(!Thread::current()->is_oom_during_evac(), "TL oom-during-evac must not be set");5051if ((threads_in_evac & OOM_MARKER_MASK) != 0) {52wait_for_no_evac_threads();53return;54}5556while (true) {57jint other = Atomic::cmpxchg(threads_in_evac + 1, &_threads_in_evac, threads_in_evac);58if (other == threads_in_evac) {59// Success: caller may safely enter evacuation60DEBUG_ONLY(Thread::current()->set_evac_allowed(true));61return;62} else {63// Failure:64// - if offender has OOM_MARKER_MASK, then loop until no more threads in evac65// - otherwise re-try CAS66if ((other & OOM_MARKER_MASK) != 0) {67wait_for_no_evac_threads();68return;69}70threads_in_evac = other;71}72}73}7475void ShenandoahEvacOOMHandler::leave_evacuation() {76if (!Thread::current()->is_oom_during_evac()) {77assert((OrderAccess::load_acquire(&_threads_in_evac) & ~OOM_MARKER_MASK) > 0, "sanity");78// NOTE: It's ok to simply decrement, even with mask set, because unmasked value is positive.79Atomic::dec(&_threads_in_evac);80} else {81// If we get here, the current thread has already gone through the82// OOM-during-evac protocol and has thus either never entered or successfully left83// the evacuation region. Simply flip its TL oom-during-evac flag back off.84Thread::current()->set_oom_during_evac(false);85}86DEBUG_ONLY(Thread::current()->set_evac_allowed(false));87assert(!Thread::current()->is_oom_during_evac(), "TL oom-during-evac must be turned off");88}8990void ShenandoahEvacOOMHandler::handle_out_of_memory_during_evacuation() {91assert(Thread::current()->is_evac_allowed(), "sanity");92assert(!Thread::current()->is_oom_during_evac(), "TL oom-during-evac must not be set");9394jint threads_in_evac = OrderAccess::load_acquire(&_threads_in_evac);95while (true) {96jint other = Atomic::cmpxchg((threads_in_evac - 1) | OOM_MARKER_MASK,97&_threads_in_evac, threads_in_evac);98if (other == threads_in_evac) {99// Success: wait for other threads to get out of the protocol and return.100wait_for_no_evac_threads();101return;102} else {103// Failure: try again with updated new value.104threads_in_evac = other;105}106}107}108109void ShenandoahEvacOOMHandler::clear() {110assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "must be at a safepoint");111assert((OrderAccess::load_acquire(&_threads_in_evac) & ~OOM_MARKER_MASK) == 0, "sanity");112OrderAccess::release_store_fence(&_threads_in_evac, 0);113}114115ShenandoahEvacOOMScope::ShenandoahEvacOOMScope() {116ShenandoahHeap::heap()->enter_evacuation();117}118119ShenandoahEvacOOMScope::~ShenandoahEvacOOMScope() {120ShenandoahHeap::heap()->leave_evacuation();121}122123124