1 /*
2 * Copyright (c) 2025 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 #include "common_components/mutator/mutator_manager.h"
16
17 #include <thread>
18
19 #include "common_components/base/time_utils.h"
20 #include "common_components/heap/collector/finalizer_processor.h"
21 #include "common_components/heap/collector/marking_collector.h"
22 #include "common_components/heap/heap.h"
23 #include "common_components/mutator/mutator.inline.h"
24
25 namespace common {
26 bool g_enableGCTimeoutCheck = true;
27
IsRuntimeThread()28 bool IsRuntimeThread()
29 {
30 if (static_cast<int>(ThreadLocal::GetThreadType()) >= static_cast<int>(ThreadType::GC_THREAD)) {
31 return true;
32 }
33 return false;
34 }
35
IsGcThread()36 bool IsGcThread()
37 {
38 if (static_cast<int>(ThreadLocal::GetThreadType()) == static_cast<int>(ThreadType::GC_THREAD)) {
39 return true;
40 }
41 return false;
42 }
43
BindMutator(Mutator & mutator) const44 void MutatorManager::BindMutator(Mutator& mutator) const
45 {
46 ThreadLocalData* tlData = ThreadLocal::GetThreadLocalData();
47 if (UNLIKELY_CC(tlData->buffer == nullptr)) {
48 (void)AllocationBuffer::GetOrCreateAllocBuffer();
49 }
50 mutator.SetSafepointActive(false);
51 tlData->mutator = &mutator;
52 }
53
UnbindMutator(Mutator & mutator) const54 void MutatorManager::UnbindMutator(Mutator& mutator) const
55 {
56 ThreadLocalData* tlData = ThreadLocal::GetThreadLocalData();
57 tlData->mutator = nullptr;
58 tlData->buffer = nullptr;
59 }
60
BindMutatorOnly(Mutator * mutator) const61 bool MutatorManager::BindMutatorOnly(Mutator *mutator) const
62 {
63 // watch dog thread may call this function and copy barrier may occur, so bind mutator here.
64 common::ThreadLocalData* tlData = common::ThreadLocal::GetThreadLocalData();
65 ASSERT(tlData != nullptr);
66 if (tlData->mutator == nullptr) {
67 tlData->mutator = mutator;
68 return true;
69 }
70 return false;
71 }
72
UnbindMutatorOnly() const73 void MutatorManager::UnbindMutatorOnly() const
74 {
75 ThreadLocalData* tlData = ThreadLocal::GetThreadLocalData();
76 tlData->mutator = nullptr;
77 }
78
CreateMutator()79 Mutator* MutatorManager::CreateMutator()
80 {
81 Mutator* mutator = ThreadLocal::GetMutator();
82 ASSERT_LOGF(mutator != nullptr, "Mutator already exists");
83 MutatorManagementRLock();
84 mutator->Init();
85 mutator->InitTid();
86 BindMutator(*mutator);
87 mutator->SetMutatorPhase(Heap::GetHeap().GetGCPhase());
88 MutatorManagementRUnlock();
89 return mutator;
90 }
91
TransitMutatorToExit()92 void MutatorManager::TransitMutatorToExit()
93 {
94 Mutator* mutator = Mutator::GetMutator();
95 LOGF_CHECK(mutator != nullptr) << "Mutator has not initialized or has been fini: " << mutator;
96 ASSERT_LOGF(!mutator->InSaferegion(), "Mutator to be fini should not be in saferegion");
97 // Enter saferegion to avoid blocking gc stw
98 mutator->MutatorLock();
99 mutator->ResetMutator();
100 mutator->MutatorUnlock();
101 (void)mutator->EnterSaferegion(false);
102 UnbindMutator(*mutator);
103 }
104
DestroyExpiredMutators()105 void MutatorManager::DestroyExpiredMutators()
106 {
107 expiringMutatorListLock_.lock();
108 ExpiredMutatorList workList;
109 workList.swap(expiringMutators_);
110 expiringMutatorListLock_.unlock();
111 for (auto it = workList.begin(); it != workList.end(); ++it) {
112 Mutator* expiringMutator = *it;
113 delete expiringMutator;
114 }
115 }
116
DestroyMutator(Mutator * mutator)117 void MutatorManager::DestroyMutator(Mutator* mutator)
118 {
119 if (TryAcquireMutatorManagementRLock()) {
120 delete mutator; // call ~Mutator() under mutatorListLock
121 MutatorManagementRUnlock();
122 } else {
123 expiringMutatorListLock_.lock();
124 expiringMutators_.push_back(mutator);
125 expiringMutatorListLock_.unlock();
126 }
127 }
128
CreateRuntimeMutator(ThreadType threadType)129 Mutator* MutatorManager::CreateRuntimeMutator(ThreadType threadType)
130 {
131 // Because TSAN tool can't identify the RwLock implemented by ourselves,
132 // we use a global instance fpMutatorInstance instead of an instance created on
133 // heap in order to prevent false positives.
134 static Mutator fpMutatorInstance;
135 Mutator* mutator = nullptr;
136 if (threadType == ThreadType::FP_THREAD) {
137 mutator = &fpMutatorInstance;
138 } else {
139 mutator = new (std::nothrow) Mutator();
140 }
141 LOGF_CHECK(mutator != nullptr) << "create mutator out of native memory";
142 MutatorManagementRLock();
143 mutator->Init();
144 mutator->InitTid();
145 MutatorManager::Instance().BindMutator(*mutator);
146 mutator->SetMutatorPhase(Heap::GetHeap().GetGCPhase());
147 ThreadLocal::SetMutator(mutator);
148 ThreadLocal::SetThreadType(threadType);
149 ThreadLocal::SetProcessorFlag(true);
150 ThreadLocalData* threadData = GetThreadLocalData();
151 PreRunManagedCode(mutator, 2, threadData); // 2 layers
152 // only running mutator can enter saferegion.
153 MutatorManagementRUnlock();
154 return mutator;
155 }
156
DestroyRuntimeMutator(ThreadType threadType)157 void MutatorManager::DestroyRuntimeMutator(ThreadType threadType)
158 {
159 Mutator* mutator = ThreadLocal::GetMutator();
160 LOGF_CHECK(mutator != nullptr) << "Fini UpdateThreads with null mutator";
161
162 MutatorManagementRLock();
163 (void)mutator->LeaveSaferegion();
164 // fp mutator is a static instance, we can't delete it, we reset the mutator to avoid invalid memory
165 // access when static instance destruction.
166 if (threadType != ThreadType::FP_THREAD) {
167 delete mutator;
168 } else {
169 mutator->ResetMutator();
170 }
171 ThreadLocal::SetAllocBuffer(nullptr);
172 ThreadLocal::SetMutator(nullptr);
173 ThreadLocal::SetProcessorFlag(false);
174 MutatorManagementRUnlock();
175 }
176
Init()177 void MutatorManager::Init()
178 {
179 #if defined(__linux__) || defined(PANDA_TARGET_OHOS) || defined(__APPLE__)
180 safepointPageManager_ = new (std::nothrow) SafepointPageManager();
181 LOGF_CHECK(safepointPageManager_ != nullptr) << "new safepointPageManager failed";
182 safepointPageManager_->Init();
183 #endif
184 }
185
Instance()186 MutatorManager& MutatorManager::Instance() noexcept
187 {
188 return BaseRuntime::GetInstance()->GetMutatorManager();
189 }
190
AcquireMutatorManagementWLock()191 void MutatorManager::AcquireMutatorManagementWLock()
192 {
193 uint64_t start = TimeUtil::NanoSeconds();
194 bool acquired = TryAcquireMutatorManagementWLock();
195 while (!acquired) {
196 TimeUtil::SleepForNano(WAIT_LOCK_INTERVAL);
197 acquired = TryAcquireMutatorManagementWLock();
198 uint64_t now = TimeUtil::NanoSeconds();
199 if (!acquired && ((now - start) / SECOND_TO_NANO_SECOND > WAIT_LOCK_TIMEOUT)) {
200 LOG_COMMON(FATAL) << "Wait mutator list lock timeout";
201 UNREACHABLE_CC();
202 }
203 }
204 }
205
AcquireMutatorManagementWLockForCpuProfile()206 bool MutatorManager::AcquireMutatorManagementWLockForCpuProfile()
207 {
208 uint64_t start = TimeUtil::NanoSeconds();
209 bool acquired = TryAcquireMutatorManagementWLock();
210 while (!acquired) {
211 TimeUtil::SleepForNano(WAIT_LOCK_INTERVAL);
212 acquired = TryAcquireMutatorManagementWLock();
213 uint64_t now = TimeUtil::NanoSeconds();
214 if (!acquired && ((now - start) / SECOND_TO_NANO_SECOND > WAIT_LOCK_TIMEOUT)) {
215 LOG_COMMON(FATAL) << "Wait mutator list lock timeout";
216 UNREACHABLE_CC();
217 }
218 }
219 return acquired;
220 }
221
222 // Visit all mutators, hold mutatorListLock firstly
VisitAllMutators(MutatorVisitor func,bool ignoreFinalizer)223 void MutatorManager::VisitAllMutators(MutatorVisitor func, bool ignoreFinalizer)
224 {
225 {
226 std::lock_guard<std::mutex> guard(allMutatorListLock_);
227 for (auto mutator : allMutatorList_) {
228 func(*mutator);
229 }
230 }
231 if (!ignoreFinalizer) {
232 Mutator* mutator = Heap::GetHeap().GetFinalizerProcessor().GetMutator();
233 if (mutator != nullptr) {
234 func(*mutator);
235 }
236 }
237 }
238
StopTheWorld(bool syncGCPhase,GCPhase phase)239 void MutatorManager::StopTheWorld(bool syncGCPhase, GCPhase phase)
240 {
241 #ifndef NDEBUG
242 bool saferegionEntered = false;
243 // Ensure an active mutator entered saferegion before STW (aka. stop all other mutators).
244 if (!IsGcThread()) {
245 Mutator* mutator = Mutator::GetMutator();
246 if (mutator != nullptr) {
247 saferegionEntered = mutator->EnterSaferegion(true);
248 }
249 }
250 #endif
251 // Block if another thread is holding the stwMutex.
252 // Prevent multi-thread doing STW concurrently.
253 stwMutex_.lock();
254 stwTriggered_.store(true);
255
256 AcquireMutatorManagementWLock();
257
258 #ifndef NDEBUG
259 // If current mutator saferegion state changed,
260 // we should restore it after the mutator called StartTheWorld().
261 saferegionStateChanged_ = saferegionEntered;
262 #endif
263
264 size_t mutatorCount = GetMutatorCount();
265 if (UNLIKELY_CC(mutatorCount == 0)) {
266 worldStopped_.store(true, std::memory_order_release);
267 if (syncGCPhase) { TransitionAllMutatorsToGCPhase(phase); }
268 return;
269 }
270 // set mutatorCount as countOfMutatorsToStop.
271 SetSuspensionMutatorCount(static_cast<uint32_t>(mutatorCount));
272 DemandSuspensionForStw();
273 WaitUntilAllStopped();
274
275 // the world is stopped.
276 worldStopped_.store(true, std::memory_order_release);
277 if (syncGCPhase) { TransitionAllMutatorsToGCPhase(phase); }
278 }
279
StartTheWorld()280 void MutatorManager::StartTheWorld() noexcept
281 {
282 #ifndef NDEBUG
283 bool shouldLeaveSaferegion = saferegionStateChanged_;
284 #endif
285 stwTriggered_.store(false);
286 worldStopped_.store(false, std::memory_order_release);
287
288 CancelSuspensionAfterStw();
289 SetSuspensionMutatorCount(0);
290
291 // wakeup all mutators which blocking on countOfMutatorsToStop futex.
292 #if defined(_WIN64) || defined(__APPLE__)
293 WakeAllMutators();
294 #else
295 (void)Futex(GetStwFutexWord(), FUTEX_WAKE, INT_MAX);
296 #endif
297
298 MutatorManagementWUnlock();
299
300 // Release stwMutex to allow other thread call STW.
301 stwMutex_.unlock();
302 #ifndef NDEBUG
303 // Restore saferegion state if the state is changed when mutator calls StopTheWorld().
304 if (!IsGcThread()) {
305 Mutator* mutator = Mutator::GetMutator();
306 if (mutator != nullptr && shouldLeaveSaferegion) {
307 (void)mutator->LeaveSaferegion();
308 }
309 }
310 #endif
311 }
312
WaitUntilAllStopped()313 void MutatorManager::WaitUntilAllStopped()
314 {
315 uint64_t beginTime = TimeUtil::MilliSeconds();
316 std::list<Mutator*> unstoppedMutators;
317 auto func = [&unstoppedMutators](Mutator& mutator) {
318 if ((!mutator.InSaferegion())) {
319 unstoppedMutators.emplace_back(&mutator);
320 }
321 };
322 VisitAllMutators(func);
323
324 size_t remainMutatorsSize = unstoppedMutators.size();
325 if (remainMutatorsSize == 0) {
326 return;
327 }
328
329 // Synchronize operation to ensure that all mutators complete phase transition
330 // Use unstoppedMutators to avoid traversing the entire mutatorList
331 int timeoutTimes = 0;
332 while (true) {
333 for (auto it = unstoppedMutators.begin(); it != unstoppedMutators.end();) {
334 Mutator* mutator = *it;
335 if (mutator->InSaferegion()) {
336 // current it(mutator) is finished by GC
337 it = unstoppedMutators.erase(it);
338 } else {
339 ++it; // skip current round & check it next round
340 }
341 }
342
343 if (unstoppedMutators.size() == 0) {
344 return;
345 }
346
347 if (UNLIKELY_CC(common::g_enableGCTimeoutCheck && TimeUtil::MilliSeconds() - beginTime >
348 (((remainMutatorsSize / STW_TIMEOUTS_THREADS_BASE_COUNT) * STW_TIMEOUTS_BASE_MS) + STW_TIMEOUTS_BASE_MS))) {
349 timeoutTimes++;
350 beginTime = TimeUtil::MilliSeconds();
351 DumpMutators(timeoutTimes);
352 }
353
354 (void)sched_yield();
355 }
356 }
357
EnsurePhaseTransition(GCPhase phase,std::list<Mutator * > & undoneMutators)358 void MutatorManager::EnsurePhaseTransition(GCPhase phase, std::list<Mutator*> &undoneMutators)
359 {
360 // Traverse through undoneMutators to select mutators that have not yet completed transition
361 // 1. ignore mutators which have completed transition
362 // 2. gc compete phase transition with mutators which are in saferegion
363 // 3. fill mutators which are running state in undoneMutators
364 while (undoneMutators.size() > 0) {
365 for (auto it = undoneMutators.begin(); it != undoneMutators.end();) {
366 Mutator* mutator = *it;
367 if (mutator->GetMutatorPhase() == phase && mutator->FinishedTransition()) {
368 it = undoneMutators.erase(it);
369 continue;
370 }
371 if (mutator->InSaferegion() && mutator->TransitionGCPhase(false)) {
372 it = undoneMutators.erase(it);
373 continue;
374 }
375 ++it;
376 }
377 }
378 }
379
TransitionAllMutatorsToGCPhase(GCPhase phase)380 void MutatorManager::TransitionAllMutatorsToGCPhase(GCPhase phase)
381 {
382 // Try to occupy mutatorListLock prevent some mutators from exiting
383 bool worldStopped = WorldStopped();
384 if (!worldStopped) {
385 AcquireMutatorManagementWLock();
386 }
387
388 GCPhase prevPhase = Heap::GetHeap().GetGCPhase();
389 // Set global gc phase in the scope of mutatorlist lock
390 Heap::GetHeap().InstallBarrier(phase);
391 Heap::GetHeap().SetGCPhase(phase);
392
393 VLOG(DEBUG, "transition gc phase: %s(%u) -> %s(%u)",
394 Collector::GetGCPhaseName(prevPhase), prevPhase, Collector::GetGCPhaseName(phase), phase);
395
396 std::list<Mutator*> undoneMutators;
397 // Broadcast mutator phase transition signal to all mutators
398 VisitAllMutators([&undoneMutators, phase](Mutator& mutator) {
399 mutator.SetSuspensionFlag(Mutator::SuspensionType::SUSPENSION_FOR_GC_PHASE);
400 mutator.SetSafepointActive(true);
401 undoneMutators.push_back(&mutator);
402 });
403 EnsurePhaseTransition(phase, undoneMutators);
404 if (!worldStopped) {
405 MutatorManagementWUnlock();
406 }
407 }
408
EnsureCpuProfileFinish(std::list<Mutator * > & undoneMutators)409 void MutatorManager::EnsureCpuProfileFinish(std::list<Mutator*> &undoneMutators)
410 {
411 while (undoneMutators.size() > 0) {
412 for (auto it = undoneMutators.begin(); it != undoneMutators.end();) {
413 Mutator* mutator = *it;
414 if (mutator->FinishedCpuProfile()) {
415 it = undoneMutators.erase(it);
416 continue;
417 }
418 if (mutator->InSaferegion() && mutator->TransitionToCpuProfile(false)) {
419 it = undoneMutators.erase(it);
420 continue;
421 }
422 ++it;
423 }
424 }
425 }
426
DumpMutators(uint32_t timeoutTimes)427 void MutatorManager::DumpMutators(uint32_t timeoutTimes)
428 {
429 constexpr size_t bufferSize = 4096;
430 char buf[bufferSize];
431 int index = 0;
432 size_t visitedCount = 0;
433 size_t visitedSaferegion = 0;
434 int firstNotStoppedTid = -1;
435 index += sprintf_s(buf, sizeof(buf), "not stopped: ");
436 LOGF_CHECK(index != -1) << "Dump mutators state failed";
437 size_t mutatorCount = 0;
438 VisitAllMutators([&](const Mutator& mut) {
439 mutatorCount++;
440 #ifndef NDEBUG
441 mut.DumpMutator();
442 #endif
443 if (!mut.InSaferegion()) {
444 if (firstNotStoppedTid == -1) {
445 firstNotStoppedTid = static_cast<int>(mut.GetTid());
446 }
447 int ret = sprintf_s(buf + index, sizeof(buf) - index, "%u ", mut.GetTid());
448 LOGF_CHECK(ret != -1) << "Dump mutators state failed";
449 index += ret;
450 } else {
451 ++visitedSaferegion;
452 }
453 ++visitedCount;
454 });
455 LOG_COMMON(ERROR) << "MutatorList size: " << mutatorCount;
456
457 LOGF_CHECK(sprintf_s(buf + index, sizeof(buf) - index, ", total: %u, visited: %zu/%zu",
458 GetSuspensionMutatorCount(), visitedSaferegion, visitedCount) != -1) <<
459 "Dump mutators state failed";
460 LOGF_CHECK(timeoutTimes <= MAX_TIMEOUT_TIMES) << "Waiting mutators entering saferegion timeout status info:" << buf;
461 LOG_COMMON(ERROR) << "STW status info: " << buf;
462 }
463
464 #if defined(GCINFO_DEBUG) && GCINFO_DEBUG
DumpForDebug()465 void MutatorManager::DumpForDebug()
466 {
467 size_t count = 0;
468 auto func = [&count](Mutator& mutator) {
469 mutator.DumpMutator();
470 count++;
471 };
472 VisitAllMutators(func);
473 LOG_COMMON(INFO) << "MutatorList size : " << count;
474 }
475
DumpAllGcInfos()476 void MutatorManager::DumpAllGcInfos()
477 {
478 auto func = [](Mutator& mutator) { mutator.DumpGCInfos(); };
479 VisitAllMutators(func);
480 }
481 #endif
482
483 } // namespace common
484