diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /security/sandbox/chromium/base/lazy_instance_helpers.h | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'security/sandbox/chromium/base/lazy_instance_helpers.h')
-rw-r--r-- | security/sandbox/chromium/base/lazy_instance_helpers.h | 101 |
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_ |