• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 #ifndef PANDA_RUNTIME_THREAD_H_
16 #define PANDA_RUNTIME_THREAD_H_
17 
18 #include <memory>
19 #include <chrono>
20 #include <limits>
21 #include <thread>
22 #include <atomic>
23 
24 #include "libpandabase/mem/gc_barrier.h"
25 #include "libpandabase/mem/ringbuf/lock_free_ring_buffer.h"
26 #include "libpandabase/os/mutex.h"
27 #include "libpandabase/os/thread.h"
28 #include "libpandabase/utils/arch.h"
29 #include "libpandabase/utils/list.h"
30 #include "libpandabase/utils/tsan_interface.h"
31 #include "runtime/include/mem/panda_containers.h"
32 #include "runtime/include/mem/panda_smart_pointers.h"
33 #include "runtime/include/object_header-inl.h"
34 #include "runtime/include/stack_walker.h"
35 #include "runtime/include/language_context.h"
36 #include "runtime/include/locks.h"
37 #include "runtime/include/thread_status.h"
38 #include "runtime/interpreter/cache.h"
39 #include "runtime/mem/frame_allocator-inl.h"
40 #include "runtime/mem/gc/gc.h"
41 #include "runtime/mem/internal_allocator.h"
42 #include "runtime/mem/tlab.h"
43 #include "runtime/mem/refstorage/reference_storage.h"
44 #include "runtime/entrypoints/entrypoints.h"
45 #include "events/events.h"
46 
47 #define ASSERT_HAVE_ACCESS_TO_MANAGED_OBJECTS()
48 
49 namespace panda {
50 
51 template <class TYPE>
52 class HandleStorage;
53 template <class TYPE>
54 class GlobalHandleStorage;
55 template <class TYPE>
56 class HandleScope;
57 
58 namespace test {
59 class ThreadTest;
60 }  // namespace test
61 
62 class ThreadManager;
63 class Runtime;
64 class PandaVM;
65 class MonitorPool;
66 
67 namespace mem {
68 class GCBarrierSet;
69 }  // namespace mem
70 
71 namespace tooling {
72 class PtThreadInfo;
73 }  // namespace tooling
74 
75 struct CustomTLSData {
76     CustomTLSData() = default;
77     virtual ~CustomTLSData() = default;
78 
79     NO_COPY_SEMANTIC(CustomTLSData);
80     NO_MOVE_SEMANTIC(CustomTLSData);
81 };
82 
83 class LockedObjectInfo {
84 public:
LockedObjectInfo(ObjectHeader * obj,void * fp)85     LockedObjectInfo(ObjectHeader *obj, void *fp) : object(obj), stack(fp) {}
GetObject()86     inline ObjectHeader *GetObject() const
87     {
88         return object;
89     }
90 
SetObject(ObjectHeader * obj_new)91     inline void SetObject(ObjectHeader *obj_new)
92     {
93         object = obj_new;
94     }
95 
GetStack()96     inline void *GetStack() const
97     {
98         return stack;
99     }
100 
SetStack(void * stack_new)101     inline void SetStack(void *stack_new)
102     {
103         stack = stack_new;
104     }
105 
GetMonitorOffset()106     static constexpr uint32_t GetMonitorOffset()
107     {
108         return MEMBER_OFFSET(LockedObjectInfo, object);
109     }
110 
GetStackOffset()111     static constexpr uint32_t GetStackOffset()
112     {
113         return MEMBER_OFFSET(LockedObjectInfo, stack);
114     }
115 
116 private:
117     ObjectHeader *object;
118     void *stack;
119 };
120 
121 template <typename Adapter = mem::AllocatorAdapter<LockedObjectInfo>>
122 class LockedObjectList {
123     static constexpr uint32_t DEFAULT_CAPACITY = 16;
124 
125 public:
LockedObjectList()126     LockedObjectList() : capacity_(DEFAULT_CAPACITY), allocator_(Adapter())
127     {
128         storage_ = allocator_.allocate(DEFAULT_CAPACITY);
129     }
130 
~LockedObjectList()131     ~LockedObjectList()
132     {
133         allocator_.deallocate(storage_, capacity_);
134     }
135 
136     NO_COPY_SEMANTIC(LockedObjectList);
137     NO_MOVE_SEMANTIC(LockedObjectList);
138 
push_back(LockedObjectInfo data)139     void push_back(LockedObjectInfo data)
140     {
141         ExtendIfNeeded();
142         storage_[size_++] = data;
143     }
144 
145     template <typename... Args>
emplace_back(Args &&...args)146     LockedObjectInfo &emplace_back(Args &&... args)
147     {
148         ExtendIfNeeded();
149         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
150         auto *raw_mem = &storage_[size_];
151         auto *datum = new (raw_mem) LockedObjectInfo(std::forward<Args>(args)...);
152         size_++;
153         return *datum;
154     }
155 
back()156     LockedObjectInfo &back()
157     {
158         ASSERT(size_ > 0);
159         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
160         return storage_[size_ - 1];
161     }
162 
empty()163     bool empty() const
164     {
165         return size_ == 0;
166     }
167 
pop_back()168     void pop_back()
169     {
170         ASSERT(size_ > 0);
171         --size_;
172         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
173         (&storage_[size_])->~LockedObjectInfo();
174     }
175 
data()176     Span<LockedObjectInfo> data()
177     {
178         return Span<LockedObjectInfo>(storage_, size_);
179     }
180 
GetCapacityOffset()181     static constexpr uint32_t GetCapacityOffset()
182     {
183         return MEMBER_OFFSET(LockedObjectList, capacity_);
184     }
185 
GetSizeOffset()186     static constexpr uint32_t GetSizeOffset()
187     {
188         return MEMBER_OFFSET(LockedObjectList, size_);
189     }
190 
GetDataOffset()191     static constexpr uint32_t GetDataOffset()
192     {
193         return MEMBER_OFFSET(LockedObjectList, storage_);
194     }
195 
196 private:
ExtendIfNeeded()197     void ExtendIfNeeded()
198     {
199         ASSERT(size_ <= capacity_);
200         if (size_ < capacity_) {
201             return;
202         }
203         uint32_t new_capacity = capacity_ * 3U / 2U;  // expand by 1.5
204         LockedObjectInfo *new_storage = allocator_.allocate(new_capacity);
205         ASSERT(new_storage != nullptr);
206         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
207         std::copy(storage_, storage_ + size_, new_storage);
208         allocator_.deallocate(storage_, capacity_);
209         storage_ = new_storage;
210         capacity_ = new_capacity;
211     }
212 
213     template <typename T, size_t alignment = sizeof(T)>
214     using Aligned __attribute__((aligned(alignment))) = T;
215     // Use uint32_t instead of size_t to guarantee the same size
216     // on all platforms and simplify compiler stubs accessing this fields.
217     // uint32_t is large enough to fit locked objects list's size.
218     Aligned<uint32_t> capacity_;
219     Aligned<uint32_t> size_ {0};
220     Aligned<LockedObjectInfo *> storage_;
221     Adapter allocator_;
222 };
223 
224 /**
225  *  Hierarchy of thread classes
226  *
227  *         +--------+
228  *         | Thread |
229  *         +--------+
230  *             |
231  *      +---------------+
232  *      | ManagedThread |
233  *      +---------------+
234  *             |
235  *     +-----------------+
236  *     | MTManagedThread |
237  *     +-----------------+
238  *
239  *
240  *  Thread - is the most low-level entity. This class contains pointers to VM which this thread associated.
241  *  ManagedThread - stores runtime context to run managed code in single-threaded environment
242  *  MTManagedThread - extends ManagedThread to be able to run code in multi-threaded environment
243  */
244 
245 /**
246  * \brief Class represents arbitrary runtime thread
247  */
248 // NOLINTNEXTLINE(clang-analyzer-optin.performance.Padding)
249 class Thread {
250 public:
251     using ThreadId = uint32_t;
252     enum class ThreadType {
253         THREAD_TYPE_NONE,
254         THREAD_TYPE_GC,
255         THREAD_TYPE_COMPILER,
256         THREAD_TYPE_MANAGED,
257         THREAD_TYPE_MT_MANAGED,
258         THREAD_TYPE_TASK,
259         THREAD_TYPE_WORKER_THREAD,
260     };
261 
262     Thread(PandaVM *vm, ThreadType thread_type);
263     virtual ~Thread();
264     NO_COPY_SEMANTIC(Thread);
265     NO_MOVE_SEMANTIC(Thread);
266 
267     PANDA_PUBLIC_API static Thread *GetCurrent();
268     PANDA_PUBLIC_API static void SetCurrent(Thread *thread);
269 
270     virtual void FreeInternalMemory();
271 
272     void FreeAllocatedMemory();
273 
GetVM()274     PandaVM *GetVM() const
275     {
276         return vm_;
277     }
278 
SetVM(PandaVM * vm)279     void SetVM(PandaVM *vm)
280     {
281         vm_ = vm;
282     }
283 
GetThreadType()284     ThreadType GetThreadType() const
285     {
286         return thread_type_;
287     }
288 
GetBarrierSet()289     ALWAYS_INLINE mem::GCBarrierSet *GetBarrierSet() const
290     {
291         return barrier_set_;
292     }
293 
294 #ifndef NDEBUG
GetLockState()295     MutatorLock::MutatorLockState GetLockState() const
296     {
297         return lock_state;
298     }
299 
SetLockState(MutatorLock::MutatorLockState state)300     void SetLockState(MutatorLock::MutatorLockState state)
301     {
302         lock_state = state;
303     }
304 #endif
305 
306     // pre_buff_ may be destroyed during Detach(), so it should be initialized once more
307     void InitPreBuff();
308 
309 protected:
310     union __attribute__((__aligned__(4))) FlagsAndThreadStatus {
311         FlagsAndThreadStatus() = default;
312         ~FlagsAndThreadStatus() = default;
313         struct __attribute__((packed)) {
314             volatile uint16_t flags;
315             volatile enum ThreadStatus status;
316         } as_struct;
317         volatile uint32_t as_int;
318         uint32_t as_nonvolatile_int;
319         std::atomic_uint32_t as_atomic;
320 
321         NO_COPY_SEMANTIC(FlagsAndThreadStatus);
322         NO_MOVE_SEMANTIC(FlagsAndThreadStatus);
323     };
324 
325     bool is_compiled_frame_ {false};  // NOLINT(misc-non-private-member-variables-in-classes)
326     // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
327     FlagsAndThreadStatus fts_ {};
328     ThreadId internal_id_ {0};  // NOLINT(misc-non-private-member-variables-in-classes)
329 
330     EntrypointsTable entrypoints_ {};                  // NOLINT(misc-non-private-member-variables-in-classes)
331     void *object_ {nullptr};                           // NOLINT(misc-non-private-member-variables-in-classes)
332     Frame *frame_ {nullptr};                           // NOLINT(misc-non-private-member-variables-in-classes)
333     ObjectHeader *exception_ {nullptr};                // NOLINT(misc-non-private-member-variables-in-classes)
334     uintptr_t native_pc_ {};                           // NOLINT(misc-non-private-member-variables-in-classes)
335     mem::TLAB *tlab_ {nullptr};                        // NOLINT(misc-non-private-member-variables-in-classes)
336     void *card_table_addr_ {nullptr};                  // NOLINT(misc-non-private-member-variables-in-classes)
337     void *card_table_min_addr_ {nullptr};              // NOLINT(misc-non-private-member-variables-in-classes)
338     void *concurrent_marking_addr_ {nullptr};          // NOLINT(misc-non-private-member-variables-in-classes)
339     void *string_class_ptr_ {nullptr};                 // NOLINT(misc-non-private-member-variables-in-classes)
340     PandaVector<ObjectHeader *> *pre_buff_ {nullptr};  // NOLINT(misc-non-private-member-variables-in-classes)
341     void *language_extension_data_ {nullptr};          // NOLINT(misc-non-private-member-variables-in-classes)
342                                                        // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes)
343     mem::GCG1BarrierSet::G1PostBarrierRingBufferType *g1_post_barrier_ring_buffer_ {nullptr};
344 #ifndef NDEBUG
345     uintptr_t runtime_call_enabled_ {1};  // NOLINT(misc-non-private-member-variables-in-classes)
346 #endif
347 
348 private:
349     void InitCardTableData(mem::GCBarrierSet *barrier);
350 
351     PandaVM *vm_ {nullptr};
352     ThreadType thread_type_ {ThreadType::THREAD_TYPE_NONE};
353     mem::GCBarrierSet *barrier_set_ {nullptr};
354 #ifndef NDEBUG
355     MutatorLock::MutatorLockState lock_state = MutatorLock::UNLOCKED;
356 #endif
357 };
358 
359 template <typename ThreadT>
360 class ScopedCurrentThread {
361 public:
ScopedCurrentThread(ThreadT * thread)362     explicit ScopedCurrentThread(ThreadT *thread) : thread_(thread)
363     {
364         ASSERT(Thread::GetCurrent() == nullptr);
365 
366         // Set current thread
367         Thread::SetCurrent(thread_);
368     }
369 
~ScopedCurrentThread()370     ~ScopedCurrentThread()
371     {
372         // Reset current thread
373         Thread::SetCurrent(nullptr);
374     }
375 
376     NO_COPY_SEMANTIC(ScopedCurrentThread);
377     NO_MOVE_SEMANTIC(ScopedCurrentThread);
378 
379 private:
380     ThreadT *thread_;
381 };
382 
383 enum ThreadFlag {
384     NO_FLAGS = 0,
385     GC_SAFEPOINT_REQUEST = 1,
386     SUSPEND_REQUEST = 2,
387     RUNTIME_TERMINATION_REQUEST = 4,
388 };
389 }  // namespace panda
390 
391 #endif  // PANDA_RUNTIME_THREAD_H_
392