tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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_