about summary refs log tree commit diff
path: root/absl/synchronization/lifetime_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'absl/synchronization/lifetime_test.cc')
-rw-r--r--absl/synchronization/lifetime_test.cc48
1 files changed, 48 insertions, 0 deletions
diff --git a/absl/synchronization/lifetime_test.cc b/absl/synchronization/lifetime_test.cc
index b7360c29016b..8b168e21a316 100644
--- a/absl/synchronization/lifetime_test.cc
+++ b/absl/synchronization/lifetime_test.cc
@@ -17,6 +17,7 @@
 #include <type_traits>
 
 #include "absl/base/attributes.h"
+#include "absl/base/const_init.h"
 #include "absl/base/internal/raw_logging.h"
 #include "absl/base/thread_annotations.h"
 #include "absl/synchronization/mutex.h"
@@ -95,6 +96,10 @@ void TestLocals() {
   RunTests(&mutex, &condvar);
 }
 
+// Normal kConstInit usage
+ABSL_CONST_INIT absl::Mutex const_init_mutex(absl::kConstInit);
+void TestConstInitGlobal() { RunTests(&const_init_mutex, nullptr); }
+
 // Global variables during start and termination
 //
 // In a translation unit, static storage duration variables are initialized in
@@ -117,10 +122,53 @@ class OnDestruction {
   Function fn_;
 };
 
+// kConstInit
+// Test early usage.  (Declaration comes first; definitions must appear after
+// the test runner.)
+extern absl::Mutex early_const_init_mutex;
+// (Normally I'd write this +[], to make the cast-to-function-pointer explicit,
+// but in some MSVC setups we support, lambdas provide conversion operators to
+// different flavors of function pointers, making this trick ambiguous.)
+OnConstruction test_early_const_init([] {
+  RunTests(&early_const_init_mutex, nullptr);
+});
+// This definition appears before test_early_const_init, but it should be
+// initialized first (due to constant initialization).  Test that the object
+// actually works when constructed this way.
+ABSL_CONST_INIT absl::Mutex early_const_init_mutex(absl::kConstInit);
+
+// Furthermore, test that the const-init c'tor doesn't stomp over the state of
+// a Mutex.  Really, this is a test that the platform under test correctly
+// supports C++11 constant initialization.  (The constant-initialization
+// constructors of globals "happen at link time"; memory is pre-initialized,
+// before the constructors of either grab_lock or check_still_locked are run.)
+extern absl::Mutex const_init_sanity_mutex;
+OnConstruction grab_lock([]() NO_THREAD_SAFETY_ANALYSIS {
+  const_init_sanity_mutex.Lock();
+});
+ABSL_CONST_INIT absl::Mutex const_init_sanity_mutex(absl::kConstInit);
+OnConstruction check_still_locked([]() NO_THREAD_SAFETY_ANALYSIS {
+  const_init_sanity_mutex.AssertHeld();
+  const_init_sanity_mutex.Unlock();
+});
+
+// Test shutdown usage.  (Declarations come first; definitions must appear after
+// the test runner.)
+extern absl::Mutex late_const_init_mutex;
+// OnDestruction is being used here as a global variable, even though it has a
+// non-trivial destructor.  This is against the style guide.  We're violating
+// that rule here to check that the exception we allow for kConstInit is safe.
+// NOLINTNEXTLINE
+OnDestruction test_late_const_init([] {
+  RunTests(&late_const_init_mutex, nullptr);
+});
+ABSL_CONST_INIT absl::Mutex late_const_init_mutex(absl::kConstInit);
+
 }  // namespace
 
 int main() {
   TestLocals();
+  TestConstInitGlobal();
   // Explicitly call exit(0) here, to make it clear that we intend for the
   // above global object destructors to run.
   std::exit(0);