summaryrefslogtreecommitdiff
path: root/absl/flags/internal/flag.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/flags/internal/flag.cc')
-rw-r--r--absl/flags/internal/flag.cc91
1 files changed, 52 insertions, 39 deletions
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<char, sizeof(AlignedTwoWords)> buf{};
- (*default_value_.gen_func)(buf.data());
- auto atomic_value = absl::bit_cast<AlignedTwoWords>(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<std::array<char, sizeof(AlignedTwoWords)>>(
- TwoWordsValue().load(std::memory_order_acquire));
- return flags_internal::Unparse(op_, two_words_val.data());
+ case FlagValueStorageKind::kSequenceLocked: {
+ std::unique_ptr<void, DynValueDeleter> cloned(flags_internal::Alloc(op_),
+ DynValueDeleter{op_});
+ ReadSequenceLockedData(cloned.get());
+ return flags_internal::Unparse(op_, cloned.get());
}
}
@@ -345,17 +344,22 @@ std::unique_ptr<FlagStateInterface> FlagImpl::SaveState() {
case FlagValueStorageKind::kAlignedBuffer: {
return absl::make_unique<FlagState>(
*this, flags_internal::Clone(op_, AlignedBufferValue()), modified,
- on_command_line, counter_);
+ on_command_line, ModificationCount());
}
case FlagValueStorageKind::kOneWordAtomic: {
return absl::make_unique<FlagState>(
*this, OneWordValue().load(std::memory_order_acquire), modified,
- on_command_line, counter_);
+ on_command_line, ModificationCount());
}
- case FlagValueStorageKind::kTwoWordsAtomic: {
- return absl::make_unique<FlagState>(
- *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<void>(success);
+ return absl::make_unique<FlagState>(*this, cloned, modified,
+ on_command_line, ModificationCount());
}
}
return nullptr;
@@ -363,21 +367,18 @@ std::unique_ptr<FlagStateInterface> 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<void>();
}
+std::atomic<uint64_t>* FlagImpl::AtomicBufferValue() const {
+ assert(ValueStorageKind() == FlagValueStorageKind::kSequenceLocked);
+ return OffsetValue<std::atomic<uint64_t>>();
+}
+
std::atomic<int64_t>& FlagImpl::OneWordValue() const {
assert(ValueStorageKind() == FlagValueStorageKind::kOneWordAtomic);
return OffsetValue<FlagOneWordValue>()->value;
}
-std::atomic<AlignedTwoWords>& FlagImpl::TwoWordsValue() const {
- assert(ValueStorageKind() == FlagValueStorageKind::kTwoWordsAtomic);
- return OffsetValue<FlagTwoWordsValue>()->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<void>(success);
+}
+
void FlagImpl::Write(const void* src) {
absl::MutexLock l(DataGuard());