xref: /aosp_15_r20/external/libchrome/base/lazy_instance_helpers.h (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright 2018 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #ifndef BASE_LAZY_INSTANCE_INTERNAL_H_
6*635a8641SAndroid Build Coastguard Worker #define BASE_LAZY_INSTANCE_INTERNAL_H_
7*635a8641SAndroid Build Coastguard Worker 
8*635a8641SAndroid Build Coastguard Worker #include "base/atomicops.h"
9*635a8641SAndroid Build Coastguard Worker #include "base/base_export.h"
10*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
11*635a8641SAndroid Build Coastguard Worker 
12*635a8641SAndroid Build Coastguard Worker // Helper methods used by LazyInstance and a few other base APIs for thread-safe
13*635a8641SAndroid Build Coastguard Worker // lazy construction.
14*635a8641SAndroid Build Coastguard Worker 
15*635a8641SAndroid Build Coastguard Worker namespace base {
16*635a8641SAndroid Build Coastguard Worker namespace internal {
17*635a8641SAndroid Build Coastguard Worker 
18*635a8641SAndroid Build Coastguard Worker // Our AtomicWord doubles as a spinlock, where a value of
19*635a8641SAndroid Build Coastguard Worker // kLazyInstanceStateCreating means the spinlock is being held for creation.
20*635a8641SAndroid Build Coastguard Worker constexpr subtle::AtomicWord kLazyInstanceStateCreating = 1;
21*635a8641SAndroid Build Coastguard Worker 
22*635a8641SAndroid Build Coastguard Worker // Helper for GetOrCreateLazyPointer(). Checks if instance needs to be created.
23*635a8641SAndroid Build Coastguard Worker // If so returns true otherwise if another thread has beat us, waits for
24*635a8641SAndroid Build Coastguard Worker // instance to be created and returns false.
25*635a8641SAndroid Build Coastguard Worker BASE_EXPORT bool NeedsLazyInstance(subtle::AtomicWord* state);
26*635a8641SAndroid Build Coastguard Worker 
27*635a8641SAndroid Build Coastguard Worker // Helper for GetOrCreateLazyPointer(). After creating an instance, this is
28*635a8641SAndroid Build Coastguard Worker // called to register the dtor to be called at program exit and to update the
29*635a8641SAndroid Build Coastguard Worker // atomic state to hold the |new_instance|
30*635a8641SAndroid Build Coastguard Worker BASE_EXPORT void CompleteLazyInstance(subtle::AtomicWord* state,
31*635a8641SAndroid Build Coastguard Worker                                       subtle::AtomicWord new_instance,
32*635a8641SAndroid Build Coastguard Worker                                       void (*destructor)(void*),
33*635a8641SAndroid Build Coastguard Worker                                       void* destructor_arg);
34*635a8641SAndroid Build Coastguard Worker 
35*635a8641SAndroid Build Coastguard Worker }  // namespace internal
36*635a8641SAndroid Build Coastguard Worker 
37*635a8641SAndroid Build Coastguard Worker namespace subtle {
38*635a8641SAndroid Build Coastguard Worker 
39*635a8641SAndroid Build Coastguard Worker // If |state| is uninitialized (zero), constructs a value using
40*635a8641SAndroid Build Coastguard Worker // |creator_func(creator_arg)|, stores it into |state| and registers
41*635a8641SAndroid Build Coastguard Worker // |destructor(destructor_arg)| to be called when the current AtExitManager goes
42*635a8641SAndroid Build Coastguard Worker // out of scope. Then, returns the value stored in |state|. It is safe to have
43*635a8641SAndroid Build Coastguard Worker // concurrent calls to this function with the same |state|. |creator_func| may
44*635a8641SAndroid Build Coastguard Worker // return nullptr if it doesn't want to create an instance anymore (e.g. on
45*635a8641SAndroid Build Coastguard Worker // shutdown), it is from then on required to return nullptr to all callers (ref.
46*635a8641SAndroid Build Coastguard Worker // StaticMemorySingletonTraits). In that case, callers need to synchronize
47*635a8641SAndroid Build Coastguard Worker // before |creator_func| may return a non-null instance again (ref.
48*635a8641SAndroid Build Coastguard Worker // StaticMemorySingletonTraits::ResurectForTesting()).
49*635a8641SAndroid Build Coastguard Worker // Implementation note on |creator_func/creator_arg|. It makes for ugly adapters
50*635a8641SAndroid Build Coastguard Worker // but it avoids redundant template instantiations (e.g. saves 27KB in
51*635a8641SAndroid Build Coastguard Worker // chrome.dll) because linker is able to fold these for multiple Types but
52*635a8641SAndroid Build Coastguard Worker // couldn't with the more advanced CreatorFunc template type which in turn
53*635a8641SAndroid Build Coastguard Worker // improves code locality (and application startup) -- ref.
54*635a8641SAndroid Build Coastguard Worker // https://chromium-review.googlesource.com/c/chromium/src/+/530984/5/base/lazy_instance.h#140,
55*635a8641SAndroid Build Coastguard Worker // worsened by https://chromium-review.googlesource.com/c/chromium/src/+/868013
56*635a8641SAndroid Build Coastguard Worker // and caught then as https://crbug.com/804034.
57*635a8641SAndroid Build Coastguard Worker template <typename Type>
GetOrCreateLazyPointer(subtle::AtomicWord * state,Type * (* creator_func)(void *),void * creator_arg,void (* destructor)(void *),void * destructor_arg)58*635a8641SAndroid Build Coastguard Worker Type* GetOrCreateLazyPointer(subtle::AtomicWord* state,
59*635a8641SAndroid Build Coastguard Worker                              Type* (*creator_func)(void*),
60*635a8641SAndroid Build Coastguard Worker                              void* creator_arg,
61*635a8641SAndroid Build Coastguard Worker                              void (*destructor)(void*),
62*635a8641SAndroid Build Coastguard Worker                              void* destructor_arg) {
63*635a8641SAndroid Build Coastguard Worker   DCHECK(state);
64*635a8641SAndroid Build Coastguard Worker   DCHECK(creator_func);
65*635a8641SAndroid Build Coastguard Worker 
66*635a8641SAndroid Build Coastguard Worker   // If any bit in the created mask is true, the instance has already been
67*635a8641SAndroid Build Coastguard Worker   // fully constructed.
68*635a8641SAndroid Build Coastguard Worker   constexpr subtle::AtomicWord kLazyInstanceCreatedMask =
69*635a8641SAndroid Build Coastguard Worker       ~internal::kLazyInstanceStateCreating;
70*635a8641SAndroid Build Coastguard Worker 
71*635a8641SAndroid Build Coastguard Worker   // We will hopefully have fast access when the instance is already created.
72*635a8641SAndroid Build Coastguard Worker   // Since a thread sees |state| == 0 or kLazyInstanceStateCreating at most
73*635a8641SAndroid Build Coastguard Worker   // once, the load is taken out of NeedsLazyInstance() as a fast-path. The load
74*635a8641SAndroid Build Coastguard Worker   // has acquire memory ordering as a thread which sees |state| > creating needs
75*635a8641SAndroid Build Coastguard Worker   // to acquire visibility over the associated data. Pairing Release_Store is in
76*635a8641SAndroid Build Coastguard Worker   // CompleteLazyInstance().
77*635a8641SAndroid Build Coastguard Worker   subtle::AtomicWord instance = subtle::Acquire_Load(state);
78*635a8641SAndroid Build Coastguard Worker   if (!(instance & kLazyInstanceCreatedMask)) {
79*635a8641SAndroid Build Coastguard Worker     if (internal::NeedsLazyInstance(state)) {
80*635a8641SAndroid Build Coastguard Worker       // This thread won the race and is now responsible for creating the
81*635a8641SAndroid Build Coastguard Worker       // instance and storing it back into |state|.
82*635a8641SAndroid Build Coastguard Worker       instance =
83*635a8641SAndroid Build Coastguard Worker           reinterpret_cast<subtle::AtomicWord>((*creator_func)(creator_arg));
84*635a8641SAndroid Build Coastguard Worker       internal::CompleteLazyInstance(state, instance, destructor,
85*635a8641SAndroid Build Coastguard Worker                                      destructor_arg);
86*635a8641SAndroid Build Coastguard Worker     } else {
87*635a8641SAndroid Build Coastguard Worker       // This thread lost the race but now has visibility over the constructed
88*635a8641SAndroid Build Coastguard Worker       // instance (NeedsLazyInstance() doesn't return until the constructing
89*635a8641SAndroid Build Coastguard Worker       // thread releases the instance via CompleteLazyInstance()).
90*635a8641SAndroid Build Coastguard Worker       instance = subtle::Acquire_Load(state);
91*635a8641SAndroid Build Coastguard Worker       DCHECK(instance & kLazyInstanceCreatedMask);
92*635a8641SAndroid Build Coastguard Worker     }
93*635a8641SAndroid Build Coastguard Worker   }
94*635a8641SAndroid Build Coastguard Worker   return reinterpret_cast<Type*>(instance);
95*635a8641SAndroid Build Coastguard Worker }
96*635a8641SAndroid Build Coastguard Worker 
97*635a8641SAndroid Build Coastguard Worker }  // namespace subtle
98*635a8641SAndroid Build Coastguard Worker 
99*635a8641SAndroid Build Coastguard Worker }  // namespace base
100*635a8641SAndroid Build Coastguard Worker 
101*635a8641SAndroid Build Coastguard Worker #endif  // BASE_LAZY_INSTANCE_INTERNAL_H_
102