1 /*
2 * Copyright (c) 2013, 2021, Red Hat, Inc. All rights reserved.
3 * Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 *
6 * This code is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License version 2 only, as
8 * published by the Free Software Foundation.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * questions.
23 *
24 */
25
26 #ifndef SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALCONTROLTHREAD_HPP
27 #define SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALCONTROLTHREAD_HPP
28
29 #include "gc/shared/gcCause.hpp"
30 #include "gc/shenandoah/shenandoahController.hpp"
31 #include "gc/shenandoah/shenandoahGC.hpp"
32 #include "gc/shenandoah/shenandoahSharedVariables.hpp"
33 #include "runtime/mutexLocker.hpp"
34
35 class ShenandoahOldGeneration;
36 class ShenandoahGeneration;
37 class ShenandoahGenerationalHeap;
38 class ShenandoahHeap;
39
40 class ShenandoahGenerationalControlThread: public ShenandoahController {
41 friend class VMStructs;
42
43 public:
44 typedef enum {
45 none,
46 concurrent_normal,
47 stw_degenerated,
48 stw_full,
49 bootstrapping_old,
50 servicing_old,
51 stopped
52 } GCMode;
53
54 class ShenandoahGCRequest {
55 public:
56 ShenandoahGCRequest() : generation(nullptr), cause(GCCause::_no_gc) {}
57 ShenandoahGeneration* generation;
58 GCCause::Cause cause;
59 };
60
61 private:
62 // This lock is used to coordinate setting the _requested_gc_cause, _requested generation
63 // and _gc_mode. It is important that these be changed together and have a consistent view.
64 Monitor _control_lock;
65
66 // Represents a normal (non cancellation) gc request. This can be set by mutators (System.gc,
67 // whitebox gc, etc.) or by the regulator thread when the heuristics want to start a cycle.
68 GCCause::Cause _requested_gc_cause;
69
70 // This is the generation the request should operate on.
71 ShenandoahGeneration* _requested_generation;
72
73 // The mode is read frequently by requesting threads and only ever written by the control thread.
74 // This may be read without taking the _control_lock, but should be read again under the lock
75 // before making any state changes (double-checked locking idiom).
76 volatile GCMode _gc_mode;
77
78 // Only the control thread knows the correct degeneration point. This is used to have the
79 // control thread resume a STW cycle from the point where the concurrent cycle was cancelled.
80 ShenandoahGC::ShenandoahDegenPoint _degen_point;
81
82 // A reference to the heap
83 ShenandoahGenerationalHeap* _heap;
84
85 // This is used to keep track of whether to age objects during the current cycle.
86 uint _age_period;
87
88 // This is true when the old generation cycle is in an interruptible phase (i.e., marking or
89 // preparing for mark).
90 ShenandoahSharedFlag _allow_old_preemption;
91
92 public:
93 ShenandoahGenerationalControlThread();
94
95 void run_service() override;
96 void stop_service() override;
97
98 void request_gc(GCCause::Cause cause) override;
99
100 // Return true if the request to start a concurrent GC for the given generation succeeded.
101 bool request_concurrent_gc(ShenandoahGeneration* generation);
102
103 // Returns the current state of the control thread
104 GCMode gc_mode() const {
105 return _gc_mode;
106 }
107 private:
108 // Returns true if the cycle has been cancelled or degenerated.
109 bool check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point);
110
111 // Executes one GC cycle
112 void run_gc_cycle(const ShenandoahGCRequest& request);
113
114 // Returns true if the old generation marking completed (i.e., final mark executed for old generation).
115 bool resume_concurrent_old_cycle(ShenandoahOldGeneration* generation, GCCause::Cause cause);
116
117 // Various service methods handle different gc cycle types
118 void service_concurrent_cycle(ShenandoahGeneration* generation, GCCause::Cause cause, bool reset_old_bitmap_specially);
119 void service_stw_full_cycle(GCCause::Cause cause);
120 void service_stw_degenerated_cycle(const ShenandoahGCRequest& request);
121 void service_concurrent_normal_cycle(const ShenandoahGCRequest& request);
122 void service_concurrent_old_cycle(const ShenandoahGCRequest& request);
123
124 void notify_gc_waiters();
125
126 // Blocks until at least one global GC cycle is complete.
127 void handle_requested_gc(GCCause::Cause cause);
128
129 // Returns true if the old generation marking was interrupted to allow a young cycle.
130 bool preempt_old_marking(ShenandoahGeneration* generation);
131
132 // Flushes cycle timings to global timings and prints the phase timings for the last completed cycle.
133 void process_phase_timings() const;
134
135 // Set the gc mode and post a notification if it has changed. The overloaded variant should be used
136 // when the _control_lock is already held.
137 void set_gc_mode(GCMode new_mode);
138 void set_gc_mode(MonitorLocker& ml, GCMode new_mode);
139
140 // Return printable name for the given gc mode.
141 static const char* gc_mode_name(GCMode mode);
142
143 // Takes the request lock and updates the requested cause and generation, then notifies the control thread.
144 // The overloaded variant should be used when the _control_lock is already held.
145 void notify_control_thread(GCCause::Cause cause, ShenandoahGeneration* generation);
146 void notify_control_thread(MonitorLocker& ml, GCCause::Cause cause, ShenandoahGeneration* generation);
147
148 // Notifies the control thread, but does not update the requested cause or generation.
149 // The overloaded variant should be used when the _control_lock is already held.
150 void notify_cancellation(GCCause::Cause cause);
151 void notify_cancellation(MonitorLocker& ml, GCCause::Cause cause);
152
153 // Configure the heap to age objects and regions if the aging period has elapsed.
154 void maybe_set_aging_cycle();
155
156 // Take the _control_lock and check for a request to run a gc cycle. If a request is found,
157 // the `prepare` methods are used to configure the heap and update heuristics accordingly.
158 void check_for_request(ShenandoahGCRequest& request);
159
160 GCMode prepare_for_allocation_failure_gc(ShenandoahGCRequest &request);
161 GCMode prepare_for_explicit_gc(ShenandoahGCRequest &request) const;
162 GCMode prepare_for_concurrent_gc(const ShenandoahGCRequest &request) const;
163 };
164
165 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHGENERATIONALCONTROLTHREAD_HPP