• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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 #ifndef BASE_ALLOCATOR_PARTITION_ALLOCATOR_ADDRESS_POOL_MANAGER_H_
6 #define BASE_ALLOCATOR_PARTITION_ALLOCATOR_ADDRESS_POOL_MANAGER_H_
7 
8 #include <bitset>
9 #include <limits>
10 
11 #include "base/allocator/partition_allocator/address_pool_manager_types.h"
12 #include "base/allocator/partition_allocator/partition_address_space.h"
13 #include "base/allocator/partition_allocator/partition_alloc_base/compiler_specific.h"
14 #include "base/allocator/partition_allocator/partition_alloc_base/component_export.h"
15 #include "base/allocator/partition_allocator/partition_alloc_base/debug/debugging_buildflags.h"
16 #include "base/allocator/partition_allocator/partition_alloc_base/thread_annotations.h"
17 #include "base/allocator/partition_allocator/partition_alloc_buildflags.h"
18 #include "base/allocator/partition_allocator/partition_alloc_check.h"
19 #include "base/allocator/partition_allocator/partition_alloc_constants.h"
20 #include "base/allocator/partition_allocator/partition_lock.h"
21 #include "build/build_config.h"
22 
23 #if !BUILDFLAG(HAS_64_BIT_POINTERS)
24 #include "base/allocator/partition_allocator/address_pool_manager_bitmap.h"
25 #endif
26 
27 namespace partition_alloc {
28 
29 class AddressSpaceStatsDumper;
30 struct AddressSpaceStats;
31 struct PoolStats;
32 
33 }  // namespace partition_alloc
34 
35 namespace partition_alloc::internal {
36 
37 // (64bit version)
38 // AddressPoolManager takes a reserved virtual address space and manages address
39 // space allocation.
40 //
41 // AddressPoolManager (currently) supports up to 4 pools. Each pool manages a
42 // contiguous reserved address space. Alloc() takes a pool_handle and returns
43 // address regions from the specified pool. Free() also takes a pool_handle and
44 // returns the address region back to the manager.
45 //
46 // (32bit version)
47 // AddressPoolManager wraps AllocPages and FreePages and remembers allocated
48 // address regions using bitmaps. IsManagedByPartitionAlloc*Pool use the bitmaps
49 // to judge whether a given address is in a pool that supports BackupRefPtr or
50 // in a pool that doesn't. All PartitionAlloc allocations must be in either of
51 // the pools.
PA_COMPONENT_EXPORT(PARTITION_ALLOC)52 class PA_COMPONENT_EXPORT(PARTITION_ALLOC) AddressPoolManager {
53  public:
54   static AddressPoolManager& GetInstance();
55 
56   AddressPoolManager(const AddressPoolManager&) = delete;
57   AddressPoolManager& operator=(const AddressPoolManager&) = delete;
58 
59 #if BUILDFLAG(HAS_64_BIT_POINTERS)
60   void Add(pool_handle handle, uintptr_t address, size_t length);
61   void Remove(pool_handle handle);
62 
63   // Populate a |used| bitset of superpages currently in use.
64   void GetPoolUsedSuperPages(pool_handle handle,
65                              std::bitset<kMaxSuperPagesInPool>& used);
66 
67   // Return the base address of a pool.
68   uintptr_t GetPoolBaseAddress(pool_handle handle);
69 #endif  // BUILDFLAG(HAS_64_BIT_POINTERS)
70 
71   // Reserves address space from the pool.
72   uintptr_t Reserve(pool_handle handle,
73                     uintptr_t requested_address,
74                     size_t length);
75 
76   // Frees address space back to the pool and decommits underlying system pages.
77   void UnreserveAndDecommit(pool_handle handle,
78                             uintptr_t address,
79                             size_t length);
80   void ResetForTesting();
81 
82 #if !BUILDFLAG(HAS_64_BIT_POINTERS)
83   void MarkUsed(pool_handle handle, uintptr_t address, size_t size);
84   void MarkUnused(pool_handle handle, uintptr_t address, size_t size);
85 
86   static bool IsManagedByRegularPool(uintptr_t address) {
87     return AddressPoolManagerBitmap::IsManagedByRegularPool(address);
88   }
89 
90   static bool IsManagedByBRPPool(uintptr_t address) {
91     return AddressPoolManagerBitmap::IsManagedByBRPPool(address);
92   }
93 #endif  // !BUILDFLAG(HAS_64_BIT_POINTERS)
94 
95   void DumpStats(AddressSpaceStatsDumper* dumper);
96 
97  private:
98   friend class AddressPoolManagerForTesting;
99 #if BUILDFLAG(ENABLE_PKEYS)
100   // If we use a pkey pool, we need to tag its metadata with the pkey. Allow the
101   // function to get access to the pool pointer.
102   friend void TagGlobalsWithPkey(int pkey);
103 #endif
104 
105   constexpr AddressPoolManager() = default;
106   ~AddressPoolManager() = default;
107 
108   // Populates `stats` if applicable.
109   // Returns whether `stats` was populated. (They might not be, e.g.
110   // if PartitionAlloc is wholly unused in this process.)
111   bool GetStats(AddressSpaceStats* stats);
112 
113 #if BUILDFLAG(HAS_64_BIT_POINTERS)
114   class Pool {
115    public:
116     constexpr Pool() = default;
117     ~Pool() = default;
118 
119     Pool(const Pool&) = delete;
120     Pool& operator=(const Pool&) = delete;
121 
122     void Initialize(uintptr_t ptr, size_t length);
123     bool IsInitialized();
124     void Reset();
125 
126     uintptr_t FindChunk(size_t size);
127     void FreeChunk(uintptr_t address, size_t size);
128 
129     bool TryReserveChunk(uintptr_t address, size_t size);
130 
131     void GetUsedSuperPages(std::bitset<kMaxSuperPagesInPool>& used);
132     uintptr_t GetBaseAddress();
133 
134     void GetStats(PoolStats* stats);
135 
136    private:
137     Lock lock_;
138 
139     // The bitset stores the allocation state of the address pool. 1 bit per
140     // super-page: 1 = allocated, 0 = free.
141     std::bitset<kMaxSuperPagesInPool> alloc_bitset_ PA_GUARDED_BY(lock_);
142 
143     // An index of a bit in the bitset before which we know for sure there all
144     // 1s. This is a best-effort hint in the sense that there still may be lots
145     // of 1s after this index, but at least we know there is no point in
146     // starting the search before it.
147     size_t bit_hint_ PA_GUARDED_BY(lock_) = 0;
148 
149     size_t total_bits_ = 0;
150     uintptr_t address_begin_ = 0;
151 #if BUILDFLAG(PA_DCHECK_IS_ON)
152     uintptr_t address_end_ = 0;
153 #endif
154   };
155 
156   PA_ALWAYS_INLINE Pool* GetPool(pool_handle handle) {
157     PA_DCHECK(kNullPoolHandle < handle && handle <= kNumPools);
158     return &aligned_pools_.pools_[handle - 1];
159   }
160 
161   // Gets the stats for the pool identified by `handle`, if
162   // initialized.
163   void GetPoolStats(pool_handle handle, PoolStats* stats);
164 
165   // If pkey support is enabled, we need to pkey-tag the pkey pool (which needs
166   // to be last). For this, we need to add padding in front of the pools so that
167   // pkey one starts on a page boundary.
168   struct {
169     char pad_[PA_PKEY_ARRAY_PAD_SZ(Pool, kNumPools)] = {};
170     Pool pools_[kNumPools];
171     char pad_after_[PA_PKEY_FILL_PAGE_SZ(sizeof(Pool))] = {};
172   } aligned_pools_ PA_PKEY_ALIGN;
173 
174 #endif  // BUILDFLAG(HAS_64_BIT_POINTERS)
175 
176   static PA_CONSTINIT AddressPoolManager singleton_;
177 };
178 
179 }  // namespace partition_alloc::internal
180 
181 #endif  // BASE_ALLOCATOR_PARTITION_ALLOCATOR_ADDRESS_POOL_MANAGER_H_
182