Coverage Report

Created: 2025-11-24 06:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/brpc/src/butil/lazy_instance.h
Line
Count
Source
1
// Copyright (c) 2012 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
// The LazyInstance<Type, Traits> class manages a single instance of Type,
6
// which will be lazily created on the first time it's accessed.  This class is
7
// useful for places you would normally use a function-level static, but you
8
// need to have guaranteed thread-safety.  The Type constructor will only ever
9
// be called once, even if two threads are racing to create the object.  Get()
10
// and Pointer() will always return the same, completely initialized instance.
11
// When the instance is constructed it is registered with AtExitManager.  The
12
// destructor will be called on program exit.
13
//
14
// LazyInstance is completely thread safe, assuming that you create it safely.
15
// The class was designed to be POD initialized, so it shouldn't require a
16
// static constructor.  It really only makes sense to declare a LazyInstance as
17
// a global variable using the LAZY_INSTANCE_INITIALIZER initializer.
18
//
19
// LazyInstance is similar to Singleton, except it does not have the singleton
20
// property.  You can have multiple LazyInstance's of the same type, and each
21
// will manage a unique instance.  It also preallocates the space for Type, as
22
// to avoid allocating the Type instance on the heap.  This may help with the
23
// performance of creating the instance, and reducing heap fragmentation.  This
24
// requires that Type be a complete type so we can determine the size.
25
//
26
// Example usage:
27
//   static LazyInstance<MyClass> my_instance = LAZY_INSTANCE_INITIALIZER;
28
//   void SomeMethod() {
29
//     my_instance.Get().SomeMethod();  // MyClass::SomeMethod()
30
//
31
//     MyClass* ptr = my_instance.Pointer();
32
//     ptr->DoDoDo();  // MyClass::DoDoDo
33
//   }
34
35
#ifndef BUTIL_LAZY_INSTANCE_H_
36
#define BUTIL_LAZY_INSTANCE_H_
37
38
#include <new>  // For placement new.
39
40
#include "butil/atomicops.h"
41
#include "butil/base_export.h"
42
#include "butil/basictypes.h"
43
#include "butil/debug/leak_annotations.h"
44
#include "butil/logging.h"
45
#include "butil/memory/aligned_memory.h"
46
#include "butil/third_party/dynamic_annotations/dynamic_annotations.h"
47
#include "butil/threading/thread_restrictions.h"
48
49
// LazyInstance uses its own struct initializer-list style static
50
// initialization, as base's LINKER_INITIALIZED requires a constructor and on
51
// some compilers (notably gcc 4.4) this still ends up needing runtime
52
// initialization.
53
#define LAZY_INSTANCE_INITIALIZER { 0, {{0}} }
54
55
namespace butil {
56
57
template <typename Type>
58
struct DefaultLazyInstanceTraits {
59
  static const bool kRegisterOnExit;
60
#ifndef NDEBUG
61
  static const bool kAllowedToAccessOnNonjoinableThread;
62
#endif
63
64
0
  static Type* New(void* instance) {
65
0
    DCHECK_EQ(reinterpret_cast<uintptr_t>(instance) & (ALIGNOF(Type) - 1), 0u)
66
0
        << ": Bad boy, the buffer passed to placement new is not aligned!\n"
67
0
        "This may break some stuff like SSE-based optimizations assuming the "
68
0
        "<Type> objects are word aligned.";
69
    // Use placement new to initialize our instance in our preallocated space.
70
    // The parenthesis is very important here to force POD type initialization.
71
0
    return new (instance) Type();
72
0
  }
Unexecuted instantiation: butil::DefaultLazyInstanceTraits<butil::ThreadLocalBoolean>::New(void*)
Unexecuted instantiation: butil::DefaultLazyInstanceTraits<butil::UnixEpochSingleton>::New(void*)
Unexecuted instantiation: butil::DefaultLazyInstanceTraits<butil::Lock>::New(void*)
73
  static void Delete(Type* instance) {
74
    // Explicitly call the destructor.
75
    instance->~Type();
76
  }
77
};
78
79
// NOTE(gejun): BullseyeCoverage Compile C++ 8.4.4 complains about `undefined
80
// reference' on in-place assignments to static constants.
81
template <typename Type>
82
const bool DefaultLazyInstanceTraits<Type>::kRegisterOnExit = true;
83
#ifndef NDEBUG
84
template <typename Type>
85
const bool DefaultLazyInstanceTraits<Type>::kAllowedToAccessOnNonjoinableThread = false;
86
#endif
87
88
// We pull out some of the functionality into non-templated functions, so we
89
// can implement the more complicated pieces out of line in the .cc file.
90
namespace internal {
91
92
// Use LazyInstance<T>::Leaky for a less-verbose call-site typedef; e.g.:
93
// butil::LazyInstance<T>::Leaky my_leaky_lazy_instance;
94
// instead of:
95
// butil::LazyInstance<T, butil::internal::LeakyLazyInstanceTraits<T> >
96
// my_leaky_lazy_instance;
97
// (especially when T is MyLongTypeNameImplClientHolderFactory).
98
// Only use this internal::-qualified verbose form to extend this traits class
99
// (depending on its implementation details).
100
template <typename Type>
101
struct LeakyLazyInstanceTraits {
102
  static const bool kRegisterOnExit;
103
#ifndef NDEBUG
104
  static const bool kAllowedToAccessOnNonjoinableThread;
105
#endif
106
107
0
  static Type* New(void* instance) {
108
    // Instruct LeakSanitizer to ignore the designated memory leak.
109
0
    ANNOTATE_SCOPED_MEMORY_LEAK;
110
0
    return DefaultLazyInstanceTraits<Type>::New(instance);
111
0
  }
Unexecuted instantiation: butil::internal::LeakyLazyInstanceTraits<butil::ThreadLocalBoolean>::New(void*)
Unexecuted instantiation: butil::internal::LeakyLazyInstanceTraits<butil::UnixEpochSingleton>::New(void*)
Unexecuted instantiation: butil::internal::LeakyLazyInstanceTraits<butil::Lock>::New(void*)
112
0
  static void Delete(Type* instance) {
113
0
  }
Unexecuted instantiation: butil::internal::LeakyLazyInstanceTraits<butil::ThreadLocalBoolean>::Delete(butil::ThreadLocalBoolean*)
Unexecuted instantiation: butil::internal::LeakyLazyInstanceTraits<butil::UnixEpochSingleton>::Delete(butil::UnixEpochSingleton*)
Unexecuted instantiation: butil::internal::LeakyLazyInstanceTraits<butil::Lock>::Delete(butil::Lock*)
114
};
115
116
template <typename Type>
117
const bool LeakyLazyInstanceTraits<Type>::kRegisterOnExit = false;
118
#ifndef NDEBUG
119
template <typename Type>
120
const bool LeakyLazyInstanceTraits<Type>::kAllowedToAccessOnNonjoinableThread = true;
121
#endif
122
123
// Our AtomicWord doubles as a spinlock, where a value of
124
// kBeingCreatedMarker means the spinlock is being held for creation.
125
static const subtle::AtomicWord kLazyInstanceStateCreating = 1;
126
127
// Check if instance needs to be created. If so return true otherwise
128
// if another thread has beat us, wait for instance to be created and
129
// return false.
130
BUTIL_EXPORT bool NeedsLazyInstance(subtle::AtomicWord* state);
131
132
// After creating an instance, call this to register the dtor to be called
133
// at program exit and to update the atomic state to hold the |new_instance|
134
BUTIL_EXPORT void CompleteLazyInstance(subtle::AtomicWord* state,
135
                                      subtle::AtomicWord new_instance,
136
                                      void* lazy_instance,
137
                                      void (*dtor)(void*));
138
139
}  // namespace internal
140
141
template <typename Type, typename Traits = DefaultLazyInstanceTraits<Type> >
142
class LazyInstance {
143
 public:
144
  // Do not define a destructor, as doing so makes LazyInstance a
145
  // non-POD-struct. We don't want that because then a static initializer will
146
  // be created to register the (empty) destructor with atexit() under MSVC, for
147
  // example. We handle destruction of the contained Type class explicitly via
148
  // the OnExit member function, where needed.
149
  // ~LazyInstance() {}
150
151
  // Convenience typedef to avoid having to repeat Type for leaky lazy
152
  // instances.
153
  typedef LazyInstance<Type, internal::LeakyLazyInstanceTraits<Type> > Leaky;
154
155
0
  Type& Get() {
156
0
    return *Pointer();
157
0
  }
Unexecuted instantiation: butil::LazyInstance<butil::ThreadLocalBoolean, butil::internal::LeakyLazyInstanceTraits<butil::ThreadLocalBoolean> >::Get()
Unexecuted instantiation: butil::LazyInstance<butil::UnixEpochSingleton, butil::internal::LeakyLazyInstanceTraits<butil::UnixEpochSingleton> >::Get()
158
159
0
  Type* Pointer() {
160
0
#ifndef NDEBUG
161
    // Avoid making TLS lookup on release builds.
162
0
    if (!Traits::kAllowedToAccessOnNonjoinableThread)
163
0
      ThreadRestrictions::AssertSingletonAllowed();
164
0
#endif
165
    // If any bit in the created mask is true, the instance has already been
166
    // fully constructed.
167
0
    static const subtle::AtomicWord kLazyInstanceCreatedMask =
168
0
        ~internal::kLazyInstanceStateCreating;
169
170
    // We will hopefully have fast access when the instance is already created.
171
    // Since a thread sees private_instance_ == 0 or kLazyInstanceStateCreating
172
    // at most once, the load is taken out of NeedsInstance() as a fast-path.
173
    // The load has acquire memory ordering as a thread which sees
174
    // private_instance_ > creating needs to acquire visibility over
175
    // the associated data (private_buf_). Pairing Release_Store is in
176
    // CompleteLazyInstance().
177
0
    subtle::AtomicWord value = subtle::Acquire_Load(&private_instance_);
178
0
    if (!(value & kLazyInstanceCreatedMask) &&
179
0
        internal::NeedsLazyInstance(&private_instance_)) {
180
      // Create the instance in the space provided by |private_buf_|.
181
0
      value = reinterpret_cast<subtle::AtomicWord>(
182
0
          Traits::New(private_buf_.void_data()));
183
0
      internal::CompleteLazyInstance(&private_instance_, value, this,
184
0
                                     Traits::kRegisterOnExit ? OnExit : NULL);
185
0
    }
186
187
    // This annotation helps race detectors recognize correct lock-less
188
    // synchronization between different threads calling Pointer().
189
    // We suggest dynamic race detection tool that "Traits::New" above
190
    // and CompleteLazyInstance(...) happens before "return instance()" below.
191
    // See the corresponding HAPPENS_BEFORE in CompleteLazyInstance(...).
192
0
    ANNOTATE_HAPPENS_AFTER(&private_instance_);
193
0
    return instance();
194
0
  }
Unexecuted instantiation: butil::LazyInstance<butil::ThreadLocalBoolean, butil::internal::LeakyLazyInstanceTraits<butil::ThreadLocalBoolean> >::Pointer()
Unexecuted instantiation: butil::LazyInstance<butil::UnixEpochSingleton, butil::internal::LeakyLazyInstanceTraits<butil::UnixEpochSingleton> >::Pointer()
Unexecuted instantiation: butil::LazyInstance<butil::Lock, butil::internal::LeakyLazyInstanceTraits<butil::Lock> >::Pointer()
195
196
  bool operator==(Type* p) {
197
    switch (subtle::NoBarrier_Load(&private_instance_)) {
198
      case 0:
199
        return p == NULL;
200
      case internal::kLazyInstanceStateCreating:
201
        return static_cast<void*>(p) == private_buf_.void_data();
202
      default:
203
        return p == instance();
204
    }
205
  }
206
207
  // Effectively private: member data is only public to allow the linker to
208
  // statically initialize it and to maintain a POD class. DO NOT USE FROM
209
  // OUTSIDE THIS CLASS.
210
211
  subtle::AtomicWord private_instance_;
212
  // Preallocated space for the Type instance.
213
  butil::AlignedMemory<sizeof(Type), ALIGNOF(Type)> private_buf_;
214
215
 private:
216
0
  Type* instance() {
217
0
    return reinterpret_cast<Type*>(subtle::NoBarrier_Load(&private_instance_));
218
0
  }
Unexecuted instantiation: butil::LazyInstance<butil::ThreadLocalBoolean, butil::internal::LeakyLazyInstanceTraits<butil::ThreadLocalBoolean> >::instance()
Unexecuted instantiation: butil::LazyInstance<butil::UnixEpochSingleton, butil::internal::LeakyLazyInstanceTraits<butil::UnixEpochSingleton> >::instance()
Unexecuted instantiation: butil::LazyInstance<butil::Lock, butil::internal::LeakyLazyInstanceTraits<butil::Lock> >::instance()
219
220
  // Adapter function for use with AtExit.  This should be called single
221
  // threaded, so don't synchronize across threads.
222
  // Calling OnExit while the instance is in use by other threads is a mistake.
223
0
  static void OnExit(void* lazy_instance) {
224
0
    LazyInstance<Type, Traits>* me =
225
0
        reinterpret_cast<LazyInstance<Type, Traits>*>(lazy_instance);
226
0
    Traits::Delete(me->instance());
227
0
    subtle::NoBarrier_Store(&me->private_instance_, 0);
228
0
  }
Unexecuted instantiation: butil::LazyInstance<butil::ThreadLocalBoolean, butil::internal::LeakyLazyInstanceTraits<butil::ThreadLocalBoolean> >::OnExit(void*)
Unexecuted instantiation: butil::LazyInstance<butil::UnixEpochSingleton, butil::internal::LeakyLazyInstanceTraits<butil::UnixEpochSingleton> >::OnExit(void*)
Unexecuted instantiation: butil::LazyInstance<butil::Lock, butil::internal::LeakyLazyInstanceTraits<butil::Lock> >::OnExit(void*)
229
};
230
231
}  // namespace butil
232
233
#endif  // BUTIL_LAZY_INSTANCE_H_