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