1 /*
2 * Copyright (c) 2021 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 #include "runtime/thread_manager.h"
17
18 #include "libpandabase/utils/logger.h"
19 #include "libpandabase/utils/utf.h"
20 #include "runtime/include/mem/allocator.h"
21 #include "runtime/include/runtime.h"
22 #include "runtime/include/panda_vm.h"
23 #include "runtime/include/thread_scopes.h"
24 #include "libpandabase/os/native_stack.h"
25 #include "libpandabase/os/thread.h"
26
27 namespace panda {
28
ThreadManager(mem::InternalAllocatorPtr allocator)29 ThreadManager::ThreadManager(mem::InternalAllocatorPtr allocator) : threads_(allocator->Adapter())
30 {
31 last_id_ = 0;
32 pending_threads_ = 0;
33 }
34
~ThreadManager()35 ThreadManager::~ThreadManager()
36 {
37 DeleteFinishedThreads();
38 threads_.clear();
39 }
40
GetInternalThreadIdWithLockHeld()41 uint32_t ThreadManager::GetInternalThreadIdWithLockHeld() REQUIRES(ids_lock_)
42 {
43 for (size_t i = 0; i < internal_thread_ids_.size(); i++) {
44 last_id_ = (last_id_ + 1) % internal_thread_ids_.size();
45 if (!internal_thread_ids_[last_id_]) {
46 internal_thread_ids_.set(last_id_);
47 return last_id_ + 1; // 0 is reserved as uninitialized value.
48 }
49 }
50 LOG(FATAL, RUNTIME) << "Out of internal thread ids";
51 UNREACHABLE();
52 }
53
GetInternalThreadId()54 uint32_t ThreadManager::GetInternalThreadId()
55 {
56 os::memory::LockHolder lock(ids_lock_);
57 return GetInternalThreadIdWithLockHeld();
58 }
59
RemoveInternalThreadIdWithLockHeld(uint32_t id)60 void ThreadManager::RemoveInternalThreadIdWithLockHeld(uint32_t id) REQUIRES(ids_lock_)
61 {
62 id--; // 0 is reserved as uninitialized value.
63 ASSERT(internal_thread_ids_[id]);
64 internal_thread_ids_.reset(id);
65 }
66
RemoveInternalThreadId(uint32_t id)67 void ThreadManager::RemoveInternalThreadId(uint32_t id)
68 {
69 os::memory::LockHolder lock(ids_lock_);
70 return RemoveInternalThreadIdWithLockHeld(id);
71 }
72
IsThreadExists(uint32_t thread_id)73 bool ThreadManager::IsThreadExists(uint32_t thread_id)
74 {
75 os::memory::LockHolder lock(thread_lock_);
76 auto i = threads_.begin();
77 while (i != threads_.end()) {
78 MTManagedThread *thread = *i;
79 if (thread->GetId() == thread_id) {
80 return true;
81 }
82 i++;
83 }
84 return false;
85 }
86
GetThreadIdByInternalThreadId(uint32_t thread_id)87 uint32_t ThreadManager::GetThreadIdByInternalThreadId(uint32_t thread_id)
88 {
89 os::memory::LockHolder lock(thread_lock_);
90 auto i = threads_.begin();
91 while (i != threads_.end()) {
92 MTManagedThread *thread = *i;
93 if (thread->GetInternalId() == thread_id) {
94 return thread->GetId();
95 }
96 i++;
97 }
98 return 0;
99 }
100
GetThreadByInternalThreadIdWithLockHeld(uint32_t thread_id)101 MTManagedThread *ThreadManager::GetThreadByInternalThreadIdWithLockHeld(uint32_t thread_id)
102 {
103 auto i = threads_.begin();
104 while (i != threads_.end()) {
105 MTManagedThread *thread = *i;
106 if (thread->GetInternalId() == thread_id) {
107 return thread;
108 }
109 i++;
110 }
111 return nullptr;
112 }
113
DeregisterSuspendedThreads()114 void ThreadManager::DeregisterSuspendedThreads()
115 {
116 if (pending_threads_ != 0) {
117 // There are threads, which are not completely registered
118 // We can not destroy other threads, as they may use shared data (waiting mutexes)
119 return;
120 }
121
122 auto current = MTManagedThread::GetCurrent();
123 auto i = threads_.begin();
124 while (i != threads_.end()) {
125 MTManagedThread *thread = *i;
126 auto status = thread->GetStatus();
127 // Do not deregister current thread (which should be in status NATIVE) as HasNoActiveThreads
128 // assumes it stays registered; do not deregister CREATED threads until they finish initializing
129 // which requires communication with ThreadManaged
130 // If thread status is not RUNNING, it's treated as suspended and we can deregister it
131 // Ignore state BLOCKED as it means we are trying to acquire lock in Monitor, which was created in
132 // internalAllocator
133 if (thread != current && CanDeregister(status)) {
134 if (thread->IsDaemon()) {
135 daemon_threads_count_--;
136 daemon_threads_.push_back(thread);
137 }
138 i = threads_.erase(i);
139 // Do not delete this thread structure as it may be used by suspended thread
140 threads_count_--;
141 continue;
142 }
143 i++;
144 }
145 }
146
WaitForDeregistration()147 void ThreadManager::WaitForDeregistration()
148 {
149 trace::ScopedTrace scoped_trace(__FUNCTION__);
150 {
151 os::memory::LockHolder lock(thread_lock_);
152
153 // First wait for non-daemon threads to finish
154 while (true) {
155 if (HasNoActiveThreads()) {
156 break;
157 }
158 stop_var_.TimedWait(&thread_lock_, WAIT_INTERVAL);
159 }
160
161 // Then stop daemon threads
162 StopDaemonThreads();
163
164 // Finally wait until all threads are suspended
165 while (true) {
166 DeregisterSuspendedThreads();
167 // Check for HasNoActiveThreads as new threads might be created by daemons
168 if (HasNoActiveThreads() && daemon_threads_count_ == 0) {
169 break;
170 }
171 stop_var_.TimedWait(&thread_lock_, WAIT_INTERVAL);
172 }
173 }
174 for (const auto &thread : daemon_threads_) {
175 thread->FreeInternalMemory();
176 }
177 }
178
StopDaemonThreads()179 void ThreadManager::StopDaemonThreads()
180 {
181 trace::ScopedTrace scoped_trace(__FUNCTION__);
182 auto i = threads_.begin();
183 while (i != threads_.end()) {
184 MTManagedThread *thread = *i;
185 if (thread->IsDaemon()) {
186 LOG(DEBUG, RUNTIME) << "Stopping daemon thread " << thread->GetId();
187 thread->StopDaemonThread();
188 }
189 i++;
190 }
191 // Suspend any future new threads
192 suspend_new_count_++;
193 }
194
GetThreadsCount()195 int ThreadManager::GetThreadsCount()
196 {
197 return threads_count_;
198 }
199
200 #ifndef NDEBUG
GetAllRegisteredThreadsCount()201 uint32_t ThreadManager::GetAllRegisteredThreadsCount()
202 {
203 return registered_threads_count_;
204 }
205 #endif // NDEBUG
206
SuspendAllThreads()207 void ThreadManager::SuspendAllThreads()
208 {
209 trace::ScopedTrace scoped_trace("Suspending mutator threads");
210 auto cur_thread = MTManagedThread::GetCurrent();
211 os::memory::LockHolder lock(thread_lock_);
212 EnumerateThreadsWithLockheld(
213 [cur_thread](MTManagedThread *thread) {
214 if (thread != cur_thread) {
215 thread->SuspendImpl(true);
216 }
217 return true;
218 },
219 static_cast<unsigned int>(EnumerationFlag::ALL));
220 suspend_new_count_++;
221 }
222
ResumeAllThreads()223 void ThreadManager::ResumeAllThreads()
224 {
225 trace::ScopedTrace scoped_trace("Resuming mutator threads");
226 auto cur_thread = MTManagedThread::GetCurrent();
227 os::memory::LockHolder lock(thread_lock_);
228 if (suspend_new_count_ > 0) {
229 suspend_new_count_--;
230 }
231 EnumerateThreadsWithLockheld(
232 [cur_thread](MTManagedThread *thread) {
233 if (thread != cur_thread) {
234 thread->ResumeImpl(true);
235 }
236 return true;
237 },
238 static_cast<unsigned int>(EnumerationFlag::ALL));
239 }
240
UnregisterExitedThread(MTManagedThread * thread)241 bool ThreadManager::UnregisterExitedThread(MTManagedThread *thread)
242 {
243 ASSERT(MTManagedThread::GetCurrent() == thread);
244 os::memory::LockHolder lock(thread_lock_);
245
246 LOG(DEBUG, RUNTIME) << "Stopping thread " << thread->GetId();
247 thread->UpdateStatus(FINISHED);
248 // Do not delete main thread, Runtime::GetMainThread is expected to always return valid object
249 if (thread == main_thread_) {
250 return false;
251 }
252
253 // While this thread is suspended, do not delete it as other thread can be accessing it.
254 // TestAllFlags is required because termination request can be sent while thread_lock_ is unlocked
255 while (thread->TestAllFlags()) {
256 thread_lock_.Unlock();
257 thread->SafepointPoll();
258 thread_lock_.Lock();
259 }
260 // This code should happen after thread has been resumed: Both WaitSuspension and ResumeImps requires locking
261 // suspend_lock_, so it acts as a memory barrier; flag clean should be visible in this thread after exit from
262 // WaitSuspenion
263 TSAN_ANNOTATE_HAPPENS_AFTER(&thread->stor_32_.fts_);
264
265 threads_.remove(thread);
266 if (thread->IsDaemon()) {
267 daemon_threads_count_--;
268 }
269 threads_count_--;
270
271 // If java_thead, its nativePeer should be 0 before
272 delete thread;
273 stop_var_.Signal();
274 return true;
275 }
276
RegisterSensitiveThread() const277 void ThreadManager::RegisterSensitiveThread() const
278 {
279 LOG(INFO, RUNTIME) << __func__ << " is an empty implementation now.";
280 }
281
DumpUnattachedThreads(std::ostream & os)282 void ThreadManager::DumpUnattachedThreads(std::ostream &os)
283 {
284 os::native_stack::DumpUnattachedThread dump;
285 dump.InitKernelTidLists();
286 os::memory::LockHolder lock(thread_lock_);
287 for (const auto &thread : threads_) {
288 dump.AddTid(static_cast<pid_t>(thread->GetId()));
289 }
290 dump.Dump(os, Runtime::GetCurrent()->IsDumpNativeCrash(), nullptr);
291 }
292
SuspendAndWaitThreadByInternalThreadId(uint32_t thread_id)293 MTManagedThread *ThreadManager::SuspendAndWaitThreadByInternalThreadId(uint32_t thread_id)
294 {
295 static constexpr uint32_t YIELD_ITERS = 500;
296 // NB! Expected to be called in registered thread, change implementation if this function used elsewhere
297 MTManagedThread *current = MTManagedThread::GetCurrent();
298 MTManagedThread *suspended = nullptr;
299 ASSERT(current->GetStatus() != ThreadStatus::RUNNING);
300 for (uint32_t loop_iter = 0;; loop_iter++) {
301 if (suspended == nullptr) {
302 // If two threads call SuspendAndWaitThreadByInternalThreadId concurrently, one has to get suspended
303 // while other waits for thread to be suspended, so thread_lock_ is required to be held until
304 // SuspendImpl is called
305 ScopedManagedCodeThread sa(current);
306 os::memory::LockHolder lock(thread_lock_);
307 auto *thread = GetThreadByInternalThreadIdWithLockHeld(thread_id);
308 if (thread != nullptr) {
309 ASSERT(current != thread);
310 // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_FUNCTION_NESTING_LEVEL)
311 if (current->IsSuspended()) {
312 // Unsafe to suspend as other thread may be waiting for this thread to suspend;
313 // Should get suspended on ScopedManagedCodeThread
314 continue;
315 }
316 thread->SuspendImpl(true);
317 suspended = thread;
318 } else {
319 // no thread found, exit
320 return nullptr;
321 }
322 } else if (suspended->GetStatus() != ThreadStatus::RUNNING) {
323 // Thread is suspended now
324 return suspended;
325 }
326 if (loop_iter < YIELD_ITERS) {
327 MTManagedThread::Yield();
328 } else {
329 static constexpr uint32_t SHORT_SLEEP_MS = 1;
330 os::thread::NativeSleep(SHORT_SLEEP_MS);
331 }
332 }
333 return nullptr;
334 }
335
336 } // namespace panda
337