about summary refs log tree commit diff
path: root/absl/flags
diff options
context:
space:
mode:
authorAbseil Team <absl-team@google.com>2019-10-16T01·18-0700
committerAndy Soffer <asoffer@google.com>2019-10-16T14·42-0400
commitab3552a18964e7063c8324f45b3896a6a20b08a8 (patch)
tree74c2403dae6781ebdc1932fc0bddcc4193aa131e /absl/flags
parente9f9000c7c80993cb589d011616b7a8016e42f4a (diff)
Export of internal Abseil changes
--
f13697e3d33803f9667d124072da4f6dd8bfbf85 by Andy Soffer <asoffer@google.com>:

Addressing https://github.com/abseil/abseil-cpp/issues/314, fixing
CMakeLists.txt to reference ABSL_TEST_COPTS rather than ABSL_DEFAULT_COPTS.

ABSL_TEST_COPTS should be preferred for all tests so that they are configured consistently (moreover, CMake should agree with Bazel).

PiperOrigin-RevId: 274932312

--
c31c24a1fa6bb98136adf51ef37c0818ac366690 by Derek Mauro <dmauro@google.com>:

Silence MSAN in the stack consumption test utility

PiperOrigin-RevId: 274912950

--
2412913c05a246cd527cd4c31452f126e9129f3a by CJ Johnson <johnsoncj@google.com>:

Internal change

PiperOrigin-RevId: 274847103

--
75e984a93b5760873501b96ac3229ccfd955daf8 by Abseil Team <absl-team@google.com>:

Reformat BUILD file to current standards.

PiperOrigin-RevId: 274815392

--
a2780e085f1df1e4ca2c814a58c893d1b78a1d9c by Samuel Benzaquen <sbenza@google.com>:

Fix invalid result regarding leading zeros in the exponent.

PiperOrigin-RevId: 274808017

--
dd402e1cb5c4ebacb576372ae24bf289d729d323 by Samuel Benzaquen <sbenza@google.com>:

Make string_view's relational operators constexpr when possible.

PiperOrigin-RevId: 274807873

--
b4ef32565653a5da1cb8bb8d0351586d23519658 by Abseil Team <absl-team@google.com>:

Internal rework.

PiperOrigin-RevId: 274787159

--
70d81971c5914e6785b8e8a9d4f6eb2655dd62c0 by Gennadiy Rozental <rogeeff@google.com>:

Internal rework.

PiperOrigin-RevId: 274715557

--
14f5b0440e353b899cafaaa15b53e77f98f401af by Gennadiy Rozental <rogeeff@google.com>:

Make deprecated statements about ParseFLag/UnparseFlag consistent in a file.

PiperOrigin-RevId: 274668123

--
2e85adbdbb92612e4d750bc34fbca3333128b42d by Abseil Team <absl-team@google.com>:

Allow absl::c_equal to be used with arrays.

This is achieved by allowing container size computation for arrays.

PiperOrigin-RevId: 274426830

--
219719f107226d328773e6cec99fb473f5d3119c by Gennadiy Rozental <rogeeff@google.com>:

Release correct extension interfaces to support usage of absl::Time and absl::Duration as ABSL_FLAG

PiperOrigin-RevId: 274273788

--
47a77f93fda23b69b4a6bdbd506fe643c69a5579 by Gennadiy Rozental <rogeeff@google.com>:

Rework of flags persistence/FlagSaver internals.

PiperOrigin-RevId: 274225213

--
7807be3fe757c19e3b0c487298387683d4c9f5b3 by Abseil Team <absl-team@google.com>:

Switch reference to sdkddkver.h to lowercase, matching conventions used in the Windows SDK and other uses. This helps to avoid confusion on case-sensitive filesystems.

PiperOrigin-RevId: 274061877

--
561304090087a19f1d10f0475f564fe132ebf06e by Andy Getzendanner <durandal@google.com>:

Fix ABSL_WAITER_MODE detection for mingw

Import of https://github.com/abseil/abseil-cpp/pull/342

PiperOrigin-RevId: 274030071

--
9b3caac2cf202b9d440dfa1b4ffd538ac4bf715b by Derek Mauro <dmauro@google.com>:

Support using Abseil with the musl libc implementation.

Only test changes were required:
  * Workaround for a bug in sigaltstack() on musl
  * printf-style pointer formatting (%p) is implementation defined,
    so verify StrFromat produces something compatible
  * Fix detection of feenableexcept()

PiperOrigin-RevId: 274011666

--
73e8a938fc139e1cc8670d4513a445bacc855539 by Abseil Team <absl-team@google.com>:

nvcc workaround: explicitly specify the definition of node_handle::Base

PiperOrigin-RevId: 274011392

--
ab9cc6d042aca7d48e16c504ab10eab39433f4b2 by Andy Soffer <asoffer@google.com>:

Internal change

PiperOrigin-RevId: 273996318

--
e567c4979ca99c7e71821ec1523b8f5edd2c76ac by Abseil Team <absl-team@google.com>:

Introduce a type alias to work around an nvcc bug.

On the previous code, nvcc gets confused thinking that T has to be a parameter
pack, as IsDecomposable accepts one.

PiperOrigin-RevId: 273980472

--
105b6e6339b77a32f4432de05f44cd3f9c436751 by Eric Fiselier <ericwf@google.com>:

Import of CCTZ from GitHub.

PiperOrigin-RevId: 273955589

--
8feb87ff1d7e721fe094855e67c19539d5e582b7 by Abseil Team <absl-team@google.com>:

Avoid dual-exporting scheduling_mode.h

PiperOrigin-RevId: 273825112

--
fbc37854776d295dae98fb9d06a541f296daab95 by Andy Getzendanner <durandal@google.com>:

Fix ABSL_HAVE_ALARM check on mingw

Import of https://github.com/abseil/abseil-cpp/pull/341

PiperOrigin-RevId: 273817839

--
6aedcd63a735b9133e143b043744ba0a25407f6f by Andy Soffer <asoffer@google.com>:

Remove bit_gen_view.h now that all callers have been migrated to bit_gen_ref.h
Tested:
TGP - https://test.corp.google.com/ui#id=OCL:273762409:BASE:273743370:1570639020744:3001bcb5

PiperOrigin-RevId: 273810331

--
6573de24a66ba715c579f7f32b5c48a1d743c7f8 by Abseil Team <absl-team@google.com>:

Internal change.

PiperOrigin-RevId: 273589963

--
91c8c28b6dca26d98b39e8e06a8ed17c701ff793 by Abseil Team <absl-team@google.com>:

Update macro name for `ABSL_GUARDED_BY()` in the example section.

PiperOrigin-RevId: 273286983

--
0ff7d1a93d70f8ecd693f8dbb98b7a4a016ca2a4 by Abseil Team <absl-team@google.com>:

Fix potential integer overflow in the absl time library.

In absl::FromTM, the tm.tm_year is added by 1900 regarding that tm.tm_year represents the years since 1900. This change checks integer overflow before doing the arithmetic operation.

PiperOrigin-RevId: 273092952

--
b41c2a1310086807be09a833099ae6d4009f037c by Gennadiy Rozental <rogeeff@google.com>:

Correctly Unlock the global mutex in case of concurrent flag initialization.

Fixes #386

PiperOrigin-RevId: 272979749

--
c53103e71b2a6063af3c6d4ff68aa2d8f9ae9e06 by Abseil Team <absl-team@google.com>:

Try to become idle only when there is no wakeup.

Immediately after waking up (when futex wait returns), the current thread tries
to become idle doing bunch of memory loads and a branch.  Problem is that there
is a good chance that we woke up due to a wakeup, especially for actively used
threads.  For such wakeups, calling MaybeBecomeIdle() would be a waste of
cycles.

Instead, call MaybeBecomeIdle() only when we are sure there is no wakeup.  For
idle threads the net effect should be the same.  For active, threads this will
be more efficient.

Moreover, since MaybeBecomeIdle() is called before waiting on the futex, the
current thread will try to become idle before sleeping.  This should result
in more accurate idleness and more efficient release of thread resources.

PiperOrigin-RevId: 272940381
GitOrigin-RevId: f13697e3d33803f9667d124072da4f6dd8bfbf85
Change-Id: I36de05aec12595183725652dd362dfa58fb095d0
Diffstat (limited to 'absl/flags')
-rw-r--r--absl/flags/BUILD.bazel3
-rw-r--r--absl/flags/flag.cc4
-rw-r--r--absl/flags/flag.h8
-rw-r--r--absl/flags/internal/commandlineflag.cc6
-rw-r--r--absl/flags/internal/commandlineflag.h24
-rw-r--r--absl/flags/internal/flag.h85
-rw-r--r--absl/flags/internal/registry.cc106
7 files changed, 124 insertions, 112 deletions
diff --git a/absl/flags/BUILD.bazel b/absl/flags/BUILD.bazel
index 2bf562f898c7..2e0dc3891f56 100644
--- a/absl/flags/BUILD.bazel
+++ b/absl/flags/BUILD.bazel
@@ -40,6 +40,8 @@ cc_library(
     deps = [
         ":handle",
         ":registry",
+        "//absl/memory",
+        "//absl/strings",
         "//absl/synchronization",
     ],
 )
@@ -184,6 +186,7 @@ cc_library(
         ":marshalling",
         "//absl/base",
         "//absl/base:core_headers",
+        "//absl/memory",
         "//absl/strings",
     ],
 )
diff --git a/absl/flags/flag.cc b/absl/flags/flag.cc
index a02d069e9b00..69038bbf48a0 100644
--- a/absl/flags/flag.cc
+++ b/absl/flags/flag.cc
@@ -49,9 +49,7 @@ namespace flags_internal {
 
 ABSL_CONST_INIT static absl::Mutex construction_guard(absl::kConstInit);
 
-void LockGlobalConstructionGuard() { construction_guard.Lock(); }
-
-void UnlockGlobalConstructionGuard() { construction_guard.Unlock(); }
+absl::Mutex* GetGlobalConstructionGuard() { return &construction_guard; }
 
 }  // namespace flags_internal
 
diff --git a/absl/flags/flag.h b/absl/flags/flag.h
index 86ad59dd9f16..4927757b8fbe 100644
--- a/absl/flags/flag.h
+++ b/absl/flags/flag.h
@@ -80,8 +80,7 @@ using Flag = flags_internal::Flag<T>;
 // if two threads attempt to construct the flag concurrently only one wins.
 
 namespace flags_internal {
-void LockGlobalConstructionGuard();
-void UnlockGlobalConstructionGuard();
+absl::Mutex* GetGlobalConstructionGuard();
 }  // namespace flags_internal
 
 template <typename T>
@@ -100,7 +99,7 @@ class Flag {
 
   flags_internal::Flag<T>* GetImpl() const {
     if (!inited_.load(std::memory_order_acquire)) {
-      flags_internal::LockGlobalConstructionGuard();
+      absl::MutexLock l(flags_internal::GetGlobalConstructionGuard());
 
       if (inited_.load(std::memory_order_acquire)) {
         return impl_;
@@ -109,8 +108,6 @@ class Flag {
       impl_ = new flags_internal::Flag<T>(name_, help_gen_, filename_,
                                           marshalling_op_, initial_value_gen_);
       inited_.store(true, std::memory_order_release);
-
-      flags_internal::UnlockGlobalConstructionGuard();
     }
 
     return impl_;
@@ -130,7 +127,6 @@ class Flag {
   std::string Filename() const { return GetImpl()->Filename(); }
   std::string DefaultValue() const { return GetImpl()->DefaultValue(); }
   std::string CurrentValue() const { return GetImpl()->CurrentValue(); }
-  bool HasValidatorFn() const { return GetImpl()->HasValidatorFn(); }
   bool InvokeValidator(const void* value) const {
     return GetImpl()->InvokeValidator(value);
   }
diff --git a/absl/flags/internal/commandlineflag.cc b/absl/flags/internal/commandlineflag.cc
index 53e2b84ecc13..99f73611d8f1 100644
--- a/absl/flags/internal/commandlineflag.cc
+++ b/absl/flags/internal/commandlineflag.cc
@@ -149,6 +149,12 @@ std::string CommandLineFlag::CurrentValue() const {
   return Unparse(marshalling_op_, cur_);
 }
 
+int64_t CommandLineFlag::MutationCounter() const {
+  absl::MutexLock l(InitFlagIfNecessary());
+
+  return counter_;
+}
+
 // Attempts to parse supplied `value` string using parsing routine in the `flag`
 // argument. If parsing is successful, it will try to validate that the parsed
 // value is valid for the specified 'flag'. Finally this function stores the
diff --git a/absl/flags/internal/commandlineflag.h b/absl/flags/internal/commandlineflag.h
index 284286b6be18..528d3106bfa8 100644
--- a/absl/flags/internal/commandlineflag.h
+++ b/absl/flags/internal/commandlineflag.h
@@ -17,6 +17,7 @@
 #define ABSL_FLAGS_INTERNAL_COMMANDLINEFLAG_H_
 
 #include <atomic>
+#include <memory>
 
 #include "absl/base/macros.h"
 #include "absl/flags/marshalling.h"
@@ -186,6 +187,16 @@ class HelpText {
   const char* help_message_;
 };
 
+// Handle to FlagState objects. Specific flag state objects will restore state
+// of a flag produced this flag state from method CommandLineFlag::SaveState().
+class FlagStateInterface {
+ public:
+  virtual ~FlagStateInterface() {}
+
+  // Restores the flag originated this object to the saved state.
+  virtual void Restore() const = 0;
+};
+
 // Holds all information for a flag.
 class CommandLineFlag {
  public:
@@ -239,7 +250,6 @@ class CommandLineFlag {
   virtual void StoreAtomic() {}
 
   // Interfaces to operate on validators.
-  virtual bool HasValidatorFn() const { return false; }
   virtual bool InvokeValidator(const void* /*value*/) const { return true; }
   // Invoke the flag validators for old flags.
   // TODO(rogeeff): implement proper validators for Abseil Flags
@@ -264,6 +274,10 @@ class CommandLineFlag {
     return res;
   }
 
+  // Interface to save flag to some persistent state. Returns current flag state
+  // or nullptr if flag does not support saving and restoring a state.
+  virtual std::unique_ptr<FlagStateInterface> SaveState() = 0;
+
   // Interfaces to overate on callbacks.
   virtual void InvokeCallback() {}
 
@@ -285,6 +299,9 @@ class CommandLineFlag {
  protected:
   ~CommandLineFlag() = default;
 
+  // Thread safe access to mutation counter.
+  int64_t MutationCounter() const;
+
   const char* const name_;
   const HelpText help_;
   const char* const filename_;
@@ -323,11 +340,6 @@ class CommandLineFlag {
   friend bool TryParseLocked(CommandLineFlag* flag, void* dst,
                              absl::string_view value, std::string* err);
   friend absl::Mutex* InitFlag(CommandLineFlag* flag);
-
-  // This is a short term, until we completely rework persistent state
-  // storage API.
-  virtual void* GetValidator() const { return nullptr; }
-  virtual bool SetValidator(void*) { return false; }
 };
 
 // Update any copy of the flag value that is stored in an atomic word.
diff --git a/absl/flags/internal/flag.h b/absl/flags/internal/flag.h
index 16330380f548..2b21c4407363 100644
--- a/absl/flags/internal/flag.h
+++ b/absl/flags/internal/flag.h
@@ -20,12 +20,44 @@
 
 #include "absl/flags/internal/commandlineflag.h"
 #include "absl/flags/internal/registry.h"
+#include "absl/memory/memory.h"
+#include "absl/strings/str_cat.h"
 
 namespace absl {
 namespace flags_internal {
 
 constexpr int64_t AtomicInit() { return 0xababababababababll; }
 
+template <typename T>
+class Flag;
+
+template <typename T>
+class FlagState : public flags_internal::FlagStateInterface {
+ public:
+  FlagState(Flag<T>* flag, T&& cur, bool modified, bool on_command_line,
+            int64_t counter)
+      : flag_(flag),
+        cur_value_(std::move(cur)),
+        modified_(modified),
+        on_command_line_(on_command_line),
+        counter_(counter) {}
+
+  ~FlagState() override = default;
+
+ private:
+  friend class Flag<T>;
+
+  // Restores the flag to the saved state.
+  void Restore() const override;
+
+  // Flag and saved flag data.
+  Flag<T>* flag_;
+  T cur_value_;
+  bool modified_;
+  bool on_command_line_;
+  int64_t counter_;
+};
+
 // Signature for the mutation callback used by watched Flags
 // The callback is noexcept.
 // TODO(rogeeff): add noexcept after C++17 support is added.
@@ -98,15 +130,12 @@ class Flag final : public flags_internal::CommandLineFlag {
 
     InvokeCallback();
   }
-  void InvokeCallback() override
-      ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
-    flags_internal::InvokeCallback(&locks_->primary_mu, &locks_->callback_mu,
-                                   callback_);
-  }
 
  private:
+  friend class FlagState<T>;
+
   void Destroy() const override {
-    // Values are heap allocated Abseil Flags.
+    // Values are heap allocated for Abseil Flags.
     if (cur_) Delete(op_, cur_);
     if (def_) Delete(op_, def_);
 
@@ -121,6 +150,41 @@ class Flag final : public flags_internal::CommandLineFlag {
     }
   }
 
+  // Interfaces to save and restore flags to/from persistent state.
+  // Returns current flag state or nullptr if flag does not support
+  // saving and restoring a state.
+  std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
+    T curr_value = Get();
+
+    absl::MutexLock l(InitFlagIfNecessary());
+
+    return absl::make_unique<flags_internal::FlagState<T>>(
+        this, std::move(curr_value), modified_, on_command_line_, counter_);
+  }
+
+  // Restores the flag state to the supplied state object. If there is
+  // nothing to restore returns false. Otherwise returns true.
+  bool RestoreState(const flags_internal::FlagState<T>& flag_state) {
+    if (MutationCounter() == flag_state.counter_) return false;
+
+    Set(flag_state.cur_value_);
+
+    // Race condition here? This should disappear once we move the rest of the
+    // flag's data into Flag's internals.
+
+    absl::MutexLock l(InitFlagIfNecessary());
+    modified_ = flag_state.modified_;
+    on_command_line_ = flag_state.on_command_line_;
+    return true;
+  }
+
+  // Interfaces to overate on callbacks.
+  void InvokeCallback() override
+      ABSL_EXCLUSIVE_LOCKS_REQUIRED(locks_->primary_mu) {
+    flags_internal::InvokeCallback(&locks_->primary_mu, &locks_->callback_mu,
+                                   callback_);
+  }
+
   // Flag's data
   // For some types, a copy of the current value is kept in an atomically
   // accessible field.
@@ -128,6 +192,15 @@ class Flag final : public flags_internal::CommandLineFlag {
   FlagCallback callback_;  // Mutation callback
 };
 
+template <typename T>
+inline void FlagState<T>::Restore() const {
+  if (flag_->RestoreState(*this)) {
+    ABSL_INTERNAL_LOG(INFO,
+                      absl::StrCat("Restore saved value of ", flag_->Name(),
+                                   " to: ", flag_->CurrentValue()));
+  }
+}
+
 // This class facilitates Flag object registration and tail expression-based
 // flag definition, for example:
 // ABSL_FLAG(int, foo, 42, "Foo help").OnUpdate(NotifyFooWatcher);
diff --git a/absl/flags/internal/registry.cc b/absl/flags/internal/registry.cc
index 4bea313bb1eb..6b2564d13a78 100644
--- a/absl/flags/internal/registry.cc
+++ b/absl/flags/internal/registry.cc
@@ -188,114 +188,34 @@ CommandLineFlag* FlagRegistry::FindRetiredFlagLocked(absl::string_view name) {
 
 class FlagSaverImpl {
  public:
-  // Constructs an empty FlagSaverImpl object.
-  FlagSaverImpl() {}
-  ~FlagSaverImpl() {
-    // reclaim memory from each of our CommandLineFlags
-    for (const SavedFlag& src : backup_registry_) {
-      Delete(src.op, src.current);
-      Delete(src.op, src.default_value);
-    }
-  }
+  FlagSaverImpl() = default;
+  FlagSaverImpl(const FlagSaverImpl&) = delete;
+  void operator=(const FlagSaverImpl&) = delete;
 
   // Saves the flag states from the flag registry into this object.
   // It's an error to call this more than once.
-  // Must be called when the registry mutex is not held.
   void SaveFromRegistry() {
     assert(backup_registry_.empty());  // call only once!
-    SavedFlag saved;
     flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) {
-      if (flag->IsRetired()) return;
-
-      saved.name = flag->Name();
-      saved.op = flag->op_;
-      saved.marshalling_op = flag->marshalling_op_;
-      {
-        absl::MutexLock l(flag->InitFlagIfNecessary());
-        saved.validator = flag->GetValidator();
-        saved.modified = flag->modified_;
-        saved.on_command_line = flag->on_command_line_;
-        saved.current = Clone(saved.op, flag->cur_);
-        saved.default_value = Clone(saved.op, flag->def_);
-        saved.counter = flag->counter_;
+      if (auto flag_state = flag->SaveState()) {
+        backup_registry_.emplace_back(std::move(flag_state));
       }
-      backup_registry_.push_back(saved);
     });
   }
 
-  // Restores the saved flag states into the flag registry.  We
-  // assume no flags were added or deleted from the registry since
-  // the SaveFromRegistry; if they were, that's trouble!  Must be
-  // called when the registry mutex is not held.
+  // Restores the saved flag states into the flag registry.
   void RestoreToRegistry() {
-    FlagRegistry* const global_registry = FlagRegistry::GlobalRegistry();
-    FlagRegistryLock frl(global_registry);
-    for (const SavedFlag& src : backup_registry_) {
-      CommandLineFlag* flag = global_registry->FindFlagLocked(src.name);
-      // If null, flag got deleted from registry.
-      if (!flag) continue;
-
-      bool restored = false;
-      {
-        // This function encapsulate the lock.
-        flag->SetValidator(src.validator);
-
-        absl::MutexLock l(flag->InitFlagIfNecessary());
-        flag->modified_ = src.modified;
-        flag->on_command_line_ = src.on_command_line;
-        if (flag->counter_ != src.counter ||
-            ChangedDirectly(flag, src.default_value, flag->def_)) {
-          restored = true;
-          Copy(src.op, src.default_value, flag->def_);
-        }
-        if (flag->counter_ != src.counter ||
-            ChangedDirectly(flag, src.current, flag->cur_)) {
-          restored = true;
-          Copy(src.op, src.current, flag->cur_);
-          UpdateCopy(flag);
-          flag->InvokeCallback();
-        }
-      }
-
-      if (restored) {
-        flag->counter_++;
-
-        // Revalidate the flag because the validator might store state based
-        // on the flag's value, which just changed due to the restore.
-        // Failing validation is ignored because it's assumed that the flag
-        // was valid previously and there's little that can be done about it
-        // here, anyway.
-        flag->ValidateInputValue(flag->CurrentValue());
-
-        ABSL_INTERNAL_LOG(
-            INFO, absl::StrCat("Restore saved value of ", flag->Name(), ": ",
-                               Unparse(src.marshalling_op, src.current)));
-      }
+    for (const auto& flag_state : backup_registry_) {
+      flag_state->Restore();
     }
   }
 
  private:
-  struct SavedFlag {
-    absl::string_view name;
-    FlagOpFn op;
-    FlagMarshallingOpFn marshalling_op;
-    int64_t counter;
-    void* validator;
-    bool modified;
-    bool on_command_line;
-    const void* current;        // nullptr after restore
-    const void* default_value;  // nullptr after restore
-  };
-
-  std::vector<SavedFlag> backup_registry_;
-
-  FlagSaverImpl(const FlagSaverImpl&);  // no copying!
-  void operator=(const FlagSaverImpl&);
+  std::vector<std::unique_ptr<flags_internal::FlagStateInterface>>
+      backup_registry_;
 };
 
-FlagSaver::FlagSaver() : impl_(new FlagSaverImpl()) {
-  impl_->SaveFromRegistry();
-}
+FlagSaver::FlagSaver() : impl_(new FlagSaverImpl) { impl_->SaveFromRegistry(); }
 
 void FlagSaver::Ignore() {
   delete impl_;
@@ -376,6 +296,10 @@ class RetiredFlagObj final : public flags_internal::CommandLineFlag {
 
     delete this;
   }
+
+  std::unique_ptr<flags_internal::FlagStateInterface> SaveState() override {
+    return nullptr;
+  }
 };
 
 }  // namespace