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