Path: blob/master/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.hpp
40961 views
/*1* Copyright (c) 2018, 2020, Red Hat, Inc. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHEVACOOMHANDLER_HPP25#define SHARE_GC_SHENANDOAH_SHENANDOAHEVACOOMHANDLER_HPP2627#include "gc/shenandoah/shenandoahPadding.hpp"28#include "memory/allocation.hpp"29#include "runtime/thread.hpp"30#include "utilities/globalDefinitions.hpp"3132/**33* Provides safe handling of out-of-memory situations during evacuation.34*35* When a Java thread encounters out-of-memory while evacuating an object in a36* load-reference-barrier (i.e. it cannot copy the object to to-space), it does not37* necessarily follow we can return immediately from the LRB (and store to from-space).38*39* In very basic case, on such failure we may wait until the the evacuation is over,40* and then resolve the forwarded copy, and to the store there. This is possible41* because other threads might still have space in their GCLABs, and successfully42* evacuate the object.43*44* But, there is a race due to non-atomic evac_in_progress transition. Consider45* thread A is stuck waiting for the evacuation to be over -- it cannot leave with46* from-space copy yet. Control thread drops evacuation_in_progress preparing for47* next STW phase that has to recover from OOME. Thread B misses that update, and48* successfully evacuates the object, does the write to to-copy. But, before49* Thread B is able to install the fwdptr, thread A discovers evac_in_progress is50* down, exits from here, reads the fwdptr, discovers old from-copy, and stores there.51* Thread B then wakes up and installs to-copy. This breaks to-space invariant, and52* silently corrupts the heap: we accepted two writes to separate copies of the object.53*54* The way it is solved here is to maintain a counter of threads inside the55* 'evacuation path'. The 'evacuation path' is the part of evacuation that does the actual56* allocation, copying and CASing of the copy object, and is protected by this57* OOM-during-evac-handler. The handler allows multiple threads to enter and exit58* evacuation path, but on OOME it requires all threads that experienced OOME to wait59* for current threads to leave, and blocks other threads from entering.60*61* Detailed state change:62*63* Upon entry of the evac-path, entering thread will attempt to increase the counter,64* using a CAS. Depending on the result of the CAS:65* - success: carry on with evac66* - failure:67* - if offending value is a valid counter, then try again68* - if offending value is OOM-during-evac special value: loop until69* counter drops to 0, then exit with resolving the ptr70*71* Upon exit, exiting thread will decrease the counter using atomic dec.72*73* Upon OOM-during-evac, any thread will attempt to CAS OOM-during-evac74* special value into the counter. Depending on result:75* - success: busy-loop until counter drops to zero, then exit with resolve76* - failure:77* - offender is valid counter update: try again78* - offender is OOM-during-evac: busy loop until counter drops to79* zero, then exit with resolve80*/81class ShenandoahEvacOOMHandler {82private:83static const jint OOM_MARKER_MASK;8485shenandoah_padding(0);86volatile jint _threads_in_evac;87shenandoah_padding(1);8889void wait_for_no_evac_threads();9091public:92ShenandoahEvacOOMHandler();9394/**95* Attempt to enter the protected evacuation path.96*97* When this returns true, it is safe to continue with normal evacuation.98* When this method returns false, evacuation must not be entered, and caller99* may safely continue with a simple resolve (if Java thread).100*/101inline void enter_evacuation(Thread* t);102103/**104* Leave evacuation path.105*/106inline void leave_evacuation(Thread* t);107108/**109* Signal out-of-memory during evacuation. It will prevent any other threads110* from entering the evacuation path, then wait until all threads have left the111* evacuation path, and then return. It is then safe to continue with a simple resolve.112*/113void handle_out_of_memory_during_evacuation();114115void clear();116117private:118// Register/Unregister thread to evacuation OOM protocol119void register_thread(Thread* t);120void unregister_thread(Thread* t);121};122123class ShenandoahEvacOOMScope : public StackObj {124private:125Thread* const _thread;126127public:128inline ShenandoahEvacOOMScope();129inline ShenandoahEvacOOMScope(Thread* t);130inline ~ShenandoahEvacOOMScope();131};132133#endif // SHARE_GC_SHENANDOAH_SHENANDOAHEVACOOMHANDLER_HPP134135136