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_SHENANDOAHCONTROLTHREAD_HPP 27 #define SHARE_GC_SHENANDOAH_SHENANDOAHCONTROLTHREAD_HPP 28 29 #include "gc/shared/gcCause.hpp" 30 #include "gc/shared/concurrentGCThread.hpp" 31 #include "gc/shenandoah/shenandoahGC.hpp" 32 #include "gc/shenandoah/shenandoahHeap.hpp" 33 #include "gc/shenandoah/shenandoahPadding.hpp" 34 #include "gc/shenandoah/shenandoahSharedVariables.hpp" 35 #include "runtime/task.hpp" 36 #include "utilities/ostream.hpp" 37 38 // Periodic task is useful for doing asynchronous things that do not require (heap) locks, 39 // or synchronization with other parts of collector. These could run even when ShenandoahConcurrentThread 40 // is busy driving the GC cycle. 41 class ShenandoahPeriodicTask : public PeriodicTask { 42 private: 43 ShenandoahControlThread* _thread; 44 public: 45 ShenandoahPeriodicTask(ShenandoahControlThread* thread) : 46 PeriodicTask(100), _thread(thread) {} 47 virtual void task(); 48 }; 49 50 // Periodic task to notify blocked paced waiters. 51 class ShenandoahPeriodicPacerNotify : public PeriodicTask { 52 public: 53 ShenandoahPeriodicPacerNotify() : PeriodicTask(PeriodicTask::min_interval) {} 54 virtual void task(); 55 }; 56 57 class ShenandoahControlThread: public ConcurrentGCThread { 58 friend class VMStructs; 59 60 private: 61 // While we could have a single lock for these, it may risk unblocking 62 // GC waiters when alloc failure GC cycle finishes. We want instead 63 // to make complete explicit cycle for demanding customers. 64 Monitor _alloc_failure_waiters_lock; 65 Monitor _gc_waiters_lock; 66 Monitor _control_lock; 67 Monitor _regulator_lock; 68 ShenandoahPeriodicTask _periodic_task; 69 ShenandoahPeriodicPacerNotify _periodic_pacer_notify_task; 70 71 public: 72 typedef enum { 73 none, 74 concurrent_normal, 75 stw_degenerated, 76 stw_full, 77 bootstrapping_old, 78 servicing_old 79 } GCMode; 80 81 void run_service(); 82 void stop_service(); 83 84 size_t get_gc_id(); 85 86 private: 87 ShenandoahSharedFlag _allow_old_preemption; 88 ShenandoahSharedFlag _preemption_requested; 89 ShenandoahSharedFlag _gc_requested; 90 ShenandoahSharedFlag _alloc_failure_gc; 91 ShenandoahSharedFlag _humongous_alloc_failure_gc; 92 ShenandoahSharedFlag _graceful_shutdown; 93 ShenandoahSharedFlag _do_counters_update; 94 ShenandoahSharedFlag _force_counters_update; 95 GCCause::Cause _requested_gc_cause; 96 ShenandoahGenerationType _requested_generation; 97 ShenandoahGC::ShenandoahDegenPoint _degen_point; 98 ShenandoahGeneration* _degen_generation; 99 100 shenandoah_padding(0); 101 volatile size_t _allocs_seen; 102 shenandoah_padding(1); 103 volatile size_t _gc_id; 104 shenandoah_padding(2); 105 volatile GCMode _mode; 106 shenandoah_padding(3); 107 108 // Returns true if the cycle has been cancelled or degenerated. 109 bool check_cancellation_or_degen(ShenandoahGC::ShenandoahDegenPoint point); 110 111 // Returns true if the old generation marking completed (i.e., final mark executed for old generation). 112 bool resume_concurrent_old_cycle(ShenandoahGeneration* generation, GCCause::Cause cause); 113 void service_concurrent_cycle(ShenandoahGeneration* generation, GCCause::Cause cause, bool reset_old_bitmap_specially); 114 void service_stw_full_cycle(GCCause::Cause cause); 115 116 // Return true if degenerated cycle finishes normally. Return false if the degenerated cycle transformed itself 117 // into a full GC. 118 bool service_stw_degenerated_cycle(GCCause::Cause cause, ShenandoahGC::ShenandoahDegenPoint point); 119 void service_uncommit(double shrink_before, size_t shrink_until); 120 121 // Return true if setting the flag which indicates allocation failure succeeds. 122 bool try_set_alloc_failure_gc(); 123 // Notify threads waiting for GC to complete. 124 void notify_alloc_failure_waiters(); 125 // True if allocation failure flag has been set. 126 bool is_alloc_failure_gc(); 127 128 void reset_gc_id(); 129 void update_gc_id(); 130 131 void notify_gc_waiters(); 132 133 // Handle GC request. 134 // Blocks until GC is over. 135 void handle_requested_gc(GCCause::Cause cause); 136 137 bool is_explicit_gc(GCCause::Cause cause) const; 138 bool is_implicit_gc(GCCause::Cause cause) const; 139 140 // Returns true if the old generation marking was interrupted to allow a young cycle. 141 bool preempt_old_marking(ShenandoahGenerationType generation); 142 143 // Returns true if the soft maximum heap has been changed using management APIs. 144 bool check_soft_max_changed() const; 145 146 void process_phase_timings(const ShenandoahHeap* heap); 147 148 public: 149 // Constructor 150 ShenandoahControlThread(); 151 ~ShenandoahControlThread(); 152 153 // Handle allocation failure from normal allocation. 154 // Blocks until memory is available. 155 void handle_alloc_failure(ShenandoahAllocRequest& req); 156 157 // Handle allocation failure from evacuation path. 158 // Optionally blocks while collector is handling the failure. 159 void handle_alloc_failure_evac(size_t words); 160 161 void request_gc(GCCause::Cause cause); 162 // Return true if the request to start a concurrent GC for the given generation succeeded. 163 bool request_concurrent_gc(ShenandoahGenerationType generation); 164 165 void handle_counters_update(); 166 void handle_force_counters_update(); 167 void set_forced_counters_update(bool value); 168 169 void notify_heap_changed(); 170 171 void pacing_notify_alloc(size_t words); 172 173 void start(); 174 void prepare_for_graceful_shutdown(); 175 bool in_graceful_shutdown(); 176 177 void service_concurrent_normal_cycle(ShenandoahHeap* heap, 178 const ShenandoahGenerationType generation, 179 GCCause::Cause cause); 180 181 void service_concurrent_old_cycle(ShenandoahHeap* heap, 182 GCCause::Cause &cause); 183 184 void set_gc_mode(GCMode new_mode); 185 GCMode gc_mode() { 186 return _mode; 187 } 188 189 static ShenandoahGenerationType select_global_generation(); 190 191 private: 192 static const char* gc_mode_name(GCMode mode); 193 void notify_control_thread(); 194 195 void service_concurrent_cycle(ShenandoahHeap* heap, 196 ShenandoahGeneration* generation, 197 GCCause::Cause &cause, 198 bool do_old_gc_bootstrap); 199 200 }; 201 202 #endif // SHARE_GC_SHENANDOAH_SHENANDOAHCONTROLTHREAD_HPP