/* * Copyright (c) 2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef COMMON_COMPONENTS_MUTATOR_MUTATOR_MANAGER_H #define COMMON_COMPONENTS_MUTATOR_MUTATOR_MANAGER_H #include #include #include #include #include "common_components/base/atomic_spin_lock.h" #include "common_components/base/globals.h" #include "common_components/base/rw_lock.h" #include "common_components/common/page_allocator.h" #include "common_components/mutator/mutator.h" #if defined(__linux__) || defined(PANDA_TARGET_OHOS) || defined(__APPLE__) #include "common_components/mutator/safepoint_page_manager.h" #endif #include "common_components/mutator/thread_local.h" #include "common_components/log/log.h" namespace common { const uint64_t WAIT_LOCK_INTERVAL = 5000; // 5us const uint64_t WAIT_LOCK_TIMEOUT = 30; // seconds const uint32_t MAX_TIMEOUT_TIMES = 1; const int STW_TIMEOUTS_THREADS_BASE_COUNT = 100; // STW wait base timeout in milliseconds, for every 100 threads, the time is increased by 240000ms. const int STW_TIMEOUTS_BASE_MS = 240000; const uint32_t LOCK_OWNER_NONE = 0; const uint32_t LOCK_OWNER_GC = LOCK_OWNER_NONE + 1; const uint32_t LOCK_OWNER_MUTATOR = LOCK_OWNER_GC + 1; extern bool g_enableGCTimeoutCheck; bool IsRuntimeThread(); bool IsGcThread(); using MutatorVisitor = std::function; struct STWParam { const char* stwReason; uint64_t elapsedTimeNs = 0; uint64_t GetElapsedNs() const { return elapsedTimeNs; } uint64_t GetElapsedUs() const { return elapsedTimeNs / 1000; } }; class MutatorManager { public: MutatorManager() {} ~MutatorManager() { #if defined(__linux__) || defined(PANDA_TARGET_OHOS) || defined(__APPLE__) if (safepointPageManager_ != nullptr) { delete safepointPageManager_; safepointPageManager_ = nullptr; } #endif } MutatorManager(const MutatorManager&) = delete; MutatorManager(MutatorManager&&) = delete; MutatorManager& operator=(const MutatorManager&) = delete; MutatorManager& operator=(MutatorManager&&) = delete; static MutatorManager& Instance() noexcept; void Init(); void Fini() { SatbBuffer::Instance().Fini(); } // Get the mutator list instance size_t GetMutatorCount() { size_t count = 0; auto func = [&count](Mutator&) { count++; }; VisitAllMutators(func); return count; } void GetAllMutators(std::vector& mutators) { auto func = [&mutators](Mutator& mutator) { mutators.emplace_back(&mutator); }; VisitAllMutators(func); } bool TryAcquireMutatorManagementWLock() { return mutatorManagementRWLock_.TryLockWrite(); } bool TryAcquireMutatorManagementRLock() { return mutatorManagementRWLock_.TryLockRead(); } void AcquireMutatorManagementWLock(); bool AcquireMutatorManagementWLockForCpuProfile(); static void VisitMuatorHelper(void* argPtr, void* handle) { Mutator* mutator = reinterpret_cast(argPtr); if (mutator != nullptr) { (*reinterpret_cast(handle))(*mutator); } } // Visit all mutators, hold mutatorListLock firstly void VisitAllMutators(MutatorVisitor func, bool ignoreFinalizer = false); // Some functions about stw void StopTheWorld(bool syncGCPhase, GCPhase phase); void StartTheWorld() noexcept; void WaitUntilAllStopped(); void DumpMutators(uint32_t timeoutTimes); void DemandSuspensionForStw() { VisitAllMutators([](Mutator& mutator) { mutator.SetSafepointActive(true); mutator.SetSuspensionFlag(MutatorBase::SuspensionType::SUSPENSION_FOR_STW); }); } void CancelSuspensionAfterStw() { VisitAllMutators([](Mutator& mutator) { mutator.SetSafepointActive(false); mutator.ClearSuspensionFlag(MutatorBase::SuspensionType::SUSPENSION_FOR_STW); }); } void BindMutator(Mutator& mutator) const; void UnbindMutator(Mutator& mutator) const; bool BindMutatorOnly(Mutator *mutator) const; void UnbindMutatorOnly() const; // Create and initialize the local mutator, then register to mutatorlist. Mutator* CreateMutator(); // Delete the thread-local mutator and unregister from mutatorlist before a mutator exit void TransitMutatorToExit(); void DestroyMutator(Mutator* mutator); Mutator* CreateRuntimeMutator(ThreadType threadType) __attribute__((noinline)); void DestroyRuntimeMutator(ThreadType threadType); bool WorldStopped() const { return worldStopped_.load(std::memory_order_acquire); } bool StwTriggered() const { return stwTriggered_.load(); } void LockStopTheWorld() { stwMutex_.lock(); } void UnlockStopTheWorld() noexcept { stwMutex_.unlock(); } void EnsurePhaseTransition(GCPhase phase, std::list &undoneMutators); void TransitionAllMutatorsToGCPhase(GCPhase phase); void EnsureCpuProfileFinish(std::list &undoneMutators); template void FlipMutators(STWParam& param, STWFunction&& stwFunction, FlipFunction *flipFunction); #if defined(GCINFO_DEBUG) && GCINFO_DEBUG void DumpForDebug(); void DumpAllGcInfos(); #endif __attribute__((always_inline)) inline int* GetStwFutexWord() { return reinterpret_cast(&suspensionMutatorCount_); } __attribute__((always_inline)) inline int GetStwFutexWordValue() const { return GetSuspensionMutatorCount(); } __attribute__((always_inline)) inline uint32_t GetSuspensionMutatorCount() const { return suspensionMutatorCount_.load(std::memory_order_acquire); } __attribute__((always_inline)) inline void SetSuspensionMutatorCount(uint32_t total) { suspensionMutatorCount_.store(total, std::memory_order_release); } #if defined(_WIN64) || defined (__APPLE__) __attribute__((always_inline)) inline void MutatorWait() { std::unique_lock mutatorsToStopLck(mutatorSuspensionMtx_); mutatorSuspensionCV_.wait(mutatorsToStopLck, [this]() { return GetSuspensionMutatorCount() == 0; }); } __attribute__((always_inline)) inline void WakeAllMutators() { std::unique_lock mutatorsToStopLck(mutatorSuspensionMtx_); mutatorSuspensionCV_.notify_all(); } #endif #if not defined (_WIN64) const SafepointPageManager* GetSafepointPageManager() const { return safepointPageManager_; } #endif void MutatorManagementRLock() { mutatorManagementRWLock_.LockRead(); } void MutatorManagementRUnlock() { mutatorManagementRWLock_.UnlockRead(); } void MutatorManagementWLock() { mutatorManagementRWLock_.LockWrite(); } void MutatorManagementWUnlock() { mutatorManagementRWLock_.UnlockWrite(); } void DestroyExpiredMutators(); bool HasNativeMutator(); std::mutex allMutatorListLock_; /* Mutex guard for allMutatorList */ // Manage all mutator during runtime /* Manage all active mutators during runtime */ std::list> allMutatorList_; private: using ExpiredMutatorList = std::list>; ExpiredMutatorList expiringMutators_; std::mutex expiringMutatorListLock_; // guard mutator set for stop-the-world RwLock mutatorManagementRWLock_; // count of mutators need to be suspended for stw. // this field is also used as futex wait/wakeup word for stw. std::atomic suspensionMutatorCount_; // Ensure only one thread can doing STW. std::recursive_mutex stwMutex_; #ifndef NDEBUG bool saferegionStateChanged_ = false; #endif // Show current STW state std::atomic worldStopped_ = { false }; std::atomic stwTriggered_ = { false }; #if defined(_WIN64) || defined (__APPLE__) std::condition_variable mutatorSuspensionCV_; std::mutex mutatorSuspensionMtx_; #endif #if not defined (_WIN64) SafepointPageManager* safepointPageManager_ = nullptr; #endif Mutator* nativeMutator_ = nullptr; }; // Scoped stop the world. class ScopedStopTheWorld { public: __attribute__((always_inline)) explicit ScopedStopTheWorld(STWParam& param, bool syncGCPhase = false, GCPhase phase = GC_PHASE_IDLE) : stwParam_(param) { reason_ = param.stwReason; MutatorManager::Instance().StopTheWorld(syncGCPhase, phase); startTime_ = TimeUtil::NanoSeconds(); } __attribute__((always_inline)) ~ScopedStopTheWorld() { uint64_t elapsedTimeNs = GetElapsedTime(); stwParam_.elapsedTimeNs = elapsedTimeNs; VLOG(DEBUG, "%s stw time %zu us", reason_, elapsedTimeNs / 1000); // 1000:nsec per usec MutatorManager::Instance().StartTheWorld(); } uint64_t GetElapsedTime() const { return TimeUtil::NanoSeconds() - startTime_; } private: uint64_t startTime_ = 0; const char* reason_ = nullptr; STWParam& stwParam_; }; // Scoped lock STW, this prevent other thread STW during the current scope. class ScopedSTWLock { public: __attribute__((always_inline)) explicit ScopedSTWLock() { MutatorManager::Instance().LockStopTheWorld(); } __attribute__((always_inline)) ~ScopedSTWLock() { MutatorManager::Instance().UnlockStopTheWorld(); } }; } // namespace common #endif // COMMON_COMPONENTS_MUTATOR_MUTATOR_MANAGER_H