• 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_THREAD_HOLDER_H
17 #define COMMON_INTERFACES_THREAD_THREAD_HOLDER_H
18 
19 #include <condition_variable>
20 #include <mutex>
21 #include <unordered_set>
22 
23 #include "base/common.h"
24 #include "heap/heap_visitor.h"
25 #include "thread/mutator_base.h"
26 #include "thread/thread_state.h"
27 
28 namespace panda::ecmascript {
29 class JSThread;
30 }
31 
32 namespace ark {
33 class Coroutine;
34 }
35 
36 namespace common {
37 class BaseThread;
38 class ThreadHolderManager;
39 
40 /**
41  * ThreadHolder does two things:
42  * 1. Represent the current ThreadState(RUNNING for VM, or NATIVE for NativeCode) for all the execution BaseThread
43  *    registered to this ThreadHolder, they will share the same ThreadState. And be responsible for transfer
44  *    ThreadState, and is the control unit for ThreadHolderManager::SuspendAll()/ResumeAll().
45  * 2. Maintain all the execution BaseThread registered to the current ThreadHolder.
46  *
47  * ThreadHolder is a package of execution BaseThreads which must run in the same OS Thread and so could
48  * share ThreadState.
49  */
50 class ThreadHolder {
51 public:
52     using JSThread = panda::ecmascript::JSThread;
53     using Coroutine = ark::Coroutine;
54     using MutatorBase = common::MutatorBase;
55 
ThreadHolder(MutatorBase * mutatorBase)56     ThreadHolder(MutatorBase *mutatorBase) : mutatorBase_(mutatorBase)
57     {
58         SetCurrent(this);
59     }
60 
~ThreadHolder()61     ~ThreadHolder()
62     {
63         SetCurrent(nullptr);
64     }
65 
66     static ThreadHolder *GetCurrent();
67     static void SetCurrent(ThreadHolder *holder);
68 
69     // This is a temporary impl so we need pass vm from JSThread, or nullptr otherwise
70     static ThreadHolder *CreateAndRegisterNewThreadHolder(void *vm);
71     static void DestroyThreadHolder(ThreadHolder *holder);
72 
73     // Transfer to Running no matter in Running or Native.
74     inline void TransferToRunning();
75 
76     // Transfer to Native no matter in Running or Native.
77     inline void TransferToNative();
78 
79     // If current in Native, transfer to Running and return true;
80     // If current in Running, do nothing and return false.
81     inline bool TransferToRunningIfInNative();
82 
83     // If current in Running, transfer to Native and return true;
84     // If current in Native, do nothing and return false.
85     inline bool TransferToNativeIfInRunning();
86 
CheckSafepointIfSuspended()87     bool CheckSafepointIfSuspended()
88     {
89         if (UNLIKELY_CC(HasSuspendRequest())) {
90             WaitSuspension();
91             return true;
92         }
93         return false;
94     }
95 
96     void WaitSuspension();
97 
HasSuspendRequest()98     bool HasSuspendRequest() const
99     {
100         return mutatorBase_->HasAnySuspensionRequest();
101     }
102 
IsInRunningState()103     bool IsInRunningState() const
104     {
105         return !mutatorBase_->InSaferegion();
106     }
107 
108     // Thread must be binded mutator before to allocate. Otherwise it cannot allocate heap object in this thread.
109     // One thread only allow to bind one muatator. If try bind sencond mutator, will be fatal.
110     void BindMutator();
111     // One thread only allow to bind one muatator. So it must be unbinded mutator before bind another one.
112     void UnbindMutator();
113     // unify JSThread* and Coroutine*
114     // When register a thread, it must be initialized, i.e. it's safe to visit GC-Root.
115     void RegisterJSThread(JSThread *jsThread);
116     void UnregisterJSThread(JSThread *jsThread);
117     void RegisterCoroutine(Coroutine *coroutine);
118     void UnregisterCoroutine(Coroutine *coroutine);
119     void VisitAllThreads(CommonRootVisitor visitor);
120 
121     // Get the thread-local alloction buffer, which is used for fast path of allocating heap objects.
122     // It should be used after binding mutator, and will be invalid after unbinding.
GetAllocBuffer()123     void* GetAllocBuffer() const
124     {
125         DCHECK_CC(allocBuffer_ != nullptr);
126         return allocBuffer_;
127     }
128 
129     void ReleaseAllocBuffer();
130 
GetJSThread()131     JSThread* GetJSThread() const
132     {
133         return jsThread_;
134     }
135 
GetMutator()136     void *GetMutator() const
137     {
138         return mutatorBase_->mutator_;
139     }
140 
GetMutatorPhase()141     GCPhase GetMutatorPhase() const
142     {
143         return mutatorBase_->GetMutatorPhase();
144     }
145 
146     // Return if thread has already binded mutator.
147     class TryBindMutatorScope {
148     public:
149         TryBindMutatorScope(ThreadHolder *holder);
150         ~TryBindMutatorScope();
151 
152     private:
153         ThreadHolder *holder_ {nullptr};
154     };
155 
GetMutatorBaseOffset()156     static constexpr size_t GetMutatorBaseOffset()
157     {
158         return offsetof(ThreadHolder, mutatorBase_);
159     }
160 
161 private:
162     // Return false if thread has already binded mutator. Otherwise bind a mutator.
163     bool TryBindMutator();
164 
165     MutatorBase *mutatorBase_ {nullptr};
166 
167     // Used for allocation fastpath, it is binded to thread local panda::AllocationBuffer.
168     void* allocBuffer_ {nullptr};
169 
170     // Access jsThreads/coroutines(iterate/insert/remove) must happen in RunningState from the currentThreadHolder, or
171     // in SuspendAll from others, because daemon thread may iterate if in NativeState.
172     // And if we use locks to make that thread safe, it would cause a AB-BA dead lock.
173     JSThread *jsThread_ {nullptr};
174     std::unordered_set<Coroutine *> coroutines_ {};
175 
176     NO_COPY_SEMANTIC_CC(ThreadHolder);
177     NO_MOVE_SEMANTIC_CC(ThreadHolder);
178 
179     friend JSThread;
180     friend ThreadHolderManager;
181 };
182 }  // namespace common
183 #endif  // COMMON_INTERFACES_THREAD_THREAD_HOLDER_H
184