• 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_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