blob: 1586205742a713a1224f9cdb5913a525fc0b4fa4 [file] [edit]
/*
* Copyright (c) 2013, 2021, Red Hat, Inc. All rights reserved.
* Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALCONTROLTHREAD_HPP
#define SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALCONTROLTHREAD_HPP
#include "gc/shared/gcCause.hpp"
#include "gc/shenandoah/shenandoahController.hpp"
#include "gc/shenandoah/shenandoahGC.hpp"
#include "gc/shenandoah/shenandoahSharedVariables.hpp"
#include "runtime/mutexLocker.hpp"
class ShenandoahOldGeneration;
class ShenandoahGeneration;
class ShenandoahGenerationalHeap;
class ShenandoahHeap;
class ShenandoahGenerationalControlThread: public ShenandoahController {
friend class VMStructs;
public:
typedef enum {
none,
concurrent_normal,
stw_degenerated,
stw_full,
bootstrapping_old,
servicing_old,
stopped
} GCMode;
class ShenandoahGCRequest {
public:
ShenandoahGCRequest() : generation(nullptr), cause(GCCause::_no_gc) {}
ShenandoahGeneration* generation;
GCCause::Cause cause;
};
private:
// This lock is used to coordinate setting the _requested_gc_cause, _requested generation
// and _gc_mode. It is important that these be changed together and have a consistent view.
Monitor _control_lock;
// Represents a normal (non cancellation) gc request. This can be set by mutators (System.gc,
// whitebox gc, etc.) or by the regulator thread when the heuristics want to start a cycle.
GCCause::Cause _requested_gc_cause;
// This is the generation the request should operate on.
ShenandoahGeneration* _requested_generation;
// The mode is read frequently by requesting threads and only ever written by the control thread.
// This may be read without taking the _control_lock, but should be read again under the lock
// before making any state changes (double-checked locking idiom).
volatile GCMode _gc_mode;
// Only the control thread knows the correct degeneration point. This is used to have the
// control thread resume a STW cycle from the point where the concurrent cycle was cancelled.
ShenandoahGC::ShenandoahDegenPoint _degen_point;
// A reference to the heap
ShenandoahGenerationalHeap* _heap;
// This is used to keep track of whether to age objects during the current cycle.
uint _age_period;
// This is true when the old generation cycle is in an interruptible phase (i.e., marking or
// preparing for mark).
ShenandoahSharedFlag _allow_old_preemption;
public:
ShenandoahGenerationalControlThread();
void run_service() override;
void stop_service() override;
void request_gc(GCCause::Cause cause) override;
// Return true if the request to start a concurrent GC for the given generation succeeded.
bool request_concurrent_gc(ShenandoahGeneration* generation);
// Returns the current state of the control thread
GCMode gc_mode() const {
return _gc_mode;
}
private:
// Returns true if the cycle has been cancelled or degenerated.
bool check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point);
// Executes one GC cycle
void run_gc_cycle(const ShenandoahGCRequest& request);
// Returns true if the old generation marking completed (i.e., final mark executed for old generation).
bool resume_concurrent_old_cycle(ShenandoahOldGeneration* generation, GCCause::Cause cause);
// Various service methods handle different gc cycle types
void service_concurrent_cycle(ShenandoahGeneration* generation, GCCause::Cause cause, bool reset_old_bitmap_specially);
void service_stw_full_cycle(GCCause::Cause cause);
void service_stw_degenerated_cycle(const ShenandoahGCRequest& request);
void service_concurrent_normal_cycle(const ShenandoahGCRequest& request);
void service_concurrent_old_cycle(const ShenandoahGCRequest& request);
void notify_gc_waiters();
// Blocks until at least one global GC cycle is complete.
void handle_requested_gc(GCCause::Cause cause);
// Returns true if the old generation marking was interrupted to allow a young cycle.
bool preempt_old_marking(ShenandoahGeneration* generation);
// Flushes cycle timings to global timings and prints the phase timings for the last completed cycle.
void process_phase_timings() const;
// Set the gc mode and post a notification if it has changed. The overloaded variant should be used
// when the _control_lock is already held.
void set_gc_mode(GCMode new_mode);
void set_gc_mode(MonitorLocker& ml, GCMode new_mode);
// Return printable name for the given gc mode.
static const char* gc_mode_name(GCMode mode);
// Takes the request lock and updates the requested cause and generation, then notifies the control thread.
// The overloaded variant should be used when the _control_lock is already held.
void notify_control_thread(GCCause::Cause cause, ShenandoahGeneration* generation);
void notify_control_thread(MonitorLocker& ml, GCCause::Cause cause, ShenandoahGeneration* generation);
// Notifies the control thread, but does not update the requested cause or generation.
// The overloaded variant should be used when the _control_lock is already held.
void notify_cancellation(GCCause::Cause cause);
void notify_cancellation(MonitorLocker& ml, GCCause::Cause cause);
// Configure the heap to age objects and regions if the aging period has elapsed.
void maybe_set_aging_cycle();
// Take the _control_lock and check for a request to run a gc cycle. If a request is found,
// the `prepare` methods are used to configure the heap and update heuristics accordingly.
void check_for_request(ShenandoahGCRequest& request);
GCMode prepare_for_allocation_failure_gc(ShenandoahGCRequest &request);
GCMode prepare_for_explicit_gc(ShenandoahGCRequest &request) const;
GCMode prepare_for_concurrent_gc(const ShenandoahGCRequest &request) const;
};
#endif // SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALCONTROLTHREAD_HPP