| /* | |
| * 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 |