* 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 <bitset>
#include <list>
#include <mutex>
#include <unordered_set>
#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;
const uint64_t WAIT_LOCK_TIMEOUT = 30;
const uint32_t MAX_TIMEOUT_TIMES = 1;
const int STW_TIMEOUTS_THREADS_BASE_COUNT = 100;
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<void(Mutator&)>;
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(); }
size_t GetMutatorCount()
{
size_t count = 0;
auto func = [&count](Mutator&) { count++; };
VisitAllMutators(func);
return count;
}
void GetAllMutators(std::vector<Mutator*>& 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<Mutator*>(argPtr);
if (mutator != nullptr) {
(*reinterpret_cast<MutatorVisitor*>(handle))(*mutator);
}
}
void VisitAllMutators(MutatorVisitor func, bool ignoreFinalizer = false);
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;
Mutator* CreateMutator();
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<Mutator*> &undoneMutators);
void TransitionAllMutatorsToGCPhase(GCPhase phase);
void EnsureCpuProfileFinish(std::list<Mutator*> &undoneMutators);
template<class STWFunction>
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<int*>(&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<std::mutex> mutatorsToStopLck(mutatorSuspensionMtx_);
mutatorSuspensionCV_.wait(mutatorsToStopLck, [this]() {
return GetSuspensionMutatorCount() == 0;
});
}
__attribute__((always_inline)) inline void WakeAllMutators()
{
std::unique_lock<std::mutex> 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_;
std::list<Mutator*, StdContainerAllocator<Mutator*, MUTATOR_LIST>> allMutatorList_;
private:
using ExpiredMutatorList = std::list<Mutator*, StdContainerAllocator<Mutator*, MUTATOR_LIST>>;
ExpiredMutatorList expiringMutators_;
std::mutex expiringMutatorListLock_;
RwLock mutatorManagementRWLock_;
std::atomic<uint32_t> suspensionMutatorCount_;
std::recursive_mutex stwMutex_;
#ifndef NDEBUG
bool saferegionStateChanged_ = false;
#endif
std::atomic<bool> worldStopped_ = { false };
std::atomic<bool> 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;
};
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);
MutatorManager::Instance().StartTheWorld();
}
uint64_t GetElapsedTime() const { return TimeUtil::NanoSeconds() - startTime_; }
private:
uint64_t startTime_ = 0;
const char* reason_ = nullptr;
STWParam& stwParam_;
};
class ScopedSTWLock {
public:
__attribute__((always_inline)) explicit ScopedSTWLock() { MutatorManager::Instance().LockStopTheWorld(); }
__attribute__((always_inline)) ~ScopedSTWLock() { MutatorManager::Instance().UnlockStopTheWorld(); }
};
}
#endif