Export of internal Abseil changes
-- b8e6b64b604449bb51ed0ba8e9439097f3aa8773 by Abseil Team <absl-team@google.com>: fix typo 'implentation' -> 'implementation' PiperOrigin-RevId: 311623471 -- 2b9262a311f3329c8006835a79498edd90568acd by Matt Kulukundis <kfm@google.com>: Internal cleanup PiperOrigin-RevId: 311549039 -- 7507ed3c28113e28f993aa634bd44a9a0d4c4a2c by Derek Mauro <dmauro@google.com>: Delete LinkerInitialized Now that all SpinLocks have the same scheduling mode for their entire lives, the scheduling mode does not need to be re-tested in the loop in LockSlow. PiperOrigin-RevId: 311521474 -- abf5fae67e21b38cda4083aaafd7012e2c6fbb7d by Andy Getzendanner <durandal@google.com>: Fix public target name of the random library Import of https://github.com/abseil/abseil-cpp/pull/684 PiperOrigin-RevId: 311429555 GitOrigin-RevId: b8e6b64b604449bb51ed0ba8e9439097f3aa8773 Change-Id: Ic48f671846bda059cc46f4a0b967cc3b1a733ba0
This commit is contained in:
parent
f2bc9d11e8
commit
d118d4bb11
6 changed files with 14 additions and 95 deletions
|
@ -79,29 +79,6 @@ SpinLock::SpinLock(base_internal::SchedulingMode mode)
|
||||||
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
|
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
|
||||||
}
|
}
|
||||||
|
|
||||||
SpinLock::SpinLock(base_internal::LinkerInitialized,
|
|
||||||
base_internal::SchedulingMode mode) {
|
|
||||||
ABSL_TSAN_MUTEX_CREATE(this, 0);
|
|
||||||
if (IsCooperative(mode)) {
|
|
||||||
InitLinkerInitializedAndCooperative();
|
|
||||||
}
|
|
||||||
// Otherwise, lockword_ is already initialized.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Static (linker initialized) spinlocks always start life as functional
|
|
||||||
// non-cooperative locks. When their static constructor does run, it will call
|
|
||||||
// this initializer to augment the lockword with the cooperative bit. By
|
|
||||||
// actually taking the lock when we do this we avoid the need for an atomic
|
|
||||||
// operation in the regular unlock path.
|
|
||||||
//
|
|
||||||
// SlowLock() must be careful to re-test for this bit so that any outstanding
|
|
||||||
// waiters may be upgraded to cooperative status.
|
|
||||||
void SpinLock::InitLinkerInitializedAndCooperative() {
|
|
||||||
Lock();
|
|
||||||
lockword_.fetch_or(kSpinLockCooperative, std::memory_order_relaxed);
|
|
||||||
Unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Monitor the lock to see if its value changes within some time period
|
// Monitor the lock to see if its value changes within some time period
|
||||||
// (adaptive_spin_count loop iterations). The last value read from the lock
|
// (adaptive_spin_count loop iterations). The last value read from the lock
|
||||||
// is returned from the method.
|
// is returned from the method.
|
||||||
|
@ -128,6 +105,14 @@ void SpinLock::SlowLock() {
|
||||||
if ((lock_value & kSpinLockHeld) == 0) {
|
if ((lock_value & kSpinLockHeld) == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
base_internal::SchedulingMode scheduling_mode;
|
||||||
|
if ((lock_value & kSpinLockCooperative) != 0) {
|
||||||
|
scheduling_mode = base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
|
||||||
|
} else {
|
||||||
|
scheduling_mode = base_internal::SCHEDULE_KERNEL_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
// The lock was not obtained initially, so this thread needs to wait for
|
// The lock was not obtained initially, so this thread needs to wait for
|
||||||
// it. Record the current timestamp in the local variable wait_start_time
|
// it. Record the current timestamp in the local variable wait_start_time
|
||||||
// so the total wait time can be stored in the lockword once this thread
|
// so the total wait time can be stored in the lockword once this thread
|
||||||
|
@ -158,12 +143,6 @@ void SpinLock::SlowLock() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
base_internal::SchedulingMode scheduling_mode;
|
|
||||||
if ((lock_value & kSpinLockCooperative) != 0) {
|
|
||||||
scheduling_mode = base_internal::SCHEDULE_COOPERATIVE_AND_KERNEL;
|
|
||||||
} else {
|
|
||||||
scheduling_mode = base_internal::SCHEDULE_KERNEL_ONLY;
|
|
||||||
}
|
|
||||||
// SpinLockDelay() calls into fiber scheduler, we need to see
|
// SpinLockDelay() calls into fiber scheduler, we need to see
|
||||||
// synchronization there to avoid false positives.
|
// synchronization there to avoid false positives.
|
||||||
ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
|
ABSL_TSAN_MUTEX_PRE_DIVERT(this, 0);
|
||||||
|
|
|
@ -56,27 +56,9 @@ class ABSL_LOCKABLE SpinLock {
|
||||||
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
|
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special constructor for use with static SpinLock objects. E.g.,
|
|
||||||
//
|
|
||||||
// static SpinLock lock(base_internal::kLinkerInitialized);
|
|
||||||
//
|
|
||||||
// When initialized using this constructor, we depend on the fact
|
|
||||||
// that the linker has already initialized the memory appropriately. The lock
|
|
||||||
// is initialized in non-cooperative mode.
|
|
||||||
//
|
|
||||||
// A SpinLock constructed like this can be freely used from global
|
|
||||||
// initializers without worrying about the order in which global
|
|
||||||
// initializers run.
|
|
||||||
explicit SpinLock(base_internal::LinkerInitialized) {
|
|
||||||
// Does nothing; lockword_ is already initialized
|
|
||||||
ABSL_TSAN_MUTEX_CREATE(this, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Constructors that allow non-cooperative spinlocks to be created for use
|
// Constructors that allow non-cooperative spinlocks to be created for use
|
||||||
// inside thread schedulers. Normal clients should not use these.
|
// inside thread schedulers. Normal clients should not use these.
|
||||||
explicit SpinLock(base_internal::SchedulingMode mode);
|
explicit SpinLock(base_internal::SchedulingMode mode);
|
||||||
SpinLock(base_internal::LinkerInitialized,
|
|
||||||
base_internal::SchedulingMode mode);
|
|
||||||
|
|
||||||
// Constructor for global SpinLock instances. See absl/base/const_init.h.
|
// Constructor for global SpinLock instances. See absl/base/const_init.h.
|
||||||
constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode)
|
constexpr SpinLock(absl::ConstInitType, base_internal::SchedulingMode mode)
|
||||||
|
@ -168,7 +150,6 @@ class ABSL_LOCKABLE SpinLock {
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles);
|
uint32_t TryLockInternal(uint32_t lock_value, uint32_t wait_cycles);
|
||||||
void InitLinkerInitializedAndCooperative();
|
|
||||||
void SlowLock() ABSL_ATTRIBUTE_COLD;
|
void SlowLock() ABSL_ATTRIBUTE_COLD;
|
||||||
void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD;
|
void SlowUnlock(uint32_t lock_value) ABSL_ATTRIBUTE_COLD;
|
||||||
uint32_t SpinLoop();
|
uint32_t SpinLoop();
|
||||||
|
|
|
@ -55,36 +55,6 @@ auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
|
||||||
ABSL_NAMESPACE_END
|
ABSL_NAMESPACE_END
|
||||||
} // namespace absl
|
} // namespace absl
|
||||||
|
|
||||||
// kLinkerInitialized
|
|
||||||
//
|
|
||||||
// An enum used only as a constructor argument to indicate that a variable has
|
|
||||||
// static storage duration, and that the constructor should do nothing to its
|
|
||||||
// state. Use of this macro indicates to the reader that it is legal to
|
|
||||||
// declare a static instance of the class, provided the constructor is given
|
|
||||||
// the absl::base_internal::kLinkerInitialized argument.
|
|
||||||
//
|
|
||||||
// Normally, it is unsafe to declare a static variable that has a constructor or
|
|
||||||
// a destructor because invocation order is undefined. However, if the type can
|
|
||||||
// be zero-initialized (which the loader does for static variables) into a valid
|
|
||||||
// state and the type's destructor does not affect storage, then a constructor
|
|
||||||
// for static initialization can be declared.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// // Declaration
|
|
||||||
// explicit MyClass(absl::base_internal:LinkerInitialized x) {}
|
|
||||||
//
|
|
||||||
// // Invocation
|
|
||||||
// static MyClass my_global(absl::base_internal::kLinkerInitialized);
|
|
||||||
namespace absl {
|
|
||||||
ABSL_NAMESPACE_BEGIN
|
|
||||||
namespace base_internal {
|
|
||||||
enum LinkerInitialized {
|
|
||||||
kLinkerInitialized = 0,
|
|
||||||
};
|
|
||||||
} // namespace base_internal
|
|
||||||
ABSL_NAMESPACE_END
|
|
||||||
} // namespace absl
|
|
||||||
|
|
||||||
// ABSL_FALLTHROUGH_INTENDED
|
// ABSL_FALLTHROUGH_INTENDED
|
||||||
//
|
//
|
||||||
// Annotates implicit fall-through between switch labels, allowing a case to
|
// Annotates implicit fall-through between switch labels, allowing a case to
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "absl/flags/internal/flag.h"
|
#include "absl/flags/internal/flag.h"
|
||||||
#include "absl/flags/internal/registry.h"
|
#include "absl/flags/internal/registry.h"
|
||||||
#include "absl/flags/marshalling.h"
|
#include "absl/flags/marshalling.h"
|
||||||
|
#include "absl/strings/string_view.h"
|
||||||
|
|
||||||
namespace absl {
|
namespace absl {
|
||||||
ABSL_NAMESPACE_BEGIN
|
ABSL_NAMESPACE_BEGIN
|
||||||
|
|
|
@ -407,7 +407,7 @@ using IntSequenceTypes =
|
||||||
INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueSequenceTest, IntSequenceTypes);
|
INSTANTIATE_TYPED_TEST_CASE_P(My, HashValueSequenceTest, IntSequenceTypes);
|
||||||
|
|
||||||
// Private type that only supports AbslHashValue to make sure our chosen hash
|
// Private type that only supports AbslHashValue to make sure our chosen hash
|
||||||
// implentation is recursive within absl::Hash.
|
// implementation is recursive within absl::Hash.
|
||||||
// It uses std::abs() on the value to provide different bitwise representations
|
// It uses std::abs() on the value to provide different bitwise representations
|
||||||
// of the same logical value.
|
// of the same logical value.
|
||||||
struct Private {
|
struct Private {
|
||||||
|
|
|
@ -209,31 +209,22 @@ class SynchronizationStorage {
|
||||||
// Instances allocated on the heap or on the stack should use the default
|
// Instances allocated on the heap or on the stack should use the default
|
||||||
// constructor.
|
// constructor.
|
||||||
SynchronizationStorage()
|
SynchronizationStorage()
|
||||||
: is_dynamic_(true), once_() {}
|
: destruct_(true), once_() {}
|
||||||
|
|
||||||
// Instances allocated in static storage (not on the heap, not on the
|
|
||||||
// stack) should use this constructor.
|
|
||||||
explicit SynchronizationStorage(base_internal::LinkerInitialized) {}
|
|
||||||
|
|
||||||
constexpr explicit SynchronizationStorage(absl::ConstInitType)
|
constexpr explicit SynchronizationStorage(absl::ConstInitType)
|
||||||
: is_dynamic_(false), once_(), space_{{0}} {}
|
: destruct_(false), once_(), space_{{0}} {}
|
||||||
|
|
||||||
SynchronizationStorage(SynchronizationStorage&) = delete;
|
SynchronizationStorage(SynchronizationStorage&) = delete;
|
||||||
SynchronizationStorage& operator=(SynchronizationStorage&) = delete;
|
SynchronizationStorage& operator=(SynchronizationStorage&) = delete;
|
||||||
|
|
||||||
~SynchronizationStorage() {
|
~SynchronizationStorage() {
|
||||||
if (is_dynamic_) {
|
if (destruct_) {
|
||||||
get()->~T();
|
get()->~T();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the object in storage. This is fast and thread safe, but does
|
// Retrieve the object in storage. This is fast and thread safe, but does
|
||||||
// incur the cost of absl::call_once().
|
// incur the cost of absl::call_once().
|
||||||
//
|
|
||||||
// For instances in static storage constructed with the
|
|
||||||
// LinkerInitialized constructor, may be called at any time without
|
|
||||||
// regard for order of dynamic initialization or destruction of objects
|
|
||||||
// in static storage. See the class comment for caveats.
|
|
||||||
T* get() {
|
T* get() {
|
||||||
absl::call_once(once_, SynchronizationStorage::Construct, this);
|
absl::call_once(once_, SynchronizationStorage::Construct, this);
|
||||||
return reinterpret_cast<T*>(&space_);
|
return reinterpret_cast<T*>(&space_);
|
||||||
|
@ -245,10 +236,7 @@ class SynchronizationStorage {
|
||||||
}
|
}
|
||||||
|
|
||||||
// When true, T's destructor is run when this is destructed.
|
// When true, T's destructor is run when this is destructed.
|
||||||
//
|
const bool destruct_;
|
||||||
// The LinkerInitialized constructor assumes this value will be set
|
|
||||||
// false by static initialization.
|
|
||||||
bool is_dynamic_;
|
|
||||||
|
|
||||||
absl::once_flag once_;
|
absl::once_flag once_;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue