From 384af0e9141283172e2bff3210dae79fb7130d9c Mon Sep 17 00:00:00 2001 From: Abseil Team Date: Wed, 30 Dec 2020 14:30:17 -0800 Subject: Export of internal Abseil changes -- 465461299a9814aca325fee599cefbfe462f12fe by Abseil Team : Optimize trivially copyable flags with a sequence lock PiperOrigin-RevId: 349602779 -- 73f39f959e21121684a51887243abad0814a335e by Abseil Team : Internal change PiperOrigin-RevId: 349590869 -- 6b3106fa66b8f075a39a1a8f3265ae132b7e2c84 by Abseil Team : Remove ABSL_DLL from `log_prefix_hook` and `abort_hook`. PiperOrigin-RevId: 349560499 -- bb0d295e699a509f3284145e025d00036b70dbb2 by Abseil Team : Tiny docstring fix A small edit to make "use of this is useful" a little less redundant. :) PiperOrigin-RevId: 349445689 GitOrigin-RevId: 465461299a9814aca325fee599cefbfe462f12fe Change-Id: I08cc4091b8b95b68188cb9168ac622dacc5fa688 --- absl/flags/internal/flag.cc | 91 ++++++++++++++++++++++++++------------------- 1 file changed, 52 insertions(+), 39 deletions(-) (limited to 'absl/flags/internal/flag.cc') diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc index 1502e7f1..f83c1fe7 100644 --- a/absl/flags/internal/flag.cc +++ b/absl/flags/internal/flag.cc @@ -96,7 +96,8 @@ class FlagState : public flags_internal::FlagStateInterface { counter_(counter) {} ~FlagState() override { - if (flag_impl_.ValueStorageKind() != FlagValueStorageKind::kAlignedBuffer) + if (flag_impl_.ValueStorageKind() != FlagValueStorageKind::kAlignedBuffer && + flag_impl_.ValueStorageKind() != FlagValueStorageKind::kSequenceLocked) return; flags_internal::Delete(flag_impl_.op_, value_.heap_allocated); } @@ -118,11 +119,9 @@ class FlagState : public flags_internal::FlagStateInterface { union SavedValue { explicit SavedValue(void* v) : heap_allocated(v) {} explicit SavedValue(int64_t v) : one_word(v) {} - explicit SavedValue(flags_internal::AlignedTwoWords v) : two_words(v) {} void* heap_allocated; int64_t one_word; - flags_internal::AlignedTwoWords two_words; } value_; bool modified_; bool on_command_line_; @@ -164,17 +163,15 @@ void FlagImpl::Init() { std::memory_order_release); break; } - case FlagValueStorageKind::kTwoWordsAtomic: { + case FlagValueStorageKind::kSequenceLocked: { // For this storage kind the default_value_ always points to gen_func // during initialization. assert(def_kind == FlagDefaultKind::kGenFunc); - alignas(AlignedTwoWords) std::array buf{}; - (*default_value_.gen_func)(buf.data()); - auto atomic_value = absl::bit_cast(buf); - TwoWordsValue().store(atomic_value, std::memory_order_release); + (*default_value_.gen_func)(AtomicBufferValue()); break; } } + seq_lock_.MarkInitialized(); } absl::Mutex* FlagImpl::DataGuard() const { @@ -231,23 +228,21 @@ void FlagImpl::StoreValue(const void* src) { switch (ValueStorageKind()) { case FlagValueStorageKind::kAlignedBuffer: Copy(op_, src, AlignedBufferValue()); + seq_lock_.IncrementModificationCount(); break; case FlagValueStorageKind::kOneWordAtomic: { int64_t one_word_val = 0; std::memcpy(&one_word_val, src, Sizeof(op_)); OneWordValue().store(one_word_val, std::memory_order_release); + seq_lock_.IncrementModificationCount(); break; } - case FlagValueStorageKind::kTwoWordsAtomic: { - AlignedTwoWords two_words_val{0, 0}; - std::memcpy(&two_words_val, src, Sizeof(op_)); - TwoWordsValue().store(two_words_val, std::memory_order_release); + case FlagValueStorageKind::kSequenceLocked: { + seq_lock_.Write(AtomicBufferValue(), src, Sizeof(op_)); break; } } - modified_ = true; - ++counter_; InvokeCallback(); } @@ -266,6 +261,10 @@ FlagFastTypeId FlagImpl::TypeId() const { return flags_internal::FastTypeId(op_); } +int64_t FlagImpl::ModificationCount() const { + return seq_lock_.ModificationCount(); +} + bool FlagImpl::IsSpecifiedOnCommandLine() const { absl::MutexLock l(DataGuard()); return on_command_line_; @@ -291,11 +290,11 @@ std::string FlagImpl::CurrentValue() const { OneWordValue().load(std::memory_order_acquire)); return flags_internal::Unparse(op_, one_word_val.data()); } - case FlagValueStorageKind::kTwoWordsAtomic: { - const auto two_words_val = - absl::bit_cast>( - TwoWordsValue().load(std::memory_order_acquire)); - return flags_internal::Unparse(op_, two_words_val.data()); + case FlagValueStorageKind::kSequenceLocked: { + std::unique_ptr cloned(flags_internal::Alloc(op_), + DynValueDeleter{op_}); + ReadSequenceLockedData(cloned.get()); + return flags_internal::Unparse(op_, cloned.get()); } } @@ -345,17 +344,22 @@ std::unique_ptr FlagImpl::SaveState() { case FlagValueStorageKind::kAlignedBuffer: { return absl::make_unique( *this, flags_internal::Clone(op_, AlignedBufferValue()), modified, - on_command_line, counter_); + on_command_line, ModificationCount()); } case FlagValueStorageKind::kOneWordAtomic: { return absl::make_unique( *this, OneWordValue().load(std::memory_order_acquire), modified, - on_command_line, counter_); + on_command_line, ModificationCount()); } - case FlagValueStorageKind::kTwoWordsAtomic: { - return absl::make_unique( - *this, TwoWordsValue().load(std::memory_order_acquire), modified, - on_command_line, counter_); + case FlagValueStorageKind::kSequenceLocked: { + void* cloned = flags_internal::Alloc(op_); + // Read is guaranteed to be successful because we hold the lock. + bool success = + seq_lock_.TryRead(cloned, AtomicBufferValue(), Sizeof(op_)); + assert(success); + static_cast(success); + return absl::make_unique(*this, cloned, modified, + on_command_line, ModificationCount()); } } return nullptr; @@ -363,21 +367,18 @@ std::unique_ptr FlagImpl::SaveState() { bool FlagImpl::RestoreState(const FlagState& flag_state) { absl::MutexLock l(DataGuard()); - - if (flag_state.counter_ == counter_) { + if (flag_state.counter_ == ModificationCount()) { return false; } switch (ValueStorageKind()) { case FlagValueStorageKind::kAlignedBuffer: + case FlagValueStorageKind::kSequenceLocked: StoreValue(flag_state.value_.heap_allocated); break; case FlagValueStorageKind::kOneWordAtomic: StoreValue(&flag_state.value_.one_word); break; - case FlagValueStorageKind::kTwoWordsAtomic: - StoreValue(&flag_state.value_.two_words); - break; } modified_ = flag_state.modified_; @@ -400,16 +401,16 @@ void* FlagImpl::AlignedBufferValue() const { return OffsetValue(); } +std::atomic* FlagImpl::AtomicBufferValue() const { + assert(ValueStorageKind() == FlagValueStorageKind::kSequenceLocked); + return OffsetValue>(); +} + std::atomic& FlagImpl::OneWordValue() const { assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic); return OffsetValue()->value; } -std::atomic& FlagImpl::TwoWordsValue() const { - assert(ValueStorageKind() == FlagValueStorageKind::kTwoWordsAtomic); - return OffsetValue()->value; -} - // Attempts to parse supplied `value` string using parsing routine in the `flag` // argument. If parsing successful, this function replaces the dst with newly // parsed value. In case if any error is encountered in either step, the error @@ -443,15 +444,27 @@ void FlagImpl::Read(void* dst) const { std::memcpy(dst, &one_word_val, Sizeof(op_)); break; } - case FlagValueStorageKind::kTwoWordsAtomic: { - const AlignedTwoWords two_words_val = - TwoWordsValue().load(std::memory_order_acquire); - std::memcpy(dst, &two_words_val, Sizeof(op_)); + case FlagValueStorageKind::kSequenceLocked: { + ReadSequenceLockedData(dst); break; } } } +void FlagImpl::ReadSequenceLockedData(void* dst) const { + int size = Sizeof(op_); + // Attempt to read using the sequence lock. + if (ABSL_PREDICT_TRUE(seq_lock_.TryRead(dst, AtomicBufferValue(), size))) { + return; + } + // We failed due to contention. Acquire the lock to prevent contention + // and try again. + absl::ReaderMutexLock l(DataGuard()); + bool success = seq_lock_.TryRead(dst, AtomicBufferValue(), size); + assert(success); + static_cast(success); +} + void FlagImpl::Write(const void* src) { absl::MutexLock l(DataGuard()); -- cgit v1.2.3