#include "partition_alloc/extended_api.h"
#include "partition_alloc/buildflags.h"
#include "partition_alloc/internal/thread_cache_internal.h"
#include "partition_alloc/partition_alloc_config.h"
#include "partition_alloc/shim/allocator_shim_default_dispatch_to_partition_alloc.h"
namespace partition_alloc::internal {
#if PA_CONFIG(THREAD_CACHE_SUPPORTED)
namespace {
void DisableThreadCacheForRootIfEnabled(PartitionRoot* root) {
if (!root || !root->settings_.with_thread_cache) {
return;
}
ThreadCacheRegistry::Instance().PurgeAll();
root->settings_.with_thread_cache = false;
root->settings_.thread_cache_index = kInvalidThreadCacheIndex;
}
void EnablePartitionAllocThreadCacheForRootIfDisabled(
PartitionRoot* root,
size_t thread_cache_index = kDefaultRootThreadCacheIndex) {
if (!root) {
return;
}
root->settings_.with_thread_cache = true;
root->settings_.thread_cache_index = thread_cache_index;
}
#if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
void DisablePartitionAllocThreadCacheForProcess() {
PA_CHECK(allocator_shim::internal::PartitionAllocMalloc::
AllocatorConfigurationFinalized());
for (size_t alloc_token = 0; alloc_token < allocator_shim::kNumPartitions;
alloc_token++) {
DisableThreadCacheForRootIfEnabled(
allocator_shim::internal::PartitionAllocMalloc::Allocator(
allocator_shim::AllocToken(alloc_token)));
DisableThreadCacheForRootIfEnabled(
allocator_shim::internal::PartitionAllocMalloc::OriginalAllocator(
allocator_shim::AllocToken(alloc_token)));
}
}
void EnablePartitionAllocThreadCacheForProcess() {
PA_CHECK(allocator_shim::internal::PartitionAllocMalloc::
AllocatorConfigurationFinalized());
for (size_t alloc_token = 0; alloc_token < allocator_shim::kNumPartitions;
alloc_token++) {
EnablePartitionAllocThreadCacheForRootIfDisabled(
allocator_shim::internal::PartitionAllocMalloc::Allocator(
allocator_shim::AllocToken(alloc_token)),
alloc_token);
}
}
#endif
}
#endif
ThreadAllocStats GetAllocStatsForCurrentThread() {
ThreadCache* thread_cache = ThreadCache::Get(kDefaultRootThreadCacheIndex);
if (ThreadCache::IsValid(thread_cache)) {
return thread_cache->thread_alloc_stats();
}
return {};
}
#if PA_CONFIG(THREAD_CACHE_SUPPORTED)
ThreadCacheProcessScopeForTesting::ThreadCacheProcessScopeForTesting(
PartitionRoot* root)
: root_(root) {
#if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
auto* regular_allocator =
allocator_shim::internal::PartitionAllocMalloc::Allocator();
regular_was_enabled_ =
regular_allocator && regular_allocator->settings_.with_thread_cache;
if (root_ != regular_allocator) {
DisablePartitionAllocThreadCacheForProcess();
EnablePartitionAllocThreadCacheForRootIfDisabled(root_);
ThreadCache::SwapForTesting(root_, kDefaultRootThreadCacheIndex);
} else {
bool regular_was_disabled = !regular_was_enabled_;
#if PA_BUILDFLAG(IS_WIN)
if (ThreadCache::IsTombstone()) {
ThreadCache::RemoveTombstoneForTesting();
regular_was_disabled = true;
}
#endif
if (regular_was_disabled) {
EnablePartitionAllocThreadCacheForRootIfDisabled(root_);
ThreadCache::SwapForTesting(root_, kDefaultRootThreadCacheIndex);
}
}
#else
PA_CHECK(
!ThreadCache::IsValid(ThreadCache::Get(kDefaultRootThreadCacheIndex)));
EnablePartitionAllocThreadCacheForRootIfDisabled(root_);
ThreadCache::SwapForTesting(root_, kDefaultRootThreadCacheIndex);
#endif
PA_CHECK(ThreadCache::Get(kDefaultRootThreadCacheIndex));
PA_CHECK(!ThreadCache::IsTombstone());
}
ThreadCacheProcessScopeForTesting::~ThreadCacheProcessScopeForTesting() {
#if PA_BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
auto* regular_allocator =
allocator_shim::internal::PartitionAllocMalloc::Allocator();
bool regular_enabled =
regular_allocator && regular_allocator->settings_.with_thread_cache;
if (regular_was_enabled_) {
if (!regular_enabled) {
EnablePartitionAllocThreadCacheForProcess();
ThreadCache::SwapForTesting(regular_allocator,
kDefaultRootThreadCacheIndex);
} else {
if (regular_allocator != root_) {
ThreadCache::SwapForTesting(regular_allocator,
kDefaultRootThreadCacheIndex);
}
}
} else {
DisableThreadCacheForRootIfEnabled(regular_allocator);
ThreadCache::SwapForTesting(nullptr, kDefaultRootThreadCacheIndex);
}
#else
DisableThreadCacheForRootIfEnabled(root_);
ThreadCache::SwapForTesting(nullptr, kDefaultRootThreadCacheIndex);
#endif }
#endif
}