blob: 99b5e055027522ba75cfa800285a1e74c1759b06 [file] [log] [blame]
Gabriel Charettef297f012018-01-17 20:59:071// Copyright 2018 The Chromium Authors. All rights reserved.
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_INTERNAL_H_
6#define BASE_LAZY_INSTANCE_INTERNAL_H_
7
8#include "base/atomicops.h"
9#include "base/base_export.h"
Hans Wennborg7b533712020-06-22 20:52:2710#include "base/check.h"
Gabriel Charettef297f012018-01-17 20:59:0711
12// Helper methods used by LazyInstance and a few other base APIs for thread-safe
13// lazy construction.
14
15namespace base {
16namespace internal {
17
18// Our AtomicWord doubles as a spinlock, where a value of
19// kLazyInstanceStateCreating means the spinlock is being held for creation.
20constexpr subtle::AtomicWord kLazyInstanceStateCreating = 1;
21
22// Helper for GetOrCreateLazyPointer(). Checks if instance needs to be created.
23// If so returns true otherwise if another thread has beat us, waits for
24// instance to be created and returns false.
25BASE_EXPORT bool NeedsLazyInstance(subtle::AtomicWord* state);
26
27// Helper for GetOrCreateLazyPointer(). After creating an instance, this is
28// called to register the dtor to be called at program exit and to update the
29// atomic state to hold the |new_instance|
30BASE_EXPORT void CompleteLazyInstance(subtle::AtomicWord* state,
31 subtle::AtomicWord new_instance,
32 void (*destructor)(void*),
33 void* destructor_arg);
34
Gabriel Charetted55aad502018-01-26 18:07:5135} // namespace internal
36
37namespace subtle {
38
39// If |state| is uninitialized (zero), constructs a value using
40// |creator_func(creator_arg)|, stores it into |state| and registers
41// |destructor(destructor_arg)| to be called when the current AtExitManager goes
42// out of scope. Then, returns the value stored in |state|. It is safe to have
Gabriel Charettef297f012018-01-17 20:59:0743// concurrent calls to this function with the same |state|. |creator_func| may
44// return nullptr if it doesn't want to create an instance anymore (e.g. on
45// shutdown), it is from then on required to return nullptr to all callers (ref.
Gabriel Charetted55aad502018-01-26 18:07:5146// StaticMemorySingletonTraits). In that case, callers need to synchronize
47// before |creator_func| may return a non-null instance again (ref.
Gabriel Charettef297f012018-01-17 20:59:0748// StaticMemorySingletonTraits::ResurectForTesting()).
Gabriel Charetted55aad502018-01-26 18:07:5149// Implementation note on |creator_func/creator_arg|. It makes for ugly adapters
50// but it avoids redundant template instantiations (e.g. saves 27KB in
51// chrome.dll) because linker is able to fold these for multiple Types but
52// couldn't with the more advanced CreatorFunc template type which in turn
53// improves code locality (and application startup) -- ref.
54// https://chromium-review.googlesource.com/c/chromium/src/+/530984/5/base/lazy_instance.h#140,
55// worsened by https://chromium-review.googlesource.com/c/chromium/src/+/868013
56// and caught then as https://crbug.com/804034.
57template <typename Type>
58Type* GetOrCreateLazyPointer(subtle::AtomicWord* state,
59 Type* (*creator_func)(void*),
60 void* creator_arg,
Gabriel Charettef297f012018-01-17 20:59:0761 void (*destructor)(void*),
62 void* destructor_arg) {
63 DCHECK(state);
Gabriel Charetted55aad502018-01-26 18:07:5164 DCHECK(creator_func);
Gabriel Charettef297f012018-01-17 20:59:0765
66 // If any bit in the created mask is true, the instance has already been
67 // fully constructed.
68 constexpr subtle::AtomicWord 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().
Gabriel Charetted55aad502018-01-26 18:07:5177 subtle::AtomicWord instance = subtle::Acquire_Load(state);
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 =
83 reinterpret_cast<subtle::AtomicWord>((*creator_func)(creator_arg));
84 internal::CompleteLazyInstance(state, instance, destructor,
85 destructor_arg);
86 } else {
87 // This thread lost the race but now has visibility over the constructed
88 // instance (NeedsLazyInstance() doesn't return until the constructing
89 // thread releases the instance via CompleteLazyInstance()).
90 instance = subtle::Acquire_Load(state);
91 DCHECK(instance & kLazyInstanceCreatedMask);
92 }
Gabriel Charettef297f012018-01-17 20:59:0793 }
Gabriel Charetted55aad502018-01-26 18:07:5194 return reinterpret_cast<Type*>(instance);
Gabriel Charettef297f012018-01-17 20:59:0795}
96
Gabriel Charetted55aad502018-01-26 18:07:5197} // namespace subtle
98
Gabriel Charettef297f012018-01-17 20:59:0799} // namespace base
100
101#endif // BASE_LAZY_INSTANCE_INTERNAL_H_