• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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