1*6777b538SAndroid Build Coastguard Worker // Copyright 2022 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_ALLOCATOR_DISPATCHER_TLS_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_ALLOCATOR_DISPATCHER_TLS_H_
7*6777b538SAndroid Build Coastguard Worker
8*6777b538SAndroid Build Coastguard Worker #include <string_view>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
11*6777b538SAndroid Build Coastguard Worker
12*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_POSIX) // the current allocation mechanism (mmap) and TLS
13*6777b538SAndroid Build Coastguard Worker // support (pthread) are both defined by POSIX
14*6777b538SAndroid Build Coastguard Worker #define USE_LOCAL_TLS_EMULATION() true
15*6777b538SAndroid Build Coastguard Worker #else
16*6777b538SAndroid Build Coastguard Worker #define USE_LOCAL_TLS_EMULATION() false
17*6777b538SAndroid Build Coastguard Worker #endif
18*6777b538SAndroid Build Coastguard Worker
19*6777b538SAndroid Build Coastguard Worker #if USE_LOCAL_TLS_EMULATION()
20*6777b538SAndroid Build Coastguard Worker #include <algorithm>
21*6777b538SAndroid Build Coastguard Worker #include <atomic>
22*6777b538SAndroid Build Coastguard Worker #include <memory>
23*6777b538SAndroid Build Coastguard Worker #include <mutex>
24*6777b538SAndroid Build Coastguard Worker
25*6777b538SAndroid Build Coastguard Worker #include "base/base_export.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/check.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/compiler_specific.h"
28*6777b538SAndroid Build Coastguard Worker #include "partition_alloc/partition_alloc_constants.h"
29*6777b538SAndroid Build Coastguard Worker
30*6777b538SAndroid Build Coastguard Worker #include <pthread.h>
31*6777b538SAndroid Build Coastguard Worker
32*6777b538SAndroid Build Coastguard Worker #if HAS_FEATURE(thread_sanitizer)
33*6777b538SAndroid Build Coastguard Worker #define DISABLE_TSAN_INSTRUMENTATION __attribute__((no_sanitize("thread")))
34*6777b538SAndroid Build Coastguard Worker #else
35*6777b538SAndroid Build Coastguard Worker #define DISABLE_TSAN_INSTRUMENTATION
36*6777b538SAndroid Build Coastguard Worker #endif
37*6777b538SAndroid Build Coastguard Worker
38*6777b538SAndroid Build Coastguard Worker #define STR_HELPER(x) #x
39*6777b538SAndroid Build Coastguard Worker #define STR(x) STR_HELPER(x)
40*6777b538SAndroid Build Coastguard Worker
41*6777b538SAndroid Build Coastguard Worker // Verify that a condition holds and cancel the process in case it doesn't. The
42*6777b538SAndroid Build Coastguard Worker // functionality is similar to RAW_CHECK but includes more information in the
43*6777b538SAndroid Build Coastguard Worker // logged messages. It is non allocating to prevent recursions.
44*6777b538SAndroid Build Coastguard Worker #define TLS_RAW_CHECK(error_message, condition) \
45*6777b538SAndroid Build Coastguard Worker TLS_RAW_CHECK_IMPL(error_message, condition, __FILE__, __LINE__)
46*6777b538SAndroid Build Coastguard Worker
47*6777b538SAndroid Build Coastguard Worker #define TLS_RAW_CHECK_IMPL(error_message, condition, file, line) \
48*6777b538SAndroid Build Coastguard Worker do { \
49*6777b538SAndroid Build Coastguard Worker if (!(condition)) { \
50*6777b538SAndroid Build Coastguard Worker constexpr const char* message = \
51*6777b538SAndroid Build Coastguard Worker "TLS System: " error_message " Failed condition '" #condition \
52*6777b538SAndroid Build Coastguard Worker "' in (" file "@" STR(line) ").\n"; \
53*6777b538SAndroid Build Coastguard Worker ::logging::RawCheckFailure(message); \
54*6777b538SAndroid Build Coastguard Worker } \
55*6777b538SAndroid Build Coastguard Worker } while (0)
56*6777b538SAndroid Build Coastguard Worker
57*6777b538SAndroid Build Coastguard Worker namespace base::debug {
58*6777b538SAndroid Build Coastguard Worker struct CrashKeyString;
59*6777b538SAndroid Build Coastguard Worker }
60*6777b538SAndroid Build Coastguard Worker
61*6777b538SAndroid Build Coastguard Worker namespace base::allocator::dispatcher {
62*6777b538SAndroid Build Coastguard Worker namespace internal {
63*6777b538SAndroid Build Coastguard Worker
64*6777b538SAndroid Build Coastguard Worker // Allocate memory using POSIX' mmap and unmap functionality. The allocator
65*6777b538SAndroid Build Coastguard Worker // implements the allocator interface required by ThreadLocalStorage.
66*6777b538SAndroid Build Coastguard Worker struct BASE_EXPORT MMapAllocator {
67*6777b538SAndroid Build Coastguard Worker // The minimum size of a memory chunk when allocating. Even for chunks with
68*6777b538SAndroid Build Coastguard Worker // fewer bytes, at least AllocationChunkSize bytes are allocated. For mmap, this
69*6777b538SAndroid Build Coastguard Worker // is usually the page size of the system.
70*6777b538SAndroid Build Coastguard Worker // For various OS-CPU combinations, partition_alloc::PartitionPageSize() is not
71*6777b538SAndroid Build Coastguard Worker // constexpr. Hence, we can not use this value but define it locally.
72*6777b538SAndroid Build Coastguard Worker #if defined(PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR) && \
73*6777b538SAndroid Build Coastguard Worker PAGE_ALLOCATOR_CONSTANTS_ARE_CONSTEXPR
74*6777b538SAndroid Build Coastguard Worker constexpr static size_t AllocationChunkSize =
75*6777b538SAndroid Build Coastguard Worker partition_alloc::PartitionPageSize();
76*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_APPLE)
77*6777b538SAndroid Build Coastguard Worker constexpr static size_t AllocationChunkSize = 16384;
78*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_ANDROID) && defined(ARCH_CPU_64_BITS)
79*6777b538SAndroid Build Coastguard Worker constexpr static size_t AllocationChunkSize = 16384;
80*6777b538SAndroid Build Coastguard Worker #elif BUILDFLAG(IS_LINUX) && defined(ARCH_CPU_ARM64)
81*6777b538SAndroid Build Coastguard Worker constexpr static size_t AllocationChunkSize = 16384;
82*6777b538SAndroid Build Coastguard Worker #else
83*6777b538SAndroid Build Coastguard Worker constexpr static size_t AllocationChunkSize = 4096;
84*6777b538SAndroid Build Coastguard Worker #endif
85*6777b538SAndroid Build Coastguard Worker
86*6777b538SAndroid Build Coastguard Worker // Allocate size_in_bytes bytes of raw memory. Return nullptr if allocation
87*6777b538SAndroid Build Coastguard Worker // fails.
88*6777b538SAndroid Build Coastguard Worker void* AllocateMemory(size_t size_in_bytes);
89*6777b538SAndroid Build Coastguard Worker // Free the raw memory pointed to by pointer_to_allocated. Returns a boolean
90*6777b538SAndroid Build Coastguard Worker // value indicating if the free was successful.
91*6777b538SAndroid Build Coastguard Worker bool FreeMemoryForTesting(void* pointer_to_allocated, size_t size_in_bytes);
92*6777b538SAndroid Build Coastguard Worker };
93*6777b538SAndroid Build Coastguard Worker
94*6777b538SAndroid Build Coastguard Worker // The allocator used by default for the thread local storage.
95*6777b538SAndroid Build Coastguard Worker using DefaultAllocator = MMapAllocator;
96*6777b538SAndroid Build Coastguard Worker
97*6777b538SAndroid Build Coastguard Worker using OnThreadTerminationFunction = void (*)(void*);
98*6777b538SAndroid Build Coastguard Worker
99*6777b538SAndroid Build Coastguard Worker // The TLS system used by default for the thread local storage. It stores and
100*6777b538SAndroid Build Coastguard Worker // retrieves thread specific data pointers.
101*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT PThreadTLSSystem {
102*6777b538SAndroid Build Coastguard Worker public:
103*6777b538SAndroid Build Coastguard Worker PThreadTLSSystem();
104*6777b538SAndroid Build Coastguard Worker
105*6777b538SAndroid Build Coastguard Worker PThreadTLSSystem(const PThreadTLSSystem&) = delete;
106*6777b538SAndroid Build Coastguard Worker PThreadTLSSystem(PThreadTLSSystem&&);
107*6777b538SAndroid Build Coastguard Worker PThreadTLSSystem& operator=(const PThreadTLSSystem&) = delete;
108*6777b538SAndroid Build Coastguard Worker PThreadTLSSystem& operator=(PThreadTLSSystem&&);
109*6777b538SAndroid Build Coastguard Worker
110*6777b538SAndroid Build Coastguard Worker // Initialize the TLS system to store a data set for different threads.
111*6777b538SAndroid Build Coastguard Worker // @param thread_termination_function An optional function which will be
112*6777b538SAndroid Build Coastguard Worker // invoked upon termination of a thread.
113*6777b538SAndroid Build Coastguard Worker bool Setup(OnThreadTerminationFunction thread_termination_function,
114*6777b538SAndroid Build Coastguard Worker const std::string_view instance_id);
115*6777b538SAndroid Build Coastguard Worker // Tear down the TLS system. After completing tear down, the thread
116*6777b538SAndroid Build Coastguard Worker // termination function passed to Setup will not be invoked anymore.
117*6777b538SAndroid Build Coastguard Worker bool TearDownForTesting();
118*6777b538SAndroid Build Coastguard Worker
119*6777b538SAndroid Build Coastguard Worker // Get the pointer to the data associated to the current thread. Returns
120*6777b538SAndroid Build Coastguard Worker // nullptr if the TLS system is not initialized or no data was set before.
121*6777b538SAndroid Build Coastguard Worker void* GetThreadSpecificData();
122*6777b538SAndroid Build Coastguard Worker // Set the pointer to the data associated to the current thread. Return true
123*6777b538SAndroid Build Coastguard Worker // if stored successfully, false otherwise.
124*6777b538SAndroid Build Coastguard Worker bool SetThreadSpecificData(void* data);
125*6777b538SAndroid Build Coastguard Worker
126*6777b538SAndroid Build Coastguard Worker private:
127*6777b538SAndroid Build Coastguard Worker base::debug::CrashKeyString* crash_key_ = nullptr;
128*6777b538SAndroid Build Coastguard Worker pthread_key_t data_access_key_ = 0;
129*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
130*6777b538SAndroid Build Coastguard Worker // From POSIX standard at https://www.open-std.org/jtc1/sc22/open/n4217.pdf:
131*6777b538SAndroid Build Coastguard Worker // The effect of calling pthread_getspecific() or pthread_setspecific() with a
132*6777b538SAndroid Build Coastguard Worker // key value not obtained from pthread_key_create() or after key has been
133*6777b538SAndroid Build Coastguard Worker // deleted with pthread_key_delete() is undefined.
134*6777b538SAndroid Build Coastguard Worker //
135*6777b538SAndroid Build Coastguard Worker // Unfortunately, POSIX doesn't define a special value of pthread_key_t
136*6777b538SAndroid Build Coastguard Worker // indicating an invalid key which would allow us to detect accesses outside
137*6777b538SAndroid Build Coastguard Worker // of initialized state. Hence, to prevent us from drifting into the evil
138*6777b538SAndroid Build Coastguard Worker // realm of undefined behaviour we store whether we're somewhere between Setup
139*6777b538SAndroid Build Coastguard Worker // and Teardown.
140*6777b538SAndroid Build Coastguard Worker std::atomic_bool initialized_{false};
141*6777b538SAndroid Build Coastguard Worker #endif
142*6777b538SAndroid Build Coastguard Worker };
143*6777b538SAndroid Build Coastguard Worker
144*6777b538SAndroid Build Coastguard Worker using DefaultTLSSystem = PThreadTLSSystem;
145*6777b538SAndroid Build Coastguard Worker
146*6777b538SAndroid Build Coastguard Worker // In some scenarios, most notably when testing, the allocator and TLS system
147*6777b538SAndroid Build Coastguard Worker // passed to |ThreadLocalStorage| are not copyable and have to be wrapped, i.e.
148*6777b538SAndroid Build Coastguard Worker // using std::reference_wrapper. |dereference| is a small helper to retrieve the
149*6777b538SAndroid Build Coastguard Worker // underlying value.
150*6777b538SAndroid Build Coastguard Worker template <typename T>
dereference(T & ref)151*6777b538SAndroid Build Coastguard Worker T& dereference(T& ref) {
152*6777b538SAndroid Build Coastguard Worker return ref;
153*6777b538SAndroid Build Coastguard Worker }
154*6777b538SAndroid Build Coastguard Worker
155*6777b538SAndroid Build Coastguard Worker template <typename T>
dereference(std::reference_wrapper<T> & ref)156*6777b538SAndroid Build Coastguard Worker T& dereference(std::reference_wrapper<T>& ref) {
157*6777b538SAndroid Build Coastguard Worker // std::reference_wrapper requires a valid reference for construction,
158*6777b538SAndroid Build Coastguard Worker // therefore, no need in checking here.
159*6777b538SAndroid Build Coastguard Worker return ref.get();
160*6777b538SAndroid Build Coastguard Worker }
161*6777b538SAndroid Build Coastguard Worker
162*6777b538SAndroid Build Coastguard Worker // Store thread local data. The data is organized in chunks, where each chunk
163*6777b538SAndroid Build Coastguard Worker // holds |ItemsPerChunk|. Each item may be free or used.
164*6777b538SAndroid Build Coastguard Worker //
165*6777b538SAndroid Build Coastguard Worker // When a thread requests data, the chunks are searched for a free data item,
166*6777b538SAndroid Build Coastguard Worker // which is registered for this thread and marked as |used|. Further requests by
167*6777b538SAndroid Build Coastguard Worker // this thread will then always return the same item. When a thread terminates,
168*6777b538SAndroid Build Coastguard Worker // the item will be reset and return to the pool of free items.
169*6777b538SAndroid Build Coastguard Worker //
170*6777b538SAndroid Build Coastguard Worker // Upon construction, the first chunk is created. If a thread requests data and
171*6777b538SAndroid Build Coastguard Worker // there is no free item available, another chunk is created. Upon destruction,
172*6777b538SAndroid Build Coastguard Worker // all memory is freed. Pointers to data items become invalid!
173*6777b538SAndroid Build Coastguard Worker //
174*6777b538SAndroid Build Coastguard Worker // Constructor and destructor are not thread safe.
175*6777b538SAndroid Build Coastguard Worker //
176*6777b538SAndroid Build Coastguard Worker // @tparam PayloadType The item type to be stored.
177*6777b538SAndroid Build Coastguard Worker // @tparam AllocatorType The allocator being used. An allocator must provide
178*6777b538SAndroid Build Coastguard Worker // the following interface:
179*6777b538SAndroid Build Coastguard Worker // void* AllocateMemory(size_t size_in_bytes); // Allocate size_in_bytes bytes
180*6777b538SAndroid Build Coastguard Worker // of raw memory.
181*6777b538SAndroid Build Coastguard Worker // void FreeMemory(void* pointer_to_allocated, size_t size_in_bytes); // Free
182*6777b538SAndroid Build Coastguard Worker // the raw memory pointed to by pointer_to_allocated.
183*6777b538SAndroid Build Coastguard Worker // Any failure in allocation or free must terminate the process.
184*6777b538SAndroid Build Coastguard Worker // @tparam TLSSystemType The TLS system being used. A TLS system must provide
185*6777b538SAndroid Build Coastguard Worker // the following interface:
186*6777b538SAndroid Build Coastguard Worker // bool Setup(OnThreadTerminationFunction thread_termination_function);
187*6777b538SAndroid Build Coastguard Worker // bool Destroy();
188*6777b538SAndroid Build Coastguard Worker // void* GetThreadSpecificData();
189*6777b538SAndroid Build Coastguard Worker // bool SetThreadSpecificData(void* data);
190*6777b538SAndroid Build Coastguard Worker // @tparam AllocationChunkSize The minimum size of a memory chunk that the
191*6777b538SAndroid Build Coastguard Worker // allocator can handle. We try to size the chunks so that each chunk uses this
192*6777b538SAndroid Build Coastguard Worker // size to the maximum.
193*6777b538SAndroid Build Coastguard Worker // @tparam IsDestructibleForTesting For testing purposes we allow the destructor
194*6777b538SAndroid Build Coastguard Worker // to perform clean up upon destruction. Otherwise, using the destructor will
195*6777b538SAndroid Build Coastguard Worker // result in a compilation failure.
196*6777b538SAndroid Build Coastguard Worker template <typename PayloadType,
197*6777b538SAndroid Build Coastguard Worker typename AllocatorType,
198*6777b538SAndroid Build Coastguard Worker typename TLSSystemType,
199*6777b538SAndroid Build Coastguard Worker size_t AllocationChunkSize,
200*6777b538SAndroid Build Coastguard Worker bool IsDestructibleForTesting>
201*6777b538SAndroid Build Coastguard Worker struct ThreadLocalStorage {
ThreadLocalStorageThreadLocalStorage202*6777b538SAndroid Build Coastguard Worker explicit ThreadLocalStorage(const std::string_view instance_id)
203*6777b538SAndroid Build Coastguard Worker : root_(AllocateAndInitializeChunk()) {
204*6777b538SAndroid Build Coastguard Worker Initialize(instance_id);
205*6777b538SAndroid Build Coastguard Worker }
206*6777b538SAndroid Build Coastguard Worker
207*6777b538SAndroid Build Coastguard Worker // Create a new instance of |ThreadLocalStorage| using the passed allocator
208*6777b538SAndroid Build Coastguard Worker // and TLS system. This initializes the underlying TLS system and creates the
209*6777b538SAndroid Build Coastguard Worker // first chunk of data.
ThreadLocalStorageThreadLocalStorage210*6777b538SAndroid Build Coastguard Worker ThreadLocalStorage(const std::string_view instance_id,
211*6777b538SAndroid Build Coastguard Worker AllocatorType allocator,
212*6777b538SAndroid Build Coastguard Worker TLSSystemType tls_system)
213*6777b538SAndroid Build Coastguard Worker : allocator_(std::move(allocator)),
214*6777b538SAndroid Build Coastguard Worker tls_system_(std::move(tls_system)),
215*6777b538SAndroid Build Coastguard Worker root_(AllocateAndInitializeChunk()) {
216*6777b538SAndroid Build Coastguard Worker Initialize(instance_id);
217*6777b538SAndroid Build Coastguard Worker }
218*6777b538SAndroid Build Coastguard Worker
219*6777b538SAndroid Build Coastguard Worker // Deletes an instance of |ThreadLocalStorage| and delete all the data chunks
220*6777b538SAndroid Build Coastguard Worker // created.
~ThreadLocalStorageThreadLocalStorage221*6777b538SAndroid Build Coastguard Worker ~ThreadLocalStorage() {
222*6777b538SAndroid Build Coastguard Worker if constexpr (IsDestructibleForTesting) {
223*6777b538SAndroid Build Coastguard Worker TearDownForTesting();
224*6777b538SAndroid Build Coastguard Worker } else if constexpr (!IsDestructibleForTesting) {
225*6777b538SAndroid Build Coastguard Worker static_assert(
226*6777b538SAndroid Build Coastguard Worker IsDestructibleForTesting,
227*6777b538SAndroid Build Coastguard Worker "ThreadLocalStorage cannot be destructed outside of test code.");
228*6777b538SAndroid Build Coastguard Worker }
229*6777b538SAndroid Build Coastguard Worker }
230*6777b538SAndroid Build Coastguard Worker
231*6777b538SAndroid Build Coastguard Worker // Explicitly prevent all forms of Copy/Move construction/assignment. For an
232*6777b538SAndroid Build Coastguard Worker // exact copy of ThreadLocalStorage we would need to copy the mapping of
233*6777b538SAndroid Build Coastguard Worker // thread to item, which we can't do at the moment. On the other side, our
234*6777b538SAndroid Build Coastguard Worker // atomic members do not support moving out of the box.
235*6777b538SAndroid Build Coastguard Worker ThreadLocalStorage(const ThreadLocalStorage&) = delete;
236*6777b538SAndroid Build Coastguard Worker ThreadLocalStorage(ThreadLocalStorage&& other) = delete;
237*6777b538SAndroid Build Coastguard Worker ThreadLocalStorage& operator=(const ThreadLocalStorage&) = delete;
238*6777b538SAndroid Build Coastguard Worker ThreadLocalStorage& operator=(ThreadLocalStorage&&) = delete;
239*6777b538SAndroid Build Coastguard Worker
240*6777b538SAndroid Build Coastguard Worker // Get the data item for the current thread. If no data is registered so far,
241*6777b538SAndroid Build Coastguard Worker // find a free item in the chunks and register it for the current thread.
GetThreadLocalDataThreadLocalStorage242*6777b538SAndroid Build Coastguard Worker PayloadType* GetThreadLocalData() {
243*6777b538SAndroid Build Coastguard Worker auto& tls_system = dereference(tls_system_);
244*6777b538SAndroid Build Coastguard Worker
245*6777b538SAndroid Build Coastguard Worker auto* slot = static_cast<SingleSlot*>(tls_system.GetThreadSpecificData());
246*6777b538SAndroid Build Coastguard Worker
247*6777b538SAndroid Build Coastguard Worker if (UNLIKELY(slot == nullptr)) {
248*6777b538SAndroid Build Coastguard Worker slot = FindAndAllocateFreeSlot(root_.load(std::memory_order_relaxed));
249*6777b538SAndroid Build Coastguard Worker
250*6777b538SAndroid Build Coastguard Worker // We might be called in the course of handling a memory allocation. We do
251*6777b538SAndroid Build Coastguard Worker // not use CHECK since they might allocate and cause a recursion.
252*6777b538SAndroid Build Coastguard Worker TLS_RAW_CHECK("Failed to set thread specific data.",
253*6777b538SAndroid Build Coastguard Worker tls_system.SetThreadSpecificData(slot));
254*6777b538SAndroid Build Coastguard Worker
255*6777b538SAndroid Build Coastguard Worker // Reset the content to wipe out any previous data.
256*6777b538SAndroid Build Coastguard Worker Reset(slot->item);
257*6777b538SAndroid Build Coastguard Worker }
258*6777b538SAndroid Build Coastguard Worker
259*6777b538SAndroid Build Coastguard Worker return &(slot->item);
260*6777b538SAndroid Build Coastguard Worker }
261*6777b538SAndroid Build Coastguard Worker
262*6777b538SAndroid Build Coastguard Worker private:
263*6777b538SAndroid Build Coastguard Worker // Encapsulate the payload item and some administrative data.
264*6777b538SAndroid Build Coastguard Worker struct SingleSlot {
265*6777b538SAndroid Build Coastguard Worker PayloadType item;
266*6777b538SAndroid Build Coastguard Worker #if !defined(__cpp_lib_atomic_value_initialization) || \
267*6777b538SAndroid Build Coastguard Worker __cpp_lib_atomic_value_initialization < 201911L
268*6777b538SAndroid Build Coastguard Worker std::atomic_flag is_used = ATOMIC_FLAG_INIT;
269*6777b538SAndroid Build Coastguard Worker #else
270*6777b538SAndroid Build Coastguard Worker std::atomic_flag is_used;
271*6777b538SAndroid Build Coastguard Worker #endif
272*6777b538SAndroid Build Coastguard Worker };
273*6777b538SAndroid Build Coastguard Worker
274*6777b538SAndroid Build Coastguard Worker template <size_t NumberOfItems>
275*6777b538SAndroid Build Coastguard Worker struct ChunkT {
276*6777b538SAndroid Build Coastguard Worker SingleSlot slots[NumberOfItems];
277*6777b538SAndroid Build Coastguard Worker // Pointer to the next chunk.
278*6777b538SAndroid Build Coastguard Worker std::atomic<ChunkT*> next_chunk = nullptr;
279*6777b538SAndroid Build Coastguard Worker // Helper flag to ensure we create the next chunk only once in a multi
280*6777b538SAndroid Build Coastguard Worker // threaded environment.
281*6777b538SAndroid Build Coastguard Worker std::once_flag create_next_chunk_flag;
282*6777b538SAndroid Build Coastguard Worker };
283*6777b538SAndroid Build Coastguard Worker
284*6777b538SAndroid Build Coastguard Worker template <size_t LowerNumberOfItems,
285*6777b538SAndroid Build Coastguard Worker size_t UpperNumberOfItems,
286*6777b538SAndroid Build Coastguard Worker size_t NumberOfBytes>
CalculateEffectiveNumberOfItemsBinSearchThreadLocalStorage287*6777b538SAndroid Build Coastguard Worker static constexpr size_t CalculateEffectiveNumberOfItemsBinSearch() {
288*6777b538SAndroid Build Coastguard Worker if constexpr (LowerNumberOfItems == UpperNumberOfItems) {
289*6777b538SAndroid Build Coastguard Worker return LowerNumberOfItems;
290*6777b538SAndroid Build Coastguard Worker }
291*6777b538SAndroid Build Coastguard Worker
292*6777b538SAndroid Build Coastguard Worker constexpr size_t CurrentNumberOfItems =
293*6777b538SAndroid Build Coastguard Worker (UpperNumberOfItems - LowerNumberOfItems) / 2 + LowerNumberOfItems;
294*6777b538SAndroid Build Coastguard Worker
295*6777b538SAndroid Build Coastguard Worker if constexpr (sizeof(ChunkT<CurrentNumberOfItems>) > NumberOfBytes) {
296*6777b538SAndroid Build Coastguard Worker return CalculateEffectiveNumberOfItemsBinSearch<
297*6777b538SAndroid Build Coastguard Worker LowerNumberOfItems, CurrentNumberOfItems, NumberOfBytes>();
298*6777b538SAndroid Build Coastguard Worker }
299*6777b538SAndroid Build Coastguard Worker
300*6777b538SAndroid Build Coastguard Worker if constexpr (sizeof(ChunkT<CurrentNumberOfItems + 1>) < NumberOfBytes) {
301*6777b538SAndroid Build Coastguard Worker return CalculateEffectiveNumberOfItemsBinSearch<
302*6777b538SAndroid Build Coastguard Worker CurrentNumberOfItems + 1, UpperNumberOfItems, NumberOfBytes>();
303*6777b538SAndroid Build Coastguard Worker }
304*6777b538SAndroid Build Coastguard Worker
305*6777b538SAndroid Build Coastguard Worker return CurrentNumberOfItems;
306*6777b538SAndroid Build Coastguard Worker }
307*6777b538SAndroid Build Coastguard Worker
308*6777b538SAndroid Build Coastguard Worker // Calculate the maximum number of items we can store in one chunk without the
309*6777b538SAndroid Build Coastguard Worker // size of the chunk exceeding NumberOfBytes. To avoid things like alignment
310*6777b538SAndroid Build Coastguard Worker // and packing tampering with the calculation, instead of calculating the
311*6777b538SAndroid Build Coastguard Worker // correct number of items we use sizeof-operator against ChunkT to search for
312*6777b538SAndroid Build Coastguard Worker // the correct size. Unfortunately, the number of recursions is limited by the
313*6777b538SAndroid Build Coastguard Worker // compiler. Therefore, we use a binary search instead of a simple linear
314*6777b538SAndroid Build Coastguard Worker // search.
315*6777b538SAndroid Build Coastguard Worker template <size_t MinimumNumberOfItems, size_t NumberOfBytes>
CalculateEffectiveNumberOfItemsThreadLocalStorage316*6777b538SAndroid Build Coastguard Worker static constexpr size_t CalculateEffectiveNumberOfItems() {
317*6777b538SAndroid Build Coastguard Worker if constexpr (sizeof(ChunkT<MinimumNumberOfItems>) < NumberOfBytes) {
318*6777b538SAndroid Build Coastguard Worker constexpr size_t LowerNumberOfItems = MinimumNumberOfItems;
319*6777b538SAndroid Build Coastguard Worker constexpr size_t UpperNumberOfItems =
320*6777b538SAndroid Build Coastguard Worker NumberOfBytes / sizeof(PayloadType) + 1;
321*6777b538SAndroid Build Coastguard Worker return CalculateEffectiveNumberOfItemsBinSearch<
322*6777b538SAndroid Build Coastguard Worker LowerNumberOfItems, UpperNumberOfItems, NumberOfBytes>();
323*6777b538SAndroid Build Coastguard Worker }
324*6777b538SAndroid Build Coastguard Worker
325*6777b538SAndroid Build Coastguard Worker return MinimumNumberOfItems;
326*6777b538SAndroid Build Coastguard Worker }
327*6777b538SAndroid Build Coastguard Worker
328*6777b538SAndroid Build Coastguard Worker public:
329*6777b538SAndroid Build Coastguard Worker // The minimum number of items per chunk. It should be high enough to
330*6777b538SAndroid Build Coastguard Worker // accommodate most items in the root chunk whilst not wasting to much space
331*6777b538SAndroid Build Coastguard Worker // on unnecessary items.
332*6777b538SAndroid Build Coastguard Worker static constexpr size_t MinimumNumberOfItemsPerChunk = 75;
333*6777b538SAndroid Build Coastguard Worker // The effective number of items per chunk. We use the AllocationChunkSize as
334*6777b538SAndroid Build Coastguard Worker // a hint to calculate to effective number of items so we occupy one of these
335*6777b538SAndroid Build Coastguard Worker // memory chunks to the maximum extent possible.
336*6777b538SAndroid Build Coastguard Worker static constexpr size_t ItemsPerChunk =
337*6777b538SAndroid Build Coastguard Worker CalculateEffectiveNumberOfItems<MinimumNumberOfItemsPerChunk,
338*6777b538SAndroid Build Coastguard Worker AllocationChunkSize>();
339*6777b538SAndroid Build Coastguard Worker
340*6777b538SAndroid Build Coastguard Worker private:
341*6777b538SAndroid Build Coastguard Worker using Chunk = ChunkT<ItemsPerChunk>;
342*6777b538SAndroid Build Coastguard Worker
343*6777b538SAndroid Build Coastguard Worker static_assert(ItemsPerChunk >= MinimumNumberOfItemsPerChunk);
344*6777b538SAndroid Build Coastguard Worker
345*6777b538SAndroid Build Coastguard Worker // Mark an item's slot ready for reuse. This function is used as thread
346*6777b538SAndroid Build Coastguard Worker // termination function in the TLS system. We do not destroy anything at this
347*6777b538SAndroid Build Coastguard Worker // point but simply mark the slot as unused.
MarkSlotAsFreeThreadLocalStorage348*6777b538SAndroid Build Coastguard Worker static void MarkSlotAsFree(void* data) {
349*6777b538SAndroid Build Coastguard Worker // We always store SingleSlots in the TLS system. Therefore, we cast to
350*6777b538SAndroid Build Coastguard Worker // SingleSlot and reset the is_used flag.
351*6777b538SAndroid Build Coastguard Worker auto* const slot = static_cast<SingleSlot*>(data);
352*6777b538SAndroid Build Coastguard Worker
353*6777b538SAndroid Build Coastguard Worker // We might be called in the course of handling a memory allocation.
354*6777b538SAndroid Build Coastguard Worker // Therefore, do not use CHECK since it might allocate and cause a
355*6777b538SAndroid Build Coastguard Worker // recursion.
356*6777b538SAndroid Build Coastguard Worker TLS_RAW_CHECK("Received an invalid slot.",
357*6777b538SAndroid Build Coastguard Worker slot && slot->is_used.test_and_set());
358*6777b538SAndroid Build Coastguard Worker
359*6777b538SAndroid Build Coastguard Worker slot->is_used.clear(std::memory_order_relaxed);
360*6777b538SAndroid Build Coastguard Worker }
361*6777b538SAndroid Build Coastguard Worker
362*6777b538SAndroid Build Coastguard Worker // Perform common initialization during construction of an instance.
InitializeThreadLocalStorage363*6777b538SAndroid Build Coastguard Worker void Initialize(const std::string_view instance_id) {
364*6777b538SAndroid Build Coastguard Worker // The constructor must be called outside of the allocation path. Therefore,
365*6777b538SAndroid Build Coastguard Worker // it is secure to verify with CHECK.
366*6777b538SAndroid Build Coastguard Worker
367*6777b538SAndroid Build Coastguard Worker // Passing MarkSlotAsFree as thread_termination_function we ensure the
368*6777b538SAndroid Build Coastguard Worker // slot/item assigned to the finished thread will be returned to the pool of
369*6777b538SAndroid Build Coastguard Worker // unused items.
370*6777b538SAndroid Build Coastguard Worker CHECK(dereference(tls_system_).Setup(&MarkSlotAsFree, instance_id));
371*6777b538SAndroid Build Coastguard Worker }
372*6777b538SAndroid Build Coastguard Worker
AllocateAndInitializeChunkThreadLocalStorage373*6777b538SAndroid Build Coastguard Worker Chunk* AllocateAndInitializeChunk() {
374*6777b538SAndroid Build Coastguard Worker void* const uninitialized_memory =
375*6777b538SAndroid Build Coastguard Worker dereference(allocator_).AllocateMemory(sizeof(Chunk));
376*6777b538SAndroid Build Coastguard Worker
377*6777b538SAndroid Build Coastguard Worker // We might be called in the course of handling a memory allocation. We do
378*6777b538SAndroid Build Coastguard Worker // not use CHECK since they might allocate and cause a recursion.
379*6777b538SAndroid Build Coastguard Worker TLS_RAW_CHECK("Failed to allocate memory for new chunk.",
380*6777b538SAndroid Build Coastguard Worker uninitialized_memory != nullptr);
381*6777b538SAndroid Build Coastguard Worker
382*6777b538SAndroid Build Coastguard Worker return new (uninitialized_memory) Chunk{};
383*6777b538SAndroid Build Coastguard Worker }
384*6777b538SAndroid Build Coastguard Worker
FreeAndDeallocateChunkForTestingThreadLocalStorage385*6777b538SAndroid Build Coastguard Worker void FreeAndDeallocateChunkForTesting(Chunk* chunk_to_erase) {
386*6777b538SAndroid Build Coastguard Worker chunk_to_erase->~Chunk();
387*6777b538SAndroid Build Coastguard Worker
388*6777b538SAndroid Build Coastguard Worker // FreeAndDeallocateChunkForTesting must be called outside of the allocation
389*6777b538SAndroid Build Coastguard Worker // path. Therefore, it is secure to verify with CHECK.
390*6777b538SAndroid Build Coastguard Worker CHECK(dereference(allocator_)
391*6777b538SAndroid Build Coastguard Worker .FreeMemoryForTesting(chunk_to_erase, sizeof(Chunk)));
392*6777b538SAndroid Build Coastguard Worker }
393*6777b538SAndroid Build Coastguard Worker
394*6777b538SAndroid Build Coastguard Worker // Find a free slot in the passed chunk, reserve it and return it to the
395*6777b538SAndroid Build Coastguard Worker // caller. If no free slot can be found, head on to the next chunk. If the
396*6777b538SAndroid Build Coastguard Worker // next chunk doesn't exist, create it.
FindAndAllocateFreeSlotThreadLocalStorage397*6777b538SAndroid Build Coastguard Worker SingleSlot* FindAndAllocateFreeSlot(Chunk* const chunk) {
398*6777b538SAndroid Build Coastguard Worker SingleSlot* const slot = std::find_if_not(
399*6777b538SAndroid Build Coastguard Worker std::begin(chunk->slots), std::end(chunk->slots),
400*6777b538SAndroid Build Coastguard Worker [](SingleSlot& candidate_slot) {
401*6777b538SAndroid Build Coastguard Worker return candidate_slot.is_used.test_and_set(std::memory_order_relaxed);
402*6777b538SAndroid Build Coastguard Worker });
403*6777b538SAndroid Build Coastguard Worker
404*6777b538SAndroid Build Coastguard Worker // So we found a slot. Happily return it to the caller.
405*6777b538SAndroid Build Coastguard Worker if (slot != std::end(chunk->slots)) {
406*6777b538SAndroid Build Coastguard Worker return slot;
407*6777b538SAndroid Build Coastguard Worker }
408*6777b538SAndroid Build Coastguard Worker
409*6777b538SAndroid Build Coastguard Worker // Ok, there are no more free slots in this chunk. First, ensure the next
410*6777b538SAndroid Build Coastguard Worker // chunk is valid and create one if necessary.
411*6777b538SAndroid Build Coastguard Worker std::call_once(chunk->create_next_chunk_flag, [&] {
412*6777b538SAndroid Build Coastguard Worker // From https://eel.is/c++draft/thread.once.callonce#3
413*6777b538SAndroid Build Coastguard Worker //
414*6777b538SAndroid Build Coastguard Worker // Synchronization: For any given once_flag: all active executions occur
415*6777b538SAndroid Build Coastguard Worker // in a total order; completion of an active execution synchronizes with
416*6777b538SAndroid Build Coastguard Worker // the start of the next one in this total order; and the returning
417*6777b538SAndroid Build Coastguard Worker // execution synchronizes with the return from all passive executions.
418*6777b538SAndroid Build Coastguard Worker //
419*6777b538SAndroid Build Coastguard Worker // Therefore, we do only a relaxed store here, call_once synchronizes with
420*6777b538SAndroid Build Coastguard Worker // other threads.
421*6777b538SAndroid Build Coastguard Worker chunk->next_chunk.store(AllocateAndInitializeChunk(),
422*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
423*6777b538SAndroid Build Coastguard Worker });
424*6777b538SAndroid Build Coastguard Worker
425*6777b538SAndroid Build Coastguard Worker return FindAndAllocateFreeSlot(chunk->next_chunk);
426*6777b538SAndroid Build Coastguard Worker }
427*6777b538SAndroid Build Coastguard Worker
428*6777b538SAndroid Build Coastguard Worker template <bool IsDestructibleForTestingP = IsDestructibleForTesting>
429*6777b538SAndroid Build Coastguard Worker typename std::enable_if<IsDestructibleForTestingP>::type
TearDownForTestingThreadLocalStorage430*6777b538SAndroid Build Coastguard Worker TearDownForTesting() {
431*6777b538SAndroid Build Coastguard Worker // The destructor must be called outside of the allocation path. Therefore,
432*6777b538SAndroid Build Coastguard Worker // it is secure to verify with CHECK.
433*6777b538SAndroid Build Coastguard Worker
434*6777b538SAndroid Build Coastguard Worker // All accessing threads must be terminated by now. For additional security
435*6777b538SAndroid Build Coastguard Worker // we tear down the TLS system first. This way we ensure that
436*6777b538SAndroid Build Coastguard Worker // MarkSlotAsFree is not called anymore and we have no accesses from the
437*6777b538SAndroid Build Coastguard Worker // TLS system's side.
438*6777b538SAndroid Build Coastguard Worker CHECK(dereference(tls_system_).TearDownForTesting());
439*6777b538SAndroid Build Coastguard Worker
440*6777b538SAndroid Build Coastguard Worker // Delete all data chunks.
441*6777b538SAndroid Build Coastguard Worker for (auto* chunk = root_.load(); chunk != nullptr;) {
442*6777b538SAndroid Build Coastguard Worker auto* next_chunk = chunk->next_chunk.load();
443*6777b538SAndroid Build Coastguard Worker FreeAndDeallocateChunkForTesting(chunk);
444*6777b538SAndroid Build Coastguard Worker chunk = next_chunk;
445*6777b538SAndroid Build Coastguard Worker }
446*6777b538SAndroid Build Coastguard Worker }
447*6777b538SAndroid Build Coastguard Worker
448*6777b538SAndroid Build Coastguard Worker // Reset a single item to its default value.
449*6777b538SAndroid Build Coastguard Worker // Since items are re-used, they may be accessed from different threads,
450*6777b538SAndroid Build Coastguard Worker // causing TSan to trigger. Therefore, the reset is exempt from TSan
451*6777b538SAndroid Build Coastguard Worker // instrumentation.
ResetThreadLocalStorage452*6777b538SAndroid Build Coastguard Worker DISABLE_TSAN_INSTRUMENTATION void Reset(PayloadType& item) { item = {}; }
453*6777b538SAndroid Build Coastguard Worker
454*6777b538SAndroid Build Coastguard Worker AllocatorType allocator_;
455*6777b538SAndroid Build Coastguard Worker TLSSystemType tls_system_;
456*6777b538SAndroid Build Coastguard Worker std::atomic<Chunk*> const root_;
457*6777b538SAndroid Build Coastguard Worker };
458*6777b538SAndroid Build Coastguard Worker
459*6777b538SAndroid Build Coastguard Worker } // namespace internal
460*6777b538SAndroid Build Coastguard Worker
461*6777b538SAndroid Build Coastguard Worker // The ThreadLocalStorage visible to the user. This uses the internal default
462*6777b538SAndroid Build Coastguard Worker // allocator and TLS system.
463*6777b538SAndroid Build Coastguard Worker template <typename StorageType,
464*6777b538SAndroid Build Coastguard Worker typename AllocatorType = internal::DefaultAllocator,
465*6777b538SAndroid Build Coastguard Worker typename TLSSystemType = internal::DefaultTLSSystem,
466*6777b538SAndroid Build Coastguard Worker size_t AllocationChunkSize = AllocatorType::AllocationChunkSize,
467*6777b538SAndroid Build Coastguard Worker bool IsDestructibleForTesting = false>
468*6777b538SAndroid Build Coastguard Worker using ThreadLocalStorage =
469*6777b538SAndroid Build Coastguard Worker internal::ThreadLocalStorage<StorageType,
470*6777b538SAndroid Build Coastguard Worker AllocatorType,
471*6777b538SAndroid Build Coastguard Worker TLSSystemType,
472*6777b538SAndroid Build Coastguard Worker AllocationChunkSize,
473*6777b538SAndroid Build Coastguard Worker IsDestructibleForTesting>;
474*6777b538SAndroid Build Coastguard Worker
475*6777b538SAndroid Build Coastguard Worker } // namespace base::allocator::dispatcher
476*6777b538SAndroid Build Coastguard Worker
477*6777b538SAndroid Build Coastguard Worker #undef TLS_RAW_CHECK_IMPL
478*6777b538SAndroid Build Coastguard Worker #undef TLS_RAW_CHECK
479*6777b538SAndroid Build Coastguard Worker #undef STR
480*6777b538SAndroid Build Coastguard Worker #undef STR_HELPER
481*6777b538SAndroid Build Coastguard Worker
482*6777b538SAndroid Build Coastguard Worker #endif // USE_LOCAL_TLS_EMULATION()
483*6777b538SAndroid Build Coastguard Worker #endif // BASE_ALLOCATOR_DISPATCHER_TLS_H_
484