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_MANAGER_H_ 16 #define PANDA_RUNTIME_THREAD_MANAGER_H_ 17 18 #include <bitset> 19 20 #include "libpandabase/os/mutex.h" 21 #include "libpandabase/utils/time.h" 22 #include "libpandabase/os/time.h" 23 #include "runtime/include/coretypes/array-inl.h" 24 #include "runtime/include/mem/panda_containers.h" 25 #include "runtime/include/mem/panda_smart_pointers.h" 26 #include "runtime/include/mtmanaged_thread.h" 27 #include "runtime/include/thread_status.h" 28 #include "runtime/include/locks.h" 29 30 namespace panda { 31 32 // This interval is required for waiting for threads to stop. 33 static const int WAIT_INTERVAL = 10; 34 static constexpr int64_t K_MAX_DUMP_TIME_NS = UINT64_C(6 * 1000 * 1000 * 1000); // 6s 35 static constexpr int64_t K_MAX_SINGLE_DUMP_TIME_NS = UINT64_C(50 * 1000 * 1000); // 50ms 36 37 enum class EnumerationFlag { 38 NONE = 0, // Nothing 39 NON_CORE_THREAD = 1, // Plugin type thread 40 MANAGED_CODE_THREAD = 2, // Thread which can execute managed code 41 VM_THREAD = 4, // Includes VM threads 42 ALL = 8, // See the comment in the function SatisfyTheMask below 43 }; 44 45 class ThreadManager { 46 public: 47 NO_COPY_SEMANTIC(ThreadManager); 48 NO_MOVE_SEMANTIC(ThreadManager); 49 50 // For performance reasons don't exceed specified amount of bits. 51 static constexpr size_t MAX_INTERNAL_THREAD_ID = std::min(0xffffU, ManagedThread::MAX_INTERNAL_THREAD_ID); 52 53 explicit ThreadManager(mem::InternalAllocatorPtr allocator); 54 55 virtual ~ThreadManager(); 56 57 template <class Callback> 58 void EnumerateThreads(const Callback &cb, unsigned int mask = static_cast<unsigned int>(EnumerationFlag::ALL), 59 unsigned int xor_mask = static_cast<unsigned int>(EnumerationFlag::NONE)) const 60 { 61 os::memory::LockHolder lock(thread_lock_); 62 63 EnumerateThreadsWithLockheld(cb, mask, xor_mask); 64 } 65 66 template <class Callback> 67 void EnumerateThreadsWithLockheld(const Callback &cb, 68 unsigned int inc_mask = static_cast<unsigned int>(EnumerationFlag::ALL), 69 unsigned int xor_mask = static_cast<unsigned int>(EnumerationFlag::NONE)) const REQUIRES(thread_lock_)70 REQUIRES(thread_lock_) 71 { 72 for (auto t : threads_) { 73 bool inc_target = SatisfyTheMask(t, inc_mask); 74 bool xor_target = SatisfyTheMask(t, xor_mask); 75 if (inc_target != xor_target) { 76 if (!cb(t)) { 77 break; 78 } 79 } 80 } 81 } 82 83 template <class Callback> EnumerateThreadsForDump(const Callback & cb,std::ostream & os)84 void EnumerateThreadsForDump(const Callback &cb, std::ostream &os) 85 { 86 // TODO: can not get WriteLock() when other thread run code "while {}" 87 // issue #3085 88 SuspendAllThreads(); 89 Locks::mutator_lock->WriteLock(); 90 MTManagedThread *self = MTManagedThread::GetCurrent(); 91 { 92 os << "ARK THREADS (" << threads_count_ << "):\n"; 93 } 94 if (self != nullptr) { 95 os::memory::LockHolder lock(thread_lock_); 96 int64_t start = panda::os::time::GetClockTimeInThreadCpuTime(); 97 int64_t end; 98 int64_t last_time = start; 99 cb(self, os); 100 for (const auto &thread : threads_) { 101 if (thread != self) { 102 cb(thread, os); 103 end = panda::os::time::GetClockTimeInThreadCpuTime(); 104 if ((end - last_time) > K_MAX_SINGLE_DUMP_TIME_NS) { 105 LOG(ERROR, RUNTIME) << "signal catcher: thread_list_dump thread : " << thread->GetId() 106 << "timeout : " << (end - last_time); 107 } 108 last_time = end; 109 if ((end - start) > K_MAX_DUMP_TIME_NS) { 110 LOG(ERROR, RUNTIME) << "signal catcher: thread_list_dump timeout : " << end - start << "\n"; 111 break; 112 } 113 } 114 } 115 } 116 Locks::mutator_lock->Unlock(); 117 ResumeAllThreads(); 118 } 119 RegisterThread(MTManagedThread * thread)120 void RegisterThread(MTManagedThread *thread) 121 { 122 os::memory::LockHolder lock(thread_lock_); 123 threads_count_++; 124 #ifndef NDEBUG 125 registered_threads_count_++; 126 #endif // NDEBUG 127 threads_.emplace_back(thread); 128 for (uint32_t i = suspend_new_count_; i > 0; i--) { 129 thread->SuspendImpl(true); 130 } 131 } 132 IncPendingThreads()133 void IncPendingThreads() 134 { 135 os::memory::LockHolder lock(thread_lock_); 136 pending_threads_++; 137 } 138 DecPendingThreads()139 void DecPendingThreads() 140 { 141 os::memory::LockHolder lock(thread_lock_); 142 pending_threads_--; 143 } 144 AddDaemonThread()145 void AddDaemonThread() 146 { 147 daemon_threads_count_++; 148 } 149 150 int GetThreadsCount(); 151 152 #ifndef NDEBUG 153 uint32_t GetAllRegisteredThreadsCount(); 154 #endif // NDEBUG 155 156 void WaitForDeregistration(); 157 158 void SuspendAllThreads(); 159 void ResumeAllThreads(); 160 161 uint32_t GetInternalThreadId(); 162 163 void RemoveInternalThreadId(uint32_t id); 164 165 bool IsRunningThreadExist(); 166 167 // Returns true if unregistration succeeded; for now it can fail when we are trying to unregister main thread 168 bool UnregisterExitedThread(MTManagedThread *thread); 169 170 MTManagedThread *SuspendAndWaitThreadByInternalThreadId(uint32_t thread_id); 171 172 void RegisterSensitiveThread() const; 173 GetThreadsLock()174 os::memory::Mutex *GetThreadsLock() 175 { 176 return &thread_lock_; 177 } 178 SetMainThread(ManagedThread * thread)179 void SetMainThread(ManagedThread *thread) 180 { 181 main_thread_ = thread; 182 } 183 184 private: HasNoActiveThreads()185 bool HasNoActiveThreads() const REQUIRES(thread_lock_) 186 { 187 ASSERT(threads_count_ >= daemon_threads_count_); 188 auto thread = static_cast<uint32_t>(threads_count_ - daemon_threads_count_); 189 return thread < 2 && pending_threads_ == 0; 190 } 191 192 bool StopThreadsOnDeadlock(MTManagedThread *current) REQUIRES(thread_lock_); 193 SatisfyTheMask(MTManagedThread * t,unsigned int mask)194 bool SatisfyTheMask(MTManagedThread *t, unsigned int mask) const 195 { 196 if ((mask & static_cast<unsigned int>(EnumerationFlag::ALL)) != 0) { 197 // Some uninitialized threads may not have attached flag, 198 // So, they are not included as MANAGED_CODE_THREAD. 199 // Newly created threads are using flag suspend new count. 200 // The case leads to deadlocks, when the thread can not be resumed. 201 // To deal with it, just add a specific ALL case 202 return true; 203 } 204 205 // For NONE mask 206 bool target = false; 207 if ((mask & static_cast<unsigned int>(EnumerationFlag::MANAGED_CODE_THREAD)) != 0) { 208 target = t->IsAttached(); 209 if ((mask & static_cast<unsigned int>(EnumerationFlag::NON_CORE_THREAD)) != 0) { 210 // Due to hyerarhical structure, we need to conjunct types 211 bool non_core_thread = t->GetThreadLang() != panda::panda_file::SourceLang::PANDA_ASSEMBLY; 212 target = target && non_core_thread; 213 } 214 } 215 216 if ((mask & static_cast<unsigned int>(EnumerationFlag::VM_THREAD)) != 0) { 217 target = target || t->IsVMThread(); 218 } 219 220 return target; 221 } 222 223 /** 224 * Tries to stop all daemon threads in case there are no active basic threads 225 * returns false if we need to wait 226 */ 227 void StopDaemonThreads() REQUIRES(thread_lock_); 228 229 /** 230 * Deregister all suspended threads including daemon threads. 231 * Returns true on success and false otherwise. 232 */ 233 bool DeregisterSuspendedThreads() REQUIRES(thread_lock_); 234 235 void DecreaseCountersForThread(MTManagedThread *thread) REQUIRES(thread_lock_); 236 237 MTManagedThread *GetThreadByInternalThreadIdWithLockHeld(uint32_t thread_id) REQUIRES(thread_lock_); 238 CanDeregister(enum ThreadStatus status)239 bool CanDeregister(enum ThreadStatus status) 240 { 241 // Deregister thread only for IS_TERMINATED_LOOP. 242 // In all other statuses we should wait: 243 // * CREATED - wait until threads finish initializing which requires communication with ThreadManager; 244 // * BLOCKED - it means we are trying to acquire lock in Monitor, which was created in internalAllocator; 245 // * TERMINATING - threads which requires communication with Runtime; 246 // * FINISHED threads should be deleted itself; 247 // * NATIVE threads are either go to FINISHED status or considered a part of a deadlock; 248 // * other statuses - should eventually go to IS_TERMINATED_LOOP or FINISHED status. 249 return status == ThreadStatus::IS_TERMINATED_LOOP; 250 } 251 252 mutable os::memory::Mutex thread_lock_; 253 ManagedThread *main_thread_ {nullptr}; 254 // Counter used to suspend newly created threads after SuspendAllThreads/SuspendDaemonThreads 255 uint32_t suspend_new_count_ GUARDED_BY(thread_lock_) = 0; 256 // We should delete only finished thread structures, so call delete explicitly on finished threads 257 // and don't touch other pointers 258 PandaList<MTManagedThread *> threads_ GUARDED_BY(thread_lock_); 259 os::memory::Mutex ids_lock_; 260 std::bitset<MAX_INTERNAL_THREAD_ID> internal_thread_ids_ GUARDED_BY(ids_lock_); 261 uint32_t last_id_ GUARDED_BY(ids_lock_); 262 PandaList<MTManagedThread *> daemon_threads_; 263 264 os::memory::ConditionVariable stop_var_; 265 std::atomic_uint32_t threads_count_ = 0; 266 #ifndef NDEBUG 267 // This field is required for counting all registered threads (including finished daemons) 268 // in AttachThreadTest. It is not needed in production mode. 269 std::atomic_uint32_t registered_threads_count_ = 0; 270 #endif // NDEBUG 271 std::atomic_uint32_t daemon_threads_count_ = 0; 272 // A specific counter of threads, which are not completely created 273 // When the counter != 0, operations with thread set are permitted to avoid destruction of shared data (mutexes) 274 // Synchronized with lock (not atomic) for mutual exclusion with thread operations 275 int pending_threads_ GUARDED_BY(thread_lock_); 276 }; 277 278 } // namespace panda 279 280 #endif // PANDA_RUNTIME_THREAD_MANAGER_H_ 281