about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--absl/base/BUILD.bazel1
-rw-r--r--absl/base/CMakeLists.txt1
-rw-r--r--absl/base/call_once_test.cc4
-rw-r--r--absl/base/const_init.h73
-rw-r--r--absl/container/BUILD.bazel2
-rw-r--r--absl/container/CMakeLists.txt2
-rw-r--r--absl/container/internal/compressed_tuple.h28
-rw-r--r--absl/container/internal/compressed_tuple_test.cc43
-rw-r--r--absl/numeric/int128.h21
-rw-r--r--absl/numeric/int128_have_intrinsic.inc2
-rw-r--r--absl/numeric/int128_no_intrinsic.inc2
-rw-r--r--absl/strings/internal/pow10_helper.h6
-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
-rw-r--r--absl/time/CMakeLists.txt161
17 files changed, 484 insertions, 203 deletions
diff --git a/absl/base/BUILD.bazel b/absl/base/BUILD.bazel
index 1c31211722c2..2717df0c93a1 100644
--- a/absl/base/BUILD.bazel
+++ b/absl/base/BUILD.bazel
@@ -67,6 +67,7 @@ cc_library(
     name = "core_headers",
     hdrs = [
         "attributes.h",
+        "const_init.h",
         "macros.h",
         "optimization.h",
         "port.h",
diff --git a/absl/base/CMakeLists.txt b/absl/base/CMakeLists.txt
index 212dd0836284..5178d2bd6eb8 100644
--- a/absl/base/CMakeLists.txt
+++ b/absl/base/CMakeLists.txt
@@ -60,6 +60,7 @@ absl_cc_library(
     core_headers
   HDRS
     "attributes.h"
+    "const_init.h"
     "macros.h"
     "optimization.h"
     "port.h"
diff --git a/absl/base/call_once_test.cc b/absl/base/call_once_test.cc
index aa7eb95db262..183b92efa329 100644
--- a/absl/base/call_once_test.cc
+++ b/absl/base/call_once_test.cc
@@ -19,6 +19,7 @@
 
 #include "gtest/gtest.h"
 #include "absl/base/attributes.h"
+#include "absl/base/const_init.h"
 #include "absl/base/thread_annotations.h"
 #include "absl/synchronization/mutex.h"
 
@@ -26,7 +27,8 @@ namespace absl {
 namespace {
 
 absl::once_flag once;
-Mutex counters_mu;
+
+ABSL_CONST_INIT Mutex counters_mu(absl::kConstInit);
 
 int running_thread_count GUARDED_BY(counters_mu) = 0;
 int call_once_invoke_count GUARDED_BY(counters_mu) = 0;
diff --git a/absl/base/const_init.h b/absl/base/const_init.h
new file mode 100644
index 000000000000..fc88b2672e23
--- /dev/null
+++ b/absl/base/const_init.h
@@ -0,0 +1,73 @@
+// Copyright 2017 The Abseil Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+// -----------------------------------------------------------------------------
+// kConstInit
+// -----------------------------------------------------------------------------
+//
+// A constructor tag used to mark an object as safe for use as a global
+// variable, avoiding the usual lifetime issues that can affect globals.
+
+#ifndef ABSL_BASE_CONST_INIT_H_
+#define ABSL_BASE_CONST_INIT_H_
+
+// In general, objects with static storage duration (such as global variables)
+// can trigger tricky object lifetime situations.  Attempting to access them
+// from the constructors or destructors of other global objects can result in
+// undefined behavior, unless their constructors and destructors are designed
+// with this issue in mind.
+//
+// The normal way to deal with this issue in C++11 is to use constant
+// initialization and trivial destructors.
+//
+// Constant initialization is guaranteed to occur before any other code
+// executes.  Constructors that are declared 'constexpr' are eligible for
+// constant initialization.  You can annotate a variable declaration with the
+// ABSL_CONST_INIT macro to express this intent.  For compilers that support
+// it, this annotation will cause a compilation error for declarations that
+// aren't subject to constant initialization (perhaps because a runtime value
+// was passed as a constructor argument).
+//
+// On program shutdown, lifetime issues can be avoided on global objects by
+// ensuring that they contain  trivial destructors.  A class has a trivial
+// destructor unless it has a user-defined destructor, a virtual method or base
+// class, or a data member or base class with a non-trivial destructor of its
+// own.  Objects with static storage duration and a trivial destructor are not
+// cleaned up on program shutdown, and are thus safe to access from other code
+// running during shutdown.
+//
+// For a few core Abseil classes, we make a best effort to allow for safe global
+// instances, even though these classes have non-trivial destructors.  These
+// objects can be created with the absl::kConstInit tag.  For example:
+//   ABSL_CONST_INIT absl::Mutex global_mutex(absl::kConstInit);
+//
+// The line above declares a global variable of type absl::Mutex which can be
+// accessed at any point during startup or shutdown.  global_mutex's destructor
+// will still run, but will not invalidate the object.  Note that C++ specifies
+// that accessing an object after its destructor has run results in undefined
+// behavior, but this pattern works on the toolchains we support.
+//
+// The absl::kConstInit tag should only be used to define objects with static
+// or thread_local storage duration.
+//
+
+namespace absl {
+
+enum ConstInitType {
+  kConstInit,
+};
+
+}  // namespace absl
+
+#endif  // ABSL_BASE_CONST_INIT_H_
diff --git a/absl/container/BUILD.bazel b/absl/container/BUILD.bazel
index d0789923c34e..66f7c9565ba2 100644
--- a/absl/container/BUILD.bazel
+++ b/absl/container/BUILD.bazel
@@ -41,6 +41,8 @@ cc_test(
     copts = ABSL_TEST_COPTS,
     deps = [
         ":compressed_tuple",
+        "//absl/memory",
+        "//absl/utility",
         "@com_google_googletest//:gtest_main",
     ],
 )
diff --git a/absl/container/CMakeLists.txt b/absl/container/CMakeLists.txt
index 8605facc2e2d..3c2735ffcf2e 100644
--- a/absl/container/CMakeLists.txt
+++ b/absl/container/CMakeLists.txt
@@ -44,6 +44,8 @@ absl_cc_test(
     "internal/compressed_tuple_test.cc"
   DEPS
     absl::compressed_tuple
+    absl::memory
+    absl::utility
     gmock_main
 )
 
diff --git a/absl/container/internal/compressed_tuple.h b/absl/container/internal/compressed_tuple.h
index cc52614f5b37..b883ae2657ed 100644
--- a/absl/container/internal/compressed_tuple.h
+++ b/absl/container/internal/compressed_tuple.h
@@ -89,8 +89,10 @@ struct Storage {
   T value;
   constexpr Storage() = default;
   explicit constexpr Storage(T&& v) : value(absl::forward<T>(v)) {}
-  constexpr const T& get() const { return value; }
-  T& get() { return value; }
+  constexpr const T& get() const& { return value; }
+  T& get() & { return value; }
+  constexpr const T&& get() const&& { return absl::move(*this).value; }
+  T&& get() && { return std::move(*this).value; }
 };
 
 template <typename D, size_t I>
@@ -99,8 +101,10 @@ struct ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC Storage<D, I, true>
   using T = internal_compressed_tuple::ElemT<D, I>;
   constexpr Storage() = default;
   explicit constexpr Storage(T&& v) : T(absl::forward<T>(v)) {}
-  constexpr const T& get() const { return *this; }
-  T& get() { return *this; }
+  constexpr const T& get() const& { return *this; }
+  T& get() & { return *this; }
+  constexpr const T&& get() const&& { return absl::move(*this); }
+  T&& get() && { return std::move(*this); }
 };
 
 template <typename D, typename I>
@@ -152,14 +156,26 @@ class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple
       : CompressedTuple::CompressedTupleImpl(absl::forward<Ts>(base)...) {}
 
   template <int I>
-  ElemT<I>& get() {
+  ElemT<I>& get() & {
     return internal_compressed_tuple::Storage<CompressedTuple, I>::get();
   }
 
   template <int I>
-  constexpr const ElemT<I>& get() const {
+  constexpr const ElemT<I>& get() const& {
     return internal_compressed_tuple::Storage<CompressedTuple, I>::get();
   }
+
+  template <int I>
+  ElemT<I>&& get() && {
+    return std::move(*this)
+        .internal_compressed_tuple::template Storage<CompressedTuple, I>::get();
+  }
+
+  template <int I>
+  constexpr const ElemT<I>&& get() const&& {
+    return absl::move(*this)
+        .internal_compressed_tuple::template Storage<CompressedTuple, I>::get();
+  }
 };
 
 // Explicit specialization for a zero-element tuple
diff --git a/absl/container/internal/compressed_tuple_test.cc b/absl/container/internal/compressed_tuple_test.cc
index 45030c675ee1..04ead100aa13 100644
--- a/absl/container/internal/compressed_tuple_test.cc
+++ b/absl/container/internal/compressed_tuple_test.cc
@@ -14,17 +14,25 @@
 
 #include "absl/container/internal/compressed_tuple.h"
 
+#include <memory>
 #include <string>
 
 #include "gmock/gmock.h"
 #include "gtest/gtest.h"
+#include "absl/memory/memory.h"
+#include "absl/utility/utility.h"
 
 namespace absl {
 namespace container_internal {
 namespace {
 
+enum class CallType { kConstRef, kConstMove };
+
 template <int>
-struct Empty {};
+struct Empty {
+  constexpr CallType value() const& { return CallType::kConstRef; }
+  constexpr CallType value() const&& { return CallType::kConstMove; }
+};
 
 template <typename T>
 struct NotEmpty {
@@ -140,15 +148,44 @@ TEST(CompressedTupleTest, NoElements) {
   EXPECT_TRUE(std::is_empty<CompressedTuple<>>::value);
 }
 
+TEST(CompressedTupleTest, MoveOnlyElements) {
+  CompressedTuple<std::unique_ptr<std::string>> str_tup(
+      absl::make_unique<std::string>("str"));
+
+  CompressedTuple<CompressedTuple<std::unique_ptr<std::string>>,
+                  std::unique_ptr<int>>
+  x(std::move(str_tup), absl::make_unique<int>(5));
+
+  EXPECT_EQ(*x.get<0>().get<0>(), "str");
+  EXPECT_EQ(*x.get<1>(), 5);
+
+  std::unique_ptr<std::string> x0 = std::move(x.get<0>()).get<0>();
+  std::unique_ptr<int> x1 = std::move(x).get<1>();
+
+  EXPECT_EQ(*x0, "str");
+  EXPECT_EQ(*x1, 5);
+}
+
 TEST(CompressedTupleTest, Constexpr) {
-  constexpr CompressedTuple<int, double, CompressedTuple<int>> x(
-      7, 1.25, CompressedTuple<int>(5));
+  constexpr CompressedTuple<int, double, CompressedTuple<int>, Empty<0>> x(
+      7, 1.25, CompressedTuple<int>(5), {});
   constexpr int x0 = x.get<0>();
   constexpr double x1 = x.get<1>();
   constexpr int x2 = x.get<2>().get<0>();
+  constexpr CallType x3 = x.get<3>().value();
+
   EXPECT_EQ(x0, 7);
   EXPECT_EQ(x1, 1.25);
   EXPECT_EQ(x2, 5);
+  EXPECT_EQ(x3, CallType::kConstRef);
+
+#if defined(__clang__)
+  // An apparent bug in earlier versions of gcc claims these are ambiguous.
+  constexpr int x2m = absl::move(x.get<2>()).get<0>();
+  constexpr CallType x3m = absl::move(x).get<3>().value();
+  EXPECT_EQ(x2m, 5);
+  EXPECT_EQ(x3m, CallType::kConstMove);
+#endif
 }
 
 #if defined(__clang__) || defined(__GNUC__)
diff --git a/absl/numeric/int128.h b/absl/numeric/int128.h
index f9c83cafec40..9c36c57116c6 100644
--- a/absl/numeric/int128.h
+++ b/absl/numeric/int128.h
@@ -37,10 +37,19 @@
 #include "absl/base/macros.h"
 #include "absl/base/port.h"
 
-#if defined(_MSC_VER) && defined(_WIN64)
+#if defined(_MSC_VER)
+// In very old versions of MSVC and when the /Zc:wchar_t flag is off, wchar_t is
+// a typedef for unsigned short.  Otherwise wchar_t is mapped to the __wchar_t
+// builtin type.  We need to make sure not to define operator wchar_t()
+// alongside operator unsigned short() in these instances.
+#define ABSL_INTERNAL_WCHAR_T __wchar_t
+#if defined(_WIN64)
 #include <intrin.h>
 #pragma intrinsic(_umul128)
-#endif  // defined(_MSC_VER) && defined(_WIN64)
+#endif  // defined(_WIN64)
+#else   // defined(_MSC_VER)
+#define ABSL_INTERNAL_WCHAR_T wchar_t
+#endif  // defined(_MSC_VER)
 
 namespace absl {
 
@@ -131,7 +140,7 @@ class
   constexpr explicit operator unsigned char() const;
   constexpr explicit operator char16_t() const;
   constexpr explicit operator char32_t() const;
-  constexpr explicit operator wchar_t() const;
+  constexpr explicit operator ABSL_INTERNAL_WCHAR_T() const;
   constexpr explicit operator short() const;  // NOLINT(runtime/int)
   // NOLINTNEXTLINE(runtime/int)
   constexpr explicit operator unsigned short() const;
@@ -468,8 +477,8 @@ constexpr uint128::operator char32_t() const {
   return static_cast<char32_t>(lo_);
 }
 
-constexpr uint128::operator wchar_t() const {
-  return static_cast<wchar_t>(lo_);
+constexpr uint128::operator ABSL_INTERNAL_WCHAR_T() const {
+  return static_cast<ABSL_INTERNAL_WCHAR_T>(lo_);
 }
 
 // NOLINTNEXTLINE(runtime/int)
@@ -719,4 +728,6 @@ inline uint128& uint128::operator--() {
 
 }  // namespace absl
 
+#undef ABSL_INTERNAL_WCHAR_T
+
 #endif  // ABSL_NUMERIC_INT128_H_
diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc
index ee2a093018d9..0c8164a5444e 100644
--- a/absl/numeric/int128_have_intrinsic.inc
+++ b/absl/numeric/int128_have_intrinsic.inc
@@ -15,4 +15,4 @@
 
 // This file contains :int128 implementation details that depend on internal
 // representation when ABSL_HAVE_INTRINSIC_INT128 is defined. This file is
-// included by int128.h.
+// included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined.
diff --git a/absl/numeric/int128_no_intrinsic.inc b/absl/numeric/int128_no_intrinsic.inc
index 0d0b3cfdeb12..08d68ac3ea58 100644
--- a/absl/numeric/int128_no_intrinsic.inc
+++ b/absl/numeric/int128_no_intrinsic.inc
@@ -15,4 +15,4 @@
 
 // This file contains :int128 implementation details that depend on internal
 // representation when ABSL_HAVE_INTRINSIC_INT128 is *not* defined. This file
-// is included by int128.h.
+// is included by int128.h and relies on ABSL_INTERNAL_WCHAR_T being defined.
diff --git a/absl/strings/internal/pow10_helper.h b/absl/strings/internal/pow10_helper.h
index 39c153928de2..fe7e735a30bb 100644
--- a/absl/strings/internal/pow10_helper.h
+++ b/absl/strings/internal/pow10_helper.h
@@ -17,8 +17,8 @@
 // precise values are computed across the full range of doubles. We can't rely
 // on the pow() function, because not all standard libraries ship a version
 // that is precise.
-#ifndef ABSL_STRINGS_POW10_HELPER_H_
-#define ABSL_STRINGS_POW10_HELPER_H_
+#ifndef ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
+#define ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
 
 #include <vector>
 
@@ -33,4 +33,4 @@ double Pow10(int exp);
 }  // namespace strings_internal
 }  // namespace absl
 
-#endif  // ABSL_STRINGS_POW10_HELPER_H_
+#endif  // ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
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
diff --git a/absl/time/CMakeLists.txt b/absl/time/CMakeLists.txt
index 53216cda055b..db60e712c940 100644
--- a/absl/time/CMakeLists.txt
+++ b/absl/time/CMakeLists.txt
@@ -14,85 +14,108 @@
 # limitations under the License.
 #
 
-list(APPEND TIME_PUBLIC_HEADERS
-  "civil_time.h"
-  "clock.h"
-  "time.h"
-)
-
-
-list(APPEND TIME_INTERNAL_HEADERS
-  "internal/test_util.h"
-  "internal/cctz/include/cctz/civil_time.h"
-  "internal/cctz/include/cctz/civil_time_detail.h"
-  "internal/cctz/include/cctz/time_zone.h"
-  "internal/cctz/include/cctz/zone_info_source.h"
-)
-
-list(APPEND TIME_SRC
+absl_cc_library(
+  NAME
+    time
+  HDRS
+    "civil_time.h"
+    "clock.h"
+    "time.h"
+  SRCS
   "civil_time.cc"
-  "time.cc"
   "clock.cc"
   "duration.cc"
   "format.cc"
-  "internal/cctz/src/civil_time_detail.cc"
-  "internal/cctz/src/time_zone_fixed.cc"
-  "internal/cctz/src/time_zone_fixed.h"
-  "internal/cctz/src/time_zone_format.cc"
-  "internal/cctz/src/time_zone_if.cc"
-  "internal/cctz/src/time_zone_if.h"
-  "internal/cctz/src/time_zone_impl.cc"
-  "internal/cctz/src/time_zone_impl.h"
-  "internal/cctz/src/time_zone_info.cc"
-  "internal/cctz/src/time_zone_info.h"
-  "internal/cctz/src/time_zone_libc.cc"
-  "internal/cctz/src/time_zone_libc.h"
-  "internal/cctz/src/time_zone_lookup.cc"
-  "internal/cctz/src/time_zone_posix.cc"
-  "internal/cctz/src/time_zone_posix.h"
-  "internal/cctz/src/tzfile.h"
-  "internal/cctz/src/zone_info_source.cc"
-  ${TIME_PUBLIC_HEADERS}
-  ${TIME_INTERNAL_HEADERS}
+  "internal/get_current_time_chrono.inc"
+  "internal/get_current_time_posix.inc"
+  "time.cc"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::base
+    absl::core_headers
+    absl::int128
+    absl::strings
+    absl::civil_time
+    absl::time_zone
+  PUBLIC
 )
-set(TIME_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::int128 absl::strings)
 
-absl_library(
-  TARGET
-    absl_time
-  SOURCES
-    ${TIME_SRC}
-  PUBLIC_LIBRARIES
-    ${TIME_PUBLIC_LIBRARIES}
-  EXPORT_NAME
-    time
+absl_cc_library(
+  NAME
+    civil_time
+  HDRS
+    "internal/cctz/include/cctz/civil_time.h"
+    "internal/cctz/include/cctz/civil_time_detail.h"
+  SRCS
+  "internal/cctz/src/civil_time_detail.cc"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
 )
 
+absl_cc_library(
+  NAME
+    time_zone
+  HDRS
+    "internal/cctz/include/cctz/time_zone.h"
+    "internal/cctz/include/cctz/zone_info_source.h"
+  SRCS
+    "internal/cctz/src/time_zone_fixed.cc"
+    "internal/cctz/src/time_zone_fixed.h"
+    "internal/cctz/src/time_zone_format.cc"
+    "internal/cctz/src/time_zone_if.cc"
+    "internal/cctz/src/time_zone_if.h"
+    "internal/cctz/src/time_zone_impl.cc"
+    "internal/cctz/src/time_zone_impl.h"
+    "internal/cctz/src/time_zone_info.cc"
+    "internal/cctz/src/time_zone_info.h"
+    "internal/cctz/src/time_zone_libc.cc"
+    "internal/cctz/src/time_zone_libc.h"
+    "internal/cctz/src/time_zone_lookup.cc"
+    "internal/cctz/src/time_zone_posix.cc"
+    "internal/cctz/src/time_zone_posix.h"
+    "internal/cctz/src/tzfile.h"
+    "internal/cctz/src/zone_info_source.cc"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+)
 
-
-#
-## TESTS
-#
-
-# test time_test
-list(APPEND TIME_TEST_SRC
-  "civil_time_test.cc"
-  "time_test.cc"
-  "clock_test.cc"
-  "duration_test.cc"
-  "format_test.cc"
-  "time_test.cc"
-  "time_zone_test.cc"
-  "internal/test_util.cc"
+absl_cc_library(
+  NAME
+    test_util
+  HDRS
+    "internal/test_util.h"
+  SRCS
+    "internal/test_util.cc"
+    "internal/zoneinfo.inc"
+  COPTS
+    ${ABSL_DEFAULT_COPTS}
+  DEPS
+    absl::time
+    absl::base
+    absl::time_zone
+    gmock
+  TESTONLY
 )
-set(TIME_TEST_PUBLIC_LIBRARIES absl::time)
 
-absl_test(
-  TARGET
+absl_cc_test(
+  NAME
     time_test
-  SOURCES
-    ${TIME_TEST_SRC}
-  PUBLIC_LIBRARIES
-    ${TIME_TEST_PUBLIC_LIBRARIES}
+  SRCS
+    "civil_time_test.cc"
+    "clock_test.cc"
+    "duration_test.cc"
+    "format_test.cc"
+    "time_test.cc"
+    "time_zone_test.cc"
+  COPTS
+    ${ABSL_TEST_COPTS}
+  DEPS
+    absl::test_util
+    absl::time
+    absl::base
+    absl::config
+    absl::core_headers
+    absl::time_zone
+    gmock_main
 )
-