summaryrefslogtreecommitdiff
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 1c312117..2717df0c 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 212dd083..5178d2bd 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 aa7eb95d..183b92ef 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 00000000..fc88b267
--- /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 d0789923..66f7c956 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 8605facc..3c2735ff 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 cc52614f..b883ae26 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 45030c67..04ead100 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 f9c83caf..9c36c571 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 ee2a0930..0c8164a5 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 0d0b3cfd..08d68ac3 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 39c15392..fe7e735a 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 de0d7b7d..cb77b685 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 0aab3d13..b8d5af79 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 b7360c29..8b168e21 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 aeef3c95..4b65e92c 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 53216cda..db60e712 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
)
-