about summary refs log tree commit diff
path: root/absl/synchronization
diff options
context:
space:
mode:
Diffstat (limited to 'absl/synchronization')
-rw-r--r--absl/synchronization/CMakeLists.txt268
-rw-r--r--absl/synchronization/internal/mutex_nonprod.inc3
-rw-r--r--absl/synchronization/lifetime_test.cc48
-rw-r--r--absl/synchronization/mutex.h22
4 files changed, 227 insertions, 114 deletions
diff --git a/absl/synchronization/CMakeLists.txt b/absl/synchronization/CMakeLists.txt
index de0d7b7d4500..cb77b685647f 100644
--- a/absl/synchronization/CMakeLists.txt
+++ b/absl/synchronization/CMakeLists.txt
@@ -14,142 +14,182 @@
 # limitations under the License.
 #
 
-list(APPEND SYNCHRONIZATION_PUBLIC_HEADERS
-  "barrier.h"
-  "blocking_counter.h"
-  "mutex.h"
-  "notification.h"
+absl_cc_library(
+  NAME
+    graphcycles_internal
+  HDRS
+    "internal/graphcycles.h"
+  SRCS
+    "internal/graphcycles.cc"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::base
+    absl::base_internal
+    absl::core_headers
+    absl::malloc_internal
 )
 
-
-list(APPEND SYNCHRONIZATION_INTERNAL_HEADERS
-  "internal/create_thread_identity.h"
-  "internal/graphcycles.h"
-  "internal/kernel_timeout.h"
-  "internal/per_thread_sem.h"
-  "internal/thread_pool.h"
-  "internal/waiter.h"
-)
-
-
-
-# synchronization library
-list(APPEND SYNCHRONIZATION_SRC
-  "barrier.cc"
-  "blocking_counter.cc"
-  "internal/create_thread_identity.cc"
-  "internal/per_thread_sem.cc"
-  "internal/waiter.cc"
-  "internal/graphcycles.cc"
-  "notification.cc"
-  "mutex.cc"
-)
-
-set(SYNCHRONIZATION_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::symbolize absl::time)
-
-absl_library(
-  TARGET
-    absl_synchronization
-  SOURCES
-    ${SYNCHRONIZATION_SRC}
-  PUBLIC_LIBRARIES
-    ${SYNCHRONIZATION_PUBLIC_LIBRARIES}
-  EXPORT_NAME
+absl_cc_library(
+  NAME
     synchronization
+  HDRS
+    "barrier.h"
+    "blocking_counter.h"
+    "internal/create_thread_identity.h"
+    "internal/kernel_timeout.h"
+    "internal/mutex_nonprod.inc"
+    "internal/per_thread_sem.h"
+    "internal/waiter.h"
+    "mutex.h"
+    "notification.h"
+  SRCS
+    "barrier.cc"
+    "blocking_counter.cc"
+    "internal/create_thread_identity.cc"
+    "internal/per_thread_sem.cc"
+    "internal/waiter.cc"
+    "notification.cc"
+    "mutex.cc"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::graphcycles_internal
+    absl::base
+    absl::base_internal
+    absl::config
+    absl::core_headers
+    absl::dynamic_annotations
+    absl::malloc_internal
+    absl::stacktrace
+    absl::symbolize
+    absl::time
+  PUBLIC
 )
 
-
-#
-## TESTS
-#
-
-
-# test barrier_test
-set(BARRIER_TEST_SRC "barrier_test.cc")
-set(BARRIER_TEST_PUBLIC_LIBRARIES absl::synchronization)
-
-absl_test(
-  TARGET
+absl_cc_test(
+  NAME
     barrier_test
-  SOURCES
-    ${BARRIER_TEST_SRC}
-  PUBLIC_LIBRARIES
-    ${BARRIER_TEST_PUBLIC_LIBRARIES}
+  SRCS
+    "barrier_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::synchronization
+    absl::time
+    gmock_main
 )
 
-
-# test blocking_counter_test
-set(BLOCKING_COUNTER_TEST_SRC "blocking_counter_test.cc")
-set(BLOCKING_COUNTER_TEST_PUBLIC_LIBRARIES absl::synchronization)
-
-absl_test(
-  TARGET
+absl_cc_test(
+  NAME
     blocking_counter_test
-  SOURCES
-    ${BLOCKING_COUNTER_TEST_SRC}
-  PUBLIC_LIBRARIES
-    ${BLOCKING_COUNTER_TEST_PUBLIC_LIBRARIES}
+  SRCS
+    "blocking_counter_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::synchronization
+    absl::time
+    gmock_main
 )
 
-
-# test graphcycles_test
-set(GRAPHCYCLES_TEST_SRC "internal/graphcycles_test.cc")
-set(GRAPHCYCLES_TEST_PUBLIC_LIBRARIES absl::synchronization)
-
-absl_test(
-  TARGET
+absl_cc_test(
+  NAME
     graphcycles_test
-  SOURCES
-    ${GRAPHCYCLES_TEST_SRC}
-  PUBLIC_LIBRARIES
-    ${GRAPHCYCLES_TEST_PUBLIC_LIBRARIES}
+  SRCS
+    "internal/graphcycles_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::graphcycles_internal
+    absl::base
+    absl::core_headers
+    gmock_main
 )
 
+absl_cc_library(
+  NAME
+    thread_pool
+  HDRS
+    "internal/thread_pool.h"
+  DEPS
+    absl::synchronization
+    absl::core_headers
+  TESTONLY
+)
 
-# test mutex_test
-set(MUTEX_TEST_SRC "mutex_test.cc")
-set(MUTEX_TEST_PUBLIC_LIBRARIES absl::synchronization)
-
-absl_test(
-  TARGET
+absl_cc_test(
+  NAME
     mutex_test
-  SOURCES
-    ${MUTEX_TEST_SRC}
-  PUBLIC_LIBRARIES
-    ${MUTEX_TEST_PUBLIC_LIBRARIES}
+  SRCS
+    "mutex_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::synchronization
+    absl::thread_pool
+    absl::base
+    absl::core_headers
+    absl::memory
+    absl::time
+    gmock_main
 )
 
-
-# test notification_test
-set(NOTIFICATION_TEST_SRC "notification_test.cc")
-set(NOTIFICATION_TEST_PUBLIC_LIBRARIES absl::synchronization)
-
-absl_test(
-  TARGET
+absl_cc_test(
+  NAME
     notification_test
-  SOURCES
-    ${NOTIFICATION_TEST_SRC}
-  PUBLIC_LIBRARIES
-    ${NOTIFICATION_TEST_PUBLIC_LIBRARIES}
+  SRCS
+    "notification_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::synchronization
+    absl::time
+    gmock_main
 )
 
-
-# test per_thread_sem_test_common
-set(PER_THREAD_SEM_TEST_COMMON_SRC "internal/per_thread_sem_test.cc")
-set(PER_THREAD_SEM_TEST_COMMON_PUBLIC_LIBRARIES absl::synchronization absl::strings)
-
-absl_test(
-  TARGET
+absl_cc_library(
+  NAME
     per_thread_sem_test_common
-  SOURCES
-    ${PER_THREAD_SEM_TEST_COMMON_SRC}
-  PUBLIC_LIBRARIES
-    ${PER_THREAD_SEM_TEST_COMMON_PUBLIC_LIBRARIES}
+  SRCS
+    "internal/per_thread_sem_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::synchronization
+    absl::base
+    absl::strings
+    absl::time
+    gmock
+  TESTONLY
 )
 
+absl_cc_test(
+  NAME
+    per_thread_sem_test
+  SRCS
+    "internal/per_thread_sem_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::per_thread_sem_test_common
+    absl::synchronization
+    absl::base
+    absl::strings
+    absl::time
+    gmock_main
+)
 
-
-
-
-
-
+absl_cc_test(
+  NAME
+    lifetime_test
+  SRCS
+    "lifetime_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::synchronization
+    absl::base
+    absl::core_headers
+    Threads::Threads
+)
diff --git a/absl/synchronization/internal/mutex_nonprod.inc b/absl/synchronization/internal/mutex_nonprod.inc
index 0aab3d1314e6..b8d5af79ad38 100644
--- a/absl/synchronization/internal/mutex_nonprod.inc
+++ b/absl/synchronization/internal/mutex_nonprod.inc
@@ -214,6 +214,9 @@ class SynchronizationStorage {
   // stack) should use this constructor.
   explicit SynchronizationStorage(base_internal::LinkerInitialized) {}
 
+  constexpr explicit SynchronizationStorage(absl::ConstInitType)
+      : is_dynamic_(false), once_(), space_{{0}} {}
+
   SynchronizationStorage(SynchronizationStorage&) = delete;
   SynchronizationStorage& operator=(SynchronizationStorage&) = delete;
 
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);
diff --git a/absl/synchronization/mutex.h b/absl/synchronization/mutex.h
index aeef3c95978c..4b65e92cb3d0 100644
--- a/absl/synchronization/mutex.h
+++ b/absl/synchronization/mutex.h
@@ -61,6 +61,7 @@
 #include <cstdint>
 #include <string>
 
+#include "absl/base/const_init.h"
 #include "absl/base/internal/identity.h"
 #include "absl/base/internal/low_level_alloc.h"
 #include "absl/base/internal/thread_identity.h"
@@ -136,7 +137,26 @@ struct SynchWaitParams;
 
 class LOCKABLE Mutex {
  public:
+  // Creates a `Mutex` that is not held by anyone. This constructor is
+  // typically used for Mutexes allocated on the heap or the stack.
+  //
+  // To create `Mutex` instances with static storage duration
+  // (e.g. a namespace-scoped or global variable), see
+  // `Mutex::Mutex(absl::kConstInit)` below instead.
   Mutex();
+
+  // Creates a mutex with static storage duration.  A global variable
+  // constructed this way avoids the lifetime issues that can occur on program
+  // startup and shutdown.  (See absl/base/const_init.h.)
+  //
+  // For Mutexes allocated on the heap and stack, instead use the default
+  // constructor, which can interact more fully with the thread sanitizer.
+  //
+  // Example usage:
+  //   namespace foo {
+  //   ABSL_CONST_INIT Mutex mu(absl::kConstInit);
+  //   }
+  explicit constexpr Mutex(absl::ConstInitType);
   ~Mutex();
 
   // Mutex::Lock()
@@ -879,10 +899,12 @@ class SCOPED_LOCKABLE ReleasableMutexLock {
 };
 
 #ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
+inline constexpr Mutex::Mutex(absl::ConstInitType) : impl_(absl::kConstInit) {}
 #else
 inline Mutex::Mutex() : mu_(0) {
   ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
 }
+inline constexpr Mutex::Mutex(absl::ConstInitType) : mu_(0) {}
 
 inline CondVar::CondVar() : cv_(0) {}
 #endif