diff options
Diffstat (limited to 'absl/flags/internal')
-rw-r--r-- | absl/flags/internal/flag.cc | 71 | ||||
-rw-r--r-- | absl/flags/internal/flag.h | 91 |
2 files changed, 99 insertions, 63 deletions
diff --git a/absl/flags/internal/flag.cc b/absl/flags/internal/flag.cc index d087f79e891c..435cc362478f 100644 --- a/absl/flags/internal/flag.cc +++ b/absl/flags/internal/flag.cc @@ -49,12 +49,11 @@ void FlagImpl::Init() { absl::MutexLock lock(&locks_->primary_mu); - if (def_ != nullptr) { + if (cur_ != nullptr) { inited_.store(true, std::memory_order_release); } else { - // Need to initialize def and cur fields. - def_ = (*initial_value_gen_)(); - cur_ = Clone(op_, def_); + // Need to initialize cur field. + cur_ = MakeInitValue().release(); StoreAtomic(); inited_.store(true, std::memory_order_release); InvokeCallback(); @@ -63,8 +62,7 @@ void FlagImpl::Init() { // Ensures that the lazily initialized data is initialized, // and returns pointer to the mutex guarding flags data. -absl::Mutex* FlagImpl::DataGuard() const - ABSL_LOCK_RETURNED(locks_->primary_mu) { +absl::Mutex* FlagImpl::DataGuard() const { if (ABSL_PREDICT_FALSE(!inited_.load(std::memory_order_acquire))) { const_cast<FlagImpl*>(this)->Init(); } @@ -79,12 +77,23 @@ void FlagImpl::Destroy() const { // Values are heap allocated for Abseil Flags. if (cur_) Delete(op_, cur_); - if (def_) Delete(op_, def_); + if (def_kind_ == FlagDefaultSrcKind::kDynamicValue) + Delete(op_, default_src_.dynamic_value); } delete locks_; } +std::unique_ptr<void, DynValueDeleter> FlagImpl::MakeInitValue() const { + void* res = nullptr; + if (def_kind_ == FlagDefaultSrcKind::kDynamicValue) { + res = Clone(op_, default_src_.dynamic_value); + } else { + res = (*default_src_.gen_func)(); + } + return {res, DynValueDeleter{op_}}; +} + std::string FlagImpl::Help() const { return help_source_kind_ == FlagHelpSrcKind::kLiteral ? help_.literal : help_.gen_func(); @@ -103,7 +112,8 @@ bool FlagImpl::IsSpecifiedOnCommandLine() const { std::string FlagImpl::DefaultValue() const { absl::MutexLock l(DataGuard()); - return Unparse(marshalling_op_, def_); + auto obj = MakeInitValue(); + return Unparse(marshalling_op_, obj.get()); } std::string FlagImpl::CurrentValue() const { @@ -121,8 +131,7 @@ void FlagImpl::SetCallback( InvokeCallback(); } -void FlagImpl::InvokeCallback() const - ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) { +void FlagImpl::InvokeCallback() const { if (!callback_) return; // If the flag has a mutation callback this function invokes it. While the @@ -172,23 +181,20 @@ bool FlagImpl::RestoreState(const CommandLineFlag& flag, const void* value, // 'dst' assuming it is a pointer to the flag's value type. In case if any error // is encountered in either step, the error message is stored in 'err' bool FlagImpl::TryParse(const CommandLineFlag& flag, void* dst, - absl::string_view value, std::string* err) const - ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) { - void* tentative_value = Clone(op_, def_); + absl::string_view value, std::string* err) const { + auto tentative_value = MakeInitValue(); std::string parse_err; - if (!Parse(marshalling_op_, value, tentative_value, &parse_err)) { + if (!Parse(marshalling_op_, value, tentative_value.get(), &parse_err)) { auto type_name = flag.Typename(); absl::string_view err_sep = parse_err.empty() ? "" : "; "; absl::string_view typename_sep = type_name.empty() ? "" : " "; *err = absl::StrCat("Illegal value '", value, "' specified for", typename_sep, type_name, " flag '", flag.Name(), "'", err_sep, parse_err); - Delete(op_, tentative_value); return false; } - Copy(op_, tentative_value, dst); - Delete(op_, tentative_value); + Copy(op_, tentative_value.get(), dst); return true; } @@ -208,7 +214,7 @@ void FlagImpl::Read(const CommandLineFlag& flag, void* dst, CopyConstruct(op_, cur_, dst); } -void FlagImpl::StoreAtomic() ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) { +void FlagImpl::StoreAtomic() { size_t data_size = Sizeof(op_); if (data_size <= sizeof(int64_t)) { @@ -299,12 +305,22 @@ bool FlagImpl::SetFromString(const CommandLineFlag& flag, break; } case SET_FLAGS_DEFAULT: { - // modify the flag's default-value - if (!TryParse(flag, def_, value, err)) return false; + // Flag's new default-value. + auto new_default_value = MakeInitValue(); + + if (!TryParse(flag, new_default_value.get(), value, err)) return false; + + if (def_kind_ == FlagDefaultSrcKind::kDynamicValue) { + // Release old default value. + Delete(op_, default_src_.dynamic_value); + } + + default_src_.dynamic_value = new_default_value.release(); + def_kind_ = FlagDefaultSrcKind::kDynamicValue; if (!modified_) { // Need to set both default value *and* current, in this case - Copy(op_, def_, cur_); + Copy(op_, default_src_.dynamic_value, cur_); StoreAtomic(); InvokeCallback(); } @@ -321,9 +337,9 @@ void FlagImpl::CheckDefaultValueParsingRoundtrip( absl::MutexLock lock(DataGuard()); - void* dst = Clone(op_, def_); + auto dst = MakeInitValue(); std::string error; - if (!flags_internal::Parse(marshalling_op_, v, dst, &error)) { + if (!flags_internal::Parse(marshalling_op_, v, dst.get(), &error)) { ABSL_INTERNAL_LOG( FATAL, absl::StrCat("Flag ", flag.Name(), " (from ", flag.Filename(), @@ -333,18 +349,15 @@ void FlagImpl::CheckDefaultValueParsingRoundtrip( // We do not compare dst to def since parsing/unparsing may make // small changes, e.g., precision loss for floating point types. - Delete(op_, dst); } bool FlagImpl::ValidateInputValue(absl::string_view value) const { absl::MutexLock l(DataGuard()); - void* obj = Clone(op_, def_); + auto obj = MakeInitValue(); std::string ignored_error; - const bool result = - flags_internal::Parse(marshalling_op_, value, obj, &ignored_error); - Delete(op_, obj); - return result; + return flags_internal::Parse(marshalling_op_, value, obj.get(), + &ignored_error); } } // namespace flags_internal diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h index d79902543a22..947a8cadaf2d 100644 --- a/absl/flags/internal/flag.h +++ b/absl/flags/internal/flag.h @@ -119,47 +119,61 @@ constexpr flags_internal::HelpInitArg HelpArg(char) { flags_internal::FlagHelpSrcKind::kGenFunc}; } -// Signature for the function generating the initial flag value based (usually +// Signature for the function generating the initial flag value (usually // based on default value supplied in flag's definition) -using InitialValGenFunc = void* (*)(); +using FlagDfltGenFunc = void* (*)(); + +union FlagDefaultSrc { + constexpr explicit FlagDefaultSrc(FlagDfltGenFunc gen_func_arg) + : gen_func(gen_func_arg) {} + + void* dynamic_value; + FlagDfltGenFunc gen_func; +}; + +enum class FlagDefaultSrcKind : int8_t { kDynamicValue, kGenFunc }; // Signature for the mutation callback used by watched Flags // The callback is noexcept. // TODO(rogeeff): add noexcept after C++17 support is added. using FlagCallback = void (*)(); -void InvokeCallback(absl::Mutex* primary_mu, absl::Mutex* callback_mu, - FlagCallback cb) ABSL_EXCLUSIVE_LOCKS_REQUIRED(primary_mu); +struct DynValueDeleter { + void operator()(void* ptr) const { Delete(op, ptr); } + + const FlagOpFn op; +}; // The class encapsulates the Flag's data and safe access to it. class FlagImpl { public: constexpr FlagImpl(const flags_internal::FlagOpFn op, const flags_internal::FlagMarshallingOpFn marshalling_op, - const flags_internal::InitialValGenFunc initial_value_gen, + const flags_internal::FlagDfltGenFunc default_value_gen, const HelpInitArg help) : op_(op), marshalling_op_(marshalling_op), - initial_value_gen_(initial_value_gen), help_(help.source), - help_source_kind_(help.kind) {} + help_source_kind_(help.kind), + def_kind_(flags_internal::FlagDefaultSrcKind::kGenFunc), + default_src_(default_value_gen) {} // Forces destruction of the Flag's data. void Destroy() const; // Constant access methods std::string Help() const; - bool IsModified() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu); - bool IsSpecifiedOnCommandLine() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu); - std::string DefaultValue() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu); - std::string CurrentValue() const ABSL_LOCKS_EXCLUDED(locks_->primary_mu); + bool IsModified() const ABSL_LOCKS_EXCLUDED(*DataGuard()); + bool IsSpecifiedOnCommandLine() const ABSL_LOCKS_EXCLUDED(*DataGuard()); + std::string DefaultValue() const ABSL_LOCKS_EXCLUDED(*DataGuard()); + std::string CurrentValue() const ABSL_LOCKS_EXCLUDED(*DataGuard()); void Read(const CommandLineFlag& flag, void* dst, const flags_internal::FlagOpFn dst_op) const - ABSL_LOCKS_EXCLUDED(locks_->primary_mu); + ABSL_LOCKS_EXCLUDED(*DataGuard()); // Attempts to parse supplied `value` std::string. bool TryParse(const CommandLineFlag& flag, void* dst, absl::string_view value, std::string* err) const - ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu); + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); template <typename T> bool AtomicGet(T* v) const { const int64_t r = atomic_.load(std::memory_order_acquire); @@ -174,23 +188,23 @@ class FlagImpl { // Mutating access methods void Write(const CommandLineFlag& flag, const void* src, const flags_internal::FlagOpFn src_op) - ABSL_LOCKS_EXCLUDED(locks_->primary_mu); + ABSL_LOCKS_EXCLUDED(*DataGuard()); bool SetFromString(const CommandLineFlag& flag, absl::string_view value, FlagSettingMode set_mode, ValueSource source, - std::string* err) ABSL_LOCKS_EXCLUDED(locks_->primary_mu); + std::string* err) ABSL_LOCKS_EXCLUDED(*DataGuard()); // If possible, updates copy of the Flag's value that is stored in an // atomic word. - void StoreAtomic() ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu); + void StoreAtomic() ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); // Interfaces to operate on callbacks. void SetCallback(const flags_internal::FlagCallback mutation_callback) - ABSL_LOCKS_EXCLUDED(locks_->primary_mu); - void InvokeCallback() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu); + ABSL_LOCKS_EXCLUDED(*DataGuard()); + void InvokeCallback() const ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); // Interfaces to save/restore mutable flag data template <typename T> std::unique_ptr<flags_internal::FlagStateInterface> SaveState( - Flag<T>* flag) const ABSL_LOCKS_EXCLUDED(locks_->primary_mu) { + Flag<T>* flag) const ABSL_LOCKS_EXCLUDED(*DataGuard()) { T&& cur_value = flag->Get(); absl::MutexLock l(DataGuard()); @@ -199,13 +213,13 @@ class FlagImpl { } bool RestoreState(const CommandLineFlag& flag, const void* value, bool modified, bool on_command_line, int64_t counter) - ABSL_LOCKS_EXCLUDED(locks_->primary_mu); + ABSL_LOCKS_EXCLUDED(*DataGuard()); // Value validation interfaces. void CheckDefaultValueParsingRoundtrip(const CommandLineFlag& flag) const - ABSL_LOCKS_EXCLUDED(locks_->primary_mu); + ABSL_LOCKS_EXCLUDED(*DataGuard()); bool ValidateInputValue(absl::string_view value) const - ABSL_LOCKS_EXCLUDED(locks_->primary_mu); + ABSL_LOCKS_EXCLUDED(*DataGuard()); private: // Lazy initialization of the Flag's data. @@ -214,27 +228,36 @@ class FlagImpl { // and returns pointer to the mutex guarding flags data. absl::Mutex* DataGuard() const ABSL_LOCK_RETURNED(locks_->primary_mu); + // Returns heap allocated value of type T initialized with default value. + std::unique_ptr<void, DynValueDeleter> MakeInitValue() const + ABSL_EXCLUSIVE_LOCKS_REQUIRED(*DataGuard()); + // Immutable Flag's data. - const FlagOpFn op_; // Type-specific handler. - const FlagMarshallingOpFn marshalling_op_; // Marshalling ops handler. - const InitialValGenFunc initial_value_gen_; // Makes flag's initial value. + const FlagOpFn op_; // Type-specific handler. + const FlagMarshallingOpFn marshalling_op_; // Marshalling ops handler. const FlagHelpSrc help_; // Help message literal or function to generate it. // Indicates if help message was supplied as literal or generator func. const FlagHelpSrcKind help_source_kind_; - // Mutable Flag's data. (guarded by locks_->primary_mu). - // Indicates that locks_, cur_ and def_ fields have been lazily initialized. + // Mutable Flag's data. (guarded by DataGuard()). + // Indicates that locks_ and cur_ fields have been lazily initialized. std::atomic<bool> inited_{false}; // Has flag value been modified? - bool modified_ ABSL_GUARDED_BY(locks_->primary_mu) = false; + bool modified_ ABSL_GUARDED_BY(*DataGuard()) = false; // Specified on command line. - bool on_command_line_ ABSL_GUARDED_BY(locks_->primary_mu) = false; - // Lazily initialized pointer to default value - void* def_ ABSL_GUARDED_BY(locks_->primary_mu) = nullptr; + bool on_command_line_ ABSL_GUARDED_BY(*DataGuard()) = false; + // If def_kind_ == kDynamicValue, default_src_ holds a dynamically allocated + // value. + FlagDefaultSrcKind def_kind_ ABSL_GUARDED_BY(*DataGuard()); + // Either a pointer to the function generating the default value based on the + // value specified in ABSL_FLAG or pointer to the dynamically set default + // value via SetCommandLineOptionWithMode. def_kind_ is used to distinguish + // these two cases. + FlagDefaultSrc default_src_ ABSL_GUARDED_BY(*DataGuard()); // Lazily initialized pointer to current value - void* cur_ ABSL_GUARDED_BY(locks_->primary_mu) = nullptr; + void* cur_ ABSL_GUARDED_BY(*DataGuard()) = nullptr; // Mutation counter - int64_t counter_ ABSL_GUARDED_BY(locks_->primary_mu) = 0; + int64_t counter_ ABSL_GUARDED_BY(*DataGuard()) = 0; // For some types, a copy of the current value is kept in an atomically // accessible field. std::atomic<int64_t> atomic_{flags_internal::AtomicInit()}; @@ -263,7 +286,7 @@ class Flag final : public flags_internal::CommandLineFlag { constexpr Flag(const char* name, const flags_internal::HelpInitArg help, const char* filename, const flags_internal::FlagMarshallingOpFn marshalling_op, - const flags_internal::InitialValGenFunc initial_value_gen) + const flags_internal::FlagDfltGenFunc initial_value_gen) : flags_internal::CommandLineFlag(name, filename), impl_(&flags_internal::FlagOps<T>, marshalling_op, initial_value_gen, help) {} |