• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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