xref: /aosp_15_r20/external/cronet/base/allocator/partition_allocator/src/partition_alloc/partition_alloc.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "partition_alloc/partition_alloc.h"
6 
7 #include <cstdint>
8 #include <cstring>
9 #include <memory>
10 
11 #include "partition_alloc/address_pool_manager.h"
12 #include "partition_alloc/memory_reclaimer.h"
13 #include "partition_alloc/partition_address_space.h"
14 #include "partition_alloc/partition_alloc_base/debug/debugging_buildflags.h"
15 #include "partition_alloc/partition_alloc_buildflags.h"
16 #include "partition_alloc/partition_alloc_hooks.h"
17 #include "partition_alloc/partition_direct_map_extent.h"
18 #include "partition_alloc/partition_oom.h"
19 #include "partition_alloc/partition_page.h"
20 #include "partition_alloc/partition_root.h"
21 #include "partition_alloc/partition_stats.h"
22 
23 #if BUILDFLAG(USE_STARSCAN)
24 #include "partition_alloc/starscan/pcscan.h"
25 #endif
26 
27 namespace partition_alloc {
28 
PartitionAllocGlobalInit(OomFunction on_out_of_memory)29 void PartitionAllocGlobalInit(OomFunction on_out_of_memory) {
30   // This is from page_allocator_constants.h and doesn't really fit here, but
31   // there isn't a centralized initialization function in page_allocator.cc, so
32   // there's no good place in that file to do a STATIC_ASSERT_OR_PA_CHECK.
33   STATIC_ASSERT_OR_PA_CHECK(
34       (internal::SystemPageSize() & internal::SystemPageOffsetMask()) == 0,
35       "SystemPageSize() must be power of 2");
36 
37   // Two partition pages are used as guard / metadata page so make sure the
38   // super page size is bigger.
39   STATIC_ASSERT_OR_PA_CHECK(
40       internal::PartitionPageSize() * 4 <= internal::kSuperPageSize,
41       "ok super page size");
42   STATIC_ASSERT_OR_PA_CHECK(
43       (internal::kSuperPageSize & internal::SystemPageOffsetMask()) == 0,
44       "ok super page multiple");
45   // Four system pages gives us room to hack out a still-guard-paged piece
46   // of metadata in the middle of a guard partition page.
47   STATIC_ASSERT_OR_PA_CHECK(
48       internal::SystemPageSize() * 4 <= internal::PartitionPageSize(),
49       "ok partition page size");
50   STATIC_ASSERT_OR_PA_CHECK(
51       (internal::PartitionPageSize() & internal::SystemPageOffsetMask()) == 0,
52       "ok partition page multiple");
53   static_assert(
54       sizeof(internal::PartitionPageMetadata) <= internal::kPageMetadataSize,
55       "PartitionPage should not be too big");
56   STATIC_ASSERT_OR_PA_CHECK(
57       internal::kPageMetadataSize * internal::NumPartitionPagesPerSuperPage() <=
58           internal::SystemPageSize(),
59       "page metadata fits in hole");
60 
61   // Limit to prevent callers accidentally overflowing an int size.
62   STATIC_ASSERT_OR_PA_CHECK(
63       internal::MaxDirectMapped() <=
64           (1UL << 31) + internal::DirectMapAllocationGranularity(),
65       "maximum direct mapped allocation");
66 
67   // Check that some of our zanier calculations worked out as expected.
68   static_assert(internal::kSmallestBucket == internal::kAlignment,
69                 "generic smallest bucket");
70   static_assert(internal::kMaxBucketed == 983040, "generic max bucketed");
71   STATIC_ASSERT_OR_PA_CHECK(
72       internal::MaxSystemPagesPerRegularSlotSpan() <= 16,
73       "System pages per slot span must be no greater than 16.");
74 
75 #if BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
76   STATIC_ASSERT_OR_PA_CHECK(
77       internal::GetInSlotMetadataIndexMultiplierShift() <
78           std::numeric_limits<size_t>::max() / 2,
79       "Calculation in GetInSlotMetadataIndexMultiplierShift() must not "
80       "underflow.");
81   // Check that the GetInSlotMetadataIndexMultiplierShift() calculation is
82   // correct.
83   STATIC_ASSERT_OR_PA_CHECK(
84       (1 << internal::GetInSlotMetadataIndexMultiplierShift()) ==
85           (internal::SystemPageSize() /
86            (sizeof(internal::InSlotMetadata) *
87             (internal::kSuperPageSize / internal::SystemPageSize()))),
88       "Bitshift must match the intended multiplication.");
89   STATIC_ASSERT_OR_PA_CHECK(
90       ((sizeof(internal::InSlotMetadata) *
91         (internal::kSuperPageSize / internal::SystemPageSize()))
92        << internal::GetInSlotMetadataIndexMultiplierShift()) <=
93           internal::SystemPageSize(),
94       "InSlotMetadata table size must be smaller than or equal to "
95       "<= SystemPageSize().");
96 #endif  // BUILDFLAG(ENABLE_BACKUP_REF_PTR_SUPPORT)
97 
98   PA_DCHECK(on_out_of_memory);
99   internal::g_oom_handling_function = on_out_of_memory;
100 }
101 
PartitionAllocGlobalUninitForTesting()102 void PartitionAllocGlobalUninitForTesting() {
103 #if BUILDFLAG(ENABLE_THREAD_ISOLATION)
104   internal::PartitionAddressSpace::UninitThreadIsolatedPoolForTesting();
105 #endif
106   internal::g_oom_handling_function = nullptr;
107 }
108 
109 PartitionAllocator::PartitionAllocator() = default;
110 
~PartitionAllocator()111 PartitionAllocator::~PartitionAllocator() {
112   MemoryReclaimer::Instance()->UnregisterPartition(&partition_root_);
113 }
114 
init(PartitionOptions opts)115 void PartitionAllocator::init(PartitionOptions opts) {
116 #if BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
117   PA_CHECK(opts.thread_cache == PartitionOptions::kDisabled)
118       << "Cannot use a thread cache when PartitionAlloc is malloc().";
119 #endif
120   partition_root_.Init(opts);
121 #if BUILDFLAG(ENABLE_THREAD_ISOLATION)
122   // The MemoryReclaimer won't have write access to the partition, so skip
123   // registration.
124   const bool use_memory_reclaimer = !opts.thread_isolation.enabled;
125 #else
126   constexpr bool use_memory_reclaimer = true;
127 #endif
128   if (use_memory_reclaimer) {
129     MemoryReclaimer::Instance()->RegisterPartition(&partition_root_);
130   }
131 }
132 
133 }  // namespace partition_alloc
134