1 /* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef COMMON_INTERFACES_THREAD_MUTATOR_BASE_H 17 #define COMMON_INTERFACES_THREAD_MUTATOR_BASE_H 18 19 #include <atomic> 20 #include <mutex> 21 #include <pthread.h> 22 #include "base/common.h" 23 24 namespace common { 25 class Mutator; 26 class ThreadHolder; 27 28 // GCPhase describes phases for stw/concurrent gc. 29 enum GCPhase : uint8_t { 30 GC_PHASE_UNDEF = 0, 31 GC_PHASE_IDLE = 1, 32 GC_PHASE_START = 8, 33 34 // only gc phase after GC_PHASE_START ( enum value > GC_PHASE_START) needs barrier. 35 GC_PHASE_ENUM = 9, 36 GC_PHASE_MARK = 10, 37 GC_PHASE_REMARK_SATB = 11, 38 GC_PHASE_FINAL_MARK = 12, 39 GC_PHASE_POST_MARK = 13, 40 GC_PHASE_PRECOPY = 14, 41 GC_PHASE_COPY = 15, 42 GC_PHASE_FIX = 16, 43 }; 44 45 class PUBLIC_API MutatorBase { 46 public: 47 // flag which indicates the reason why mutator should suspend. flag is set by some external thread. 48 enum SuspensionType : uint32_t { 49 SUSPENSION_FOR_GC_PHASE = 1 << 0, 50 SUSPENSION_FOR_STW = 1 << 1, 51 SUSPENSION_FOR_EXIT = 1 << 2, 52 SUSPENSION_FOR_CPU_PROFILE = 1 << 3, 53 SUSPENSION_FOR_PENDING_CALLBACK = 1 << 4, 54 SUSPENSION_FOR_RUNNING_CALLBACK = 1 << 5, 55 /** 56 * The below ones are not actually suspension request, it's just some callbacks need to process 57 * at the beginning of transfering to RUNNING 58 * So This is equivalent to: 59 * ```` __attribute__((always_inline)) inline void DoLeaveSaferegion() 60 * ```` { 61 * ```` SetInSaferegion(SAFE_REGION_FALSE); 62 * ```` if (UNLIKELY_CC(HasAnySuspensionRequest())) { 63 * ```` HandleSuspensionRequest(); 64 * ```` } 65 * ------> if (UNLIKELY_CC(HasOtherCallback())) { 66 * ------> ProcessCallback(); 67 * ------> } 68 * ```` } 69 * But this will make `DoLeaveSaferegion` cost more, so we just merge it into suspension request, 70 * and do some extra process at the end of `HandleSuspensionRequest` 71 */ 72 SUSPENSION_FOR_FINALIZE = 1 << 31, 73 CALLBACKS_TO_PROCESS = SUSPENSION_FOR_FINALIZE, 74 }; 75 76 enum GCPhaseTransitionState : uint32_t { 77 NO_TRANSITION, 78 NEED_TRANSITION, 79 IN_TRANSITION, 80 FINISH_TRANSITION, 81 }; 82 83 enum CpuProfileState : uint32_t { 84 NO_CPUPROFILE, 85 NEED_CPUPROFILE, 86 IN_CPUPROFILING, 87 FINISH_CPUPROFILE, 88 }; 89 90 // Indicate whether mutator is in saferegion 91 enum SaferegionState : uint32_t { 92 SAFE_REGION_TRUE = 0x17161514, 93 SAFE_REGION_FALSE = 0x03020100, 94 }; 95 96 // // Indicate whether mutator need SafepointPolling 97 // enum class SafepointPollingState : uint64_t { 98 // SAFEPOINT_POLLING_FALSE = 0, 99 // SAFEPOINT_POLLING_TRUE = 1, 100 // }; 101 102 // Called when a mutator starts and finishes, respectively. Init()103 void Init() 104 { 105 observerCnt_ = 0; 106 mutatorPhase_.store(GCPhase::GC_PHASE_IDLE); 107 } 108 109 // Sets saferegion state of this mutator. SetInSaferegion(SaferegionState state)110 __attribute__((always_inline)) inline void SetInSaferegion(SaferegionState state) 111 { 112 // assure sequential execution of setting insaferegion state and checking suspended state. 113 inSaferegion_.store(state, std::memory_order_seq_cst); 114 } 115 116 // Returns true if this mutator is in saferegion, otherwise false. InSaferegion()117 __attribute__((always_inline)) inline bool InSaferegion() const 118 { 119 return inSaferegion_.load(std::memory_order_seq_cst) != SAFE_REGION_FALSE; 120 } 121 IncObserver()122 inline void IncObserver() { observerCnt_.fetch_add(1); } 123 DecObserver()124 inline void DecObserver() { observerCnt_.fetch_sub(1); } 125 126 // Return true indicate there are some observer is visitting this mutator HasObserver()127 inline bool HasObserver() { return observerCnt_.load() != 0; } 128 GetObserverCount()129 inline size_t GetObserverCount() const { return observerCnt_.load(); } 130 131 // Force current mutator enter saferegion, internal use only. 132 __attribute__((always_inline)) inline void DoEnterSaferegion(); 133 // Force current mutator leave saferegion, internal use only. DoLeaveSaferegion()134 __attribute__((always_inline)) inline void DoLeaveSaferegion() 135 { 136 SetInSaferegion(SAFE_REGION_FALSE); 137 // go slow path if the mutator should suspend 138 if (UNLIKELY_CC(HasAnySuspensionRequest())) { 139 HandleSuspensionRequest(); 140 } 141 } 142 143 // If current mutator is not in saferegion, enter and return true 144 // If current mutator has been in saferegion, return false 145 __attribute__((always_inline)) inline bool EnterSaferegion(bool updateUnwindContext) noexcept; 146 // If current mutator is in saferegion, leave and return true 147 // If current mutator has left saferegion, return false 148 __attribute__((always_inline)) inline bool LeaveSaferegion() noexcept; 149 150 // Called if current mutator should do corresponding task by suspensionFlag value 151 void HandleSuspensionRequest(); 152 // Called if current mutator should handle stw request 153 void SuspendForStw(); 154 155 // temporary impl to clean GC callback, and need to refact to flip function 156 void HandleJSGCCallback(); 157 ConstructSuspensionFlag(uint32_t flag,uint32_t clearFlag,uint32_t setFlag)158 static uint32_t ConstructSuspensionFlag(uint32_t flag, uint32_t clearFlag, uint32_t setFlag) 159 { 160 return (flag & ~clearFlag) | setFlag; 161 } 162 FinishedTransition()163 __attribute__((always_inline)) inline bool FinishedTransition() const 164 { 165 return transitionState_ == FINISH_TRANSITION; 166 } 167 FinishedCpuProfile()168 __attribute__((always_inline)) inline bool FinishedCpuProfile() const 169 { 170 return cpuProfileState_.load(std::memory_order_acquire) == FINISH_CPUPROFILE; 171 } 172 SetCpuProfileState(CpuProfileState state)173 __attribute__((always_inline)) inline void SetCpuProfileState(CpuProfileState state) 174 { 175 cpuProfileState_.store(state, std::memory_order_relaxed); 176 } 177 SetSuspensionFlag(SuspensionType flag)178 __attribute__((always_inline)) inline void SetSuspensionFlag(SuspensionType flag) 179 { 180 if (flag == SUSPENSION_FOR_GC_PHASE) { 181 transitionState_.store(NEED_TRANSITION, std::memory_order_relaxed); 182 } else if (flag == SUSPENSION_FOR_CPU_PROFILE) { 183 cpuProfileState_.store(NEED_CPUPROFILE, std::memory_order_relaxed); 184 } 185 suspensionFlag_.fetch_or(flag, std::memory_order_seq_cst); 186 } 187 ClearSuspensionFlag(SuspensionType flag)188 __attribute__((always_inline)) inline void ClearSuspensionFlag(SuspensionType flag) 189 { 190 suspensionFlag_.fetch_and(~flag, std::memory_order_seq_cst); 191 } 192 GetSuspensionFlag()193 __attribute__((always_inline)) inline uint32_t GetSuspensionFlag() const 194 { 195 return suspensionFlag_.load(std::memory_order_acquire); 196 } 197 HasSuspensionRequest(SuspensionType flag)198 __attribute__((always_inline)) inline bool HasSuspensionRequest(SuspensionType flag) const 199 { 200 return (suspensionFlag_.load(std::memory_order_acquire) & flag) != 0; 201 } 202 203 // Check whether current mutator needs to be suspended for GC or other request HasAnySuspensionRequest()204 __attribute__((always_inline)) inline bool HasAnySuspensionRequest() const 205 { 206 return (suspensionFlag_.load(std::memory_order_acquire) != 0); 207 } 208 209 // Check whether current mutator needs to be suspended for GC or other request, see comments in `SuspensionType` HasAnySuspensionRequestExceptCallbacks()210 __attribute__((always_inline)) inline bool HasAnySuspensionRequestExceptCallbacks() const 211 { 212 uint32_t flag = suspensionFlag_.load(std::memory_order_acquire); 213 return (flag & ~CALLBACKS_TO_PROCESS) != 0; 214 } 215 CASSetSuspensionFlag(uint32_t oldFlag,uint32_t newFlag)216 __attribute__((always_inline)) inline bool CASSetSuspensionFlag(uint32_t oldFlag, uint32_t newFlag) 217 { 218 return suspensionFlag_.compare_exchange_strong(oldFlag, newFlag); 219 } 220 SetFinalizeRequest()221 __attribute__((always_inline)) inline void SetFinalizeRequest() 222 { 223 SetSuspensionFlag(SUSPENSION_FOR_FINALIZE); 224 } 225 ClearFinalizeRequest()226 __attribute__((always_inline)) inline void ClearFinalizeRequest() 227 { 228 ClearSuspensionFlag(SUSPENSION_FOR_FINALIZE); 229 } 230 SetSafepointActive(bool value)231 void SetSafepointActive(bool value) 232 { 233 safepointActive_ = static_cast<uint32_t>(value); 234 } 235 236 // Spin wait phase transition finished when GC is tranverting this mutator's phase WaitForPhaseTransition()237 __attribute__((always_inline)) inline void WaitForPhaseTransition() const 238 { 239 GCPhaseTransitionState state = transitionState_.load(std::memory_order_acquire); 240 while (state != FINISH_TRANSITION) { 241 if (state != IN_TRANSITION) { 242 return; 243 } 244 // Give up CPU to avoid overloading 245 (void)sched_yield(); 246 state = transitionState_.load(std::memory_order_acquire); 247 } 248 } 249 WaitForCpuProfiling()250 __attribute__((always_inline)) inline void WaitForCpuProfiling() const 251 { 252 while (cpuProfileState_.load(std::memory_order_acquire) != FINISH_CPUPROFILE) { 253 // Give up CPU to avoid overloading 254 (void)sched_yield(); 255 } 256 } 257 258 inline void GcPhaseEnum(GCPhase newPhase); 259 inline void GCPhasePreForward(GCPhase newPhase); 260 inline void HandleGCPhase(GCPhase newPhase); 261 262 inline void HandleCpuProfile(); 263 264 void TransitionToGCPhaseExclusive(GCPhase newPhase); 265 266 void TransitionToCpuProfileExclusive(); 267 268 // Ensure that mutator phase is changed only once by mutator itself or GC 269 bool TransitionGCPhase(bool bySelf); 270 271 __attribute__((always_inline)) inline bool TransitionToCpuProfile(bool bySelf); 272 SetMutatorPhase(const GCPhase newPhase)273 __attribute__((always_inline)) inline void SetMutatorPhase(const GCPhase newPhase) 274 { 275 mutatorPhase_.store(newPhase, std::memory_order_release); 276 } 277 GetMutatorPhase()278 __attribute__((always_inline)) inline GCPhase GetMutatorPhase() const 279 { 280 return mutatorPhase_.load(std::memory_order_acquire); 281 } 282 GetSafepointActiveState()283 bool GetSafepointActiveState() const 284 { 285 return safepointActive_; 286 } 287 MutatorBaseLock()288 void MutatorBaseLock() { mutatorBaseLock_.lock(); } 289 MutatorBaseUnlock()290 void MutatorBaseUnlock() { mutatorBaseLock_.unlock(); } 291 RegisterJSThread(void * jsThread)292 void RegisterJSThread(void *jsThread) 293 { 294 CHECK_CC(jsThread_ == nullptr); 295 jsThread_ = jsThread; 296 } 297 UnregisterJSThread()298 void UnregisterJSThread() 299 { 300 jsThread_ = nullptr; 301 } 302 GetSafepointActiveOffset()303 static constexpr size_t GetSafepointActiveOffset() 304 { 305 return offsetof(MutatorBase, safepointActive_); 306 } 307 308 private: 309 // Indicate whether execution thread should check safepoint suspension request 310 uint32_t safepointActive_ = 0; 311 // Indicate the current mutator phase and use which barrier in concurrent gc 312 std::atomic<GCPhase> mutatorPhase_ = { GCPhase::GC_PHASE_UNDEF }; 313 // in saferegion, it will not access any managed objects and can be visitted by observer 314 std::atomic<uint32_t> inSaferegion_ = { SAFE_REGION_TRUE }; 315 // Protect observerCnt 316 std::mutex observeCntMutex_; 317 // Increase when this mutator is observed by some observer 318 std::atomic<size_t> observerCnt_ = { 0 }; 319 320 // If set implies this mutator should process suspension requests 321 std::atomic<uint32_t> suspensionFlag_ = { 0 }; 322 // Indicate the state of mutator's phase transition 323 std::atomic<GCPhaseTransitionState> transitionState_ = { NO_TRANSITION }; 324 325 std::mutex mutatorBaseLock_; 326 327 std::atomic<CpuProfileState> cpuProfileState_ = { NO_CPUPROFILE }; 328 329 // This is stored for process `satbNode`, merge Mutator & MutatorBase & SatbNode 330 void *mutator_ {nullptr}; 331 332 // used to synchronize cmc-gc phase to JSThread 333 void *jsThread_ {nullptr}; 334 335 friend Mutator; 336 friend ThreadHolder; 337 }; 338 } // namespace common 339 #endif // COMMON_INTERFACES_THREAD_MUTATOR_BASE_H 340