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