summaryrefslogtreecommitdiffstats
path: root/security/sandbox/chromium/base/lazy_instance_helpers.h
diff options
context:
space:
mode:
Diffstat (limited to 'security/sandbox/chromium/base/lazy_instance_helpers.h')
-rw-r--r--security/sandbox/chromium/base/lazy_instance_helpers.h101
1 files changed, 101 insertions, 0 deletions
diff --git a/security/sandbox/chromium/base/lazy_instance_helpers.h b/security/sandbox/chromium/base/lazy_instance_helpers.h
new file mode 100644
index 0000000000..5a43d8b1f2
--- /dev/null
+++ b/security/sandbox/chromium/base/lazy_instance_helpers.h
@@ -0,0 +1,101 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_LAZY_INSTANCE_INTERNAL_H_
+#define BASE_LAZY_INSTANCE_INTERNAL_H_
+
+#include "base/atomicops.h"
+#include "base/base_export.h"
+#include "base/logging.h"
+
+// Helper methods used by LazyInstance and a few other base APIs for thread-safe
+// lazy construction.
+
+namespace base {
+namespace internal {
+
+// Our AtomicWord doubles as a spinlock, where a value of
+// kLazyInstanceStateCreating means the spinlock is being held for creation.
+constexpr subtle::AtomicWord kLazyInstanceStateCreating = 1;
+
+// Helper for GetOrCreateLazyPointer(). Checks if instance needs to be created.
+// If so returns true otherwise if another thread has beat us, waits for
+// instance to be created and returns false.
+BASE_EXPORT bool NeedsLazyInstance(subtle::AtomicWord* state);
+
+// Helper for GetOrCreateLazyPointer(). After creating an instance, this is
+// called to register the dtor to be called at program exit and to update the
+// atomic state to hold the |new_instance|
+BASE_EXPORT void CompleteLazyInstance(subtle::AtomicWord* state,
+ subtle::AtomicWord new_instance,
+ void (*destructor)(void*),
+ void* destructor_arg);
+
+} // namespace internal
+
+namespace subtle {
+
+// If |state| is uninitialized (zero), constructs a value using
+// |creator_func(creator_arg)|, stores it into |state| and registers
+// |destructor(destructor_arg)| to be called when the current AtExitManager goes
+// out of scope. Then, returns the value stored in |state|. It is safe to have
+// concurrent calls to this function with the same |state|. |creator_func| may
+// return nullptr if it doesn't want to create an instance anymore (e.g. on
+// shutdown), it is from then on required to return nullptr to all callers (ref.
+// StaticMemorySingletonTraits). In that case, callers need to synchronize
+// before |creator_func| may return a non-null instance again (ref.
+// StaticMemorySingletonTraits::ResurectForTesting()).
+// Implementation note on |creator_func/creator_arg|. It makes for ugly adapters
+// but it avoids redundant template instantiations (e.g. saves 27KB in
+// chrome.dll) because linker is able to fold these for multiple Types but
+// couldn't with the more advanced CreatorFunc template type which in turn
+// improves code locality (and application startup) -- ref.
+// https://chromium-review.googlesource.com/c/chromium/src/+/530984/5/base/lazy_instance.h#140,
+// worsened by https://chromium-review.googlesource.com/c/chromium/src/+/868013
+// and caught then as https://crbug.com/804034.
+template <typename Type>
+Type* GetOrCreateLazyPointer(subtle::AtomicWord* state,
+ Type* (*creator_func)(void*),
+ void* creator_arg,
+ void (*destructor)(void*),
+ void* destructor_arg) {
+ DCHECK(state);
+ DCHECK(creator_func);
+
+ // If any bit in the created mask is true, the instance has already been
+ // fully constructed.
+ constexpr subtle::AtomicWord kLazyInstanceCreatedMask =
+ ~internal::kLazyInstanceStateCreating;
+
+ // We will hopefully have fast access when the instance is already created.
+ // Since a thread sees |state| == 0 or kLazyInstanceStateCreating at most
+ // once, the load is taken out of NeedsLazyInstance() as a fast-path. The load
+ // has acquire memory ordering as a thread which sees |state| > creating needs
+ // to acquire visibility over the associated data. Pairing Release_Store is in
+ // CompleteLazyInstance().
+ subtle::AtomicWord instance = subtle::Acquire_Load(state);
+ if (!(instance & kLazyInstanceCreatedMask)) {
+ if (internal::NeedsLazyInstance(state)) {
+ // This thread won the race and is now responsible for creating the
+ // instance and storing it back into |state|.
+ instance =
+ reinterpret_cast<subtle::AtomicWord>((*creator_func)(creator_arg));
+ internal::CompleteLazyInstance(state, instance, destructor,
+ destructor_arg);
+ } else {
+ // This thread lost the race but now has visibility over the constructed
+ // instance (NeedsLazyInstance() doesn't return until the constructing
+ // thread releases the instance via CompleteLazyInstance()).
+ instance = subtle::Acquire_Load(state);
+ DCHECK(instance & kLazyInstanceCreatedMask);
+ }
+ }
+ return reinterpret_cast<Type*>(instance);
+}
+
+} // namespace subtle
+
+} // namespace base
+
+#endif // BASE_LAZY_INSTANCE_INTERNAL_H_