Export of internal Abseil changes.

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

Add move semantics to absl::container_internal::CompressedTuple

PiperOrigin-RevId: 225394165

--
43da91e4f95a196b2e6b76f1c2f4158817b0ebb0 by Greg Falcon <gfalcon@google.com>:

Add a constructor to allow for global absl::Mutex instances.

This adds a new constexpr constructor to absl::Mutex, invoked with the absl::kConstInit tag value, which is intended to be used to construct Mutex instances with static storage duration.

What's tricky about is absl::Mutex (like std::mutex) is not a trivially destructible class, so by the letter of the law, accessing a global Mutex instance after it is destroyed results in undefined behavior.  Despite this, we take care in the destructor to not invalidate the memory layout of the Mutex.  Using a kConstInit-constructed global Mutex after it is destroyed happens to work on the toolchains we use.  Google relies heavily on this behavior internally.

Code sanitizers that detect undefined behavior are able to notice use-after-free of globals, and might complain about this pattern.

PiperOrigin-RevId: 225389447

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

Internal change.

PiperOrigin-RevId: 225373389

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

Update absl/time/CMakeLists.txt to use new functions
i.e. absl_cc_(library|test)

PiperOrigin-RevId: 225246853

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

Update absl/synchronisation/CMakeLists.txt to use new functions
i.e. absl_cc_(library|test)

PiperOrigin-RevId: 225237980

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

Internal cleanup

PiperOrigin-RevId: 225226813

--
48fab23fb8cdca45e95da14fce0de56614d09c25 by Jon Cohen <cohenjon@google.com>:

Use a shim #define for wchar_t in msvc in int128.

On ancient versions of msvc and with some compatibility flags on wchar_t is a typedef for unsigned short, whereas on standards-conforming versions wchar_t is a typedef for __wchar_t.  The first situation causes int128 to not compile as you can't define both `operator wchar_t()` and `operator unsigned short()` because they are the same type.

This CL introduces a wrapper #define in order to abstract over the different typedefs for wchar_t.  We do a define instead of a typedef so that we can #undef at the end and not leak the symbol, since we need it in a header.

https://docs.microsoft.com/en-us/previous-versions/dh8che7s(v=vs.140) has more detail about the underlying problem.

PiperOrigin-RevId: 225223756
GitOrigin-RevId: 636137f6f0de910691a3950387fefacfa4909fb8
Change-Id: Iad94e52e9484c5acec115a2f09ef2d5ec22c2074
This commit is contained in:
Abseil Team 2018-12-13 10:30:03 -08:00 committed by jueminyang
parent 8fbcdb9095
commit 389ec3f906
17 changed files with 486 additions and 205 deletions

View file

@ -67,6 +67,7 @@ cc_library(
name = "core_headers", name = "core_headers",
hdrs = [ hdrs = [
"attributes.h", "attributes.h",
"const_init.h",
"macros.h", "macros.h",
"optimization.h", "optimization.h",
"port.h", "port.h",

View file

@ -60,6 +60,7 @@ absl_cc_library(
core_headers core_headers
HDRS HDRS
"attributes.h" "attributes.h"
"const_init.h"
"macros.h" "macros.h"
"optimization.h" "optimization.h"
"port.h" "port.h"

View file

@ -19,6 +19,7 @@
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
#include "absl/base/const_init.h"
#include "absl/base/thread_annotations.h" #include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h" #include "absl/synchronization/mutex.h"
@ -26,7 +27,8 @@ namespace absl {
namespace { namespace {
absl::once_flag once; 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 running_thread_count GUARDED_BY(counters_mu) = 0;
int call_once_invoke_count GUARDED_BY(counters_mu) = 0; int call_once_invoke_count GUARDED_BY(counters_mu) = 0;

73
absl/base/const_init.h Normal file
View file

@ -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_

View file

@ -41,6 +41,8 @@ cc_test(
copts = ABSL_TEST_COPTS, copts = ABSL_TEST_COPTS,
deps = [ deps = [
":compressed_tuple", ":compressed_tuple",
"//absl/memory",
"//absl/utility",
"@com_google_googletest//:gtest_main", "@com_google_googletest//:gtest_main",
], ],
) )

View file

@ -44,6 +44,8 @@ absl_cc_test(
"internal/compressed_tuple_test.cc" "internal/compressed_tuple_test.cc"
DEPS DEPS
absl::compressed_tuple absl::compressed_tuple
absl::memory
absl::utility
gmock_main gmock_main
) )

View file

@ -89,8 +89,10 @@ struct Storage {
T value; T value;
constexpr Storage() = default; constexpr Storage() = default;
explicit constexpr Storage(T&& v) : value(absl::forward<T>(v)) {} explicit constexpr Storage(T&& v) : value(absl::forward<T>(v)) {}
constexpr const T& get() const { return value; } constexpr const T& get() const& { return value; }
T& get() { 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> 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>; using T = internal_compressed_tuple::ElemT<D, I>;
constexpr Storage() = default; constexpr Storage() = default;
explicit constexpr Storage(T&& v) : T(absl::forward<T>(v)) {} explicit constexpr Storage(T&& v) : T(absl::forward<T>(v)) {}
constexpr const T& get() const { return *this; } constexpr const T& get() const& { return *this; }
T& get() { 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> template <typename D, typename I>
@ -152,14 +156,26 @@ class ABSL_INTERNAL_COMPRESSED_TUPLE_DECLSPEC CompressedTuple
: CompressedTuple::CompressedTupleImpl(absl::forward<Ts>(base)...) {} : CompressedTuple::CompressedTupleImpl(absl::forward<Ts>(base)...) {}
template <int I> template <int I>
ElemT<I>& get() { ElemT<I>& get() & {
return internal_compressed_tuple::Storage<CompressedTuple, I>::get(); return internal_compressed_tuple::Storage<CompressedTuple, I>::get();
} }
template <int I> template <int I>
constexpr const ElemT<I>& get() const { constexpr const ElemT<I>& get() const& {
return internal_compressed_tuple::Storage<CompressedTuple, I>::get(); 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 // Explicit specialization for a zero-element tuple

View file

@ -14,17 +14,25 @@
#include "absl/container/internal/compressed_tuple.h" #include "absl/container/internal/compressed_tuple.h"
#include <memory>
#include <string> #include <string>
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "absl/memory/memory.h"
#include "absl/utility/utility.h"
namespace absl { namespace absl {
namespace container_internal { namespace container_internal {
namespace { namespace {
enum class CallType { kConstRef, kConstMove };
template <int> template <int>
struct Empty {}; struct Empty {
constexpr CallType value() const& { return CallType::kConstRef; }
constexpr CallType value() const&& { return CallType::kConstMove; }
};
template <typename T> template <typename T>
struct NotEmpty { struct NotEmpty {
@ -140,15 +148,44 @@ TEST(CompressedTupleTest, NoElements) {
EXPECT_TRUE(std::is_empty<CompressedTuple<>>::value); 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) { TEST(CompressedTupleTest, Constexpr) {
constexpr CompressedTuple<int, double, CompressedTuple<int>> x( constexpr CompressedTuple<int, double, CompressedTuple<int>, Empty<0>> x(
7, 1.25, CompressedTuple<int>(5)); 7, 1.25, CompressedTuple<int>(5), {});
constexpr int x0 = x.get<0>(); constexpr int x0 = x.get<0>();
constexpr double x1 = x.get<1>(); constexpr double x1 = x.get<1>();
constexpr int x2 = x.get<2>().get<0>(); constexpr int x2 = x.get<2>().get<0>();
constexpr CallType x3 = x.get<3>().value();
EXPECT_EQ(x0, 7); EXPECT_EQ(x0, 7);
EXPECT_EQ(x1, 1.25); EXPECT_EQ(x1, 1.25);
EXPECT_EQ(x2, 5); 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__) #if defined(__clang__) || defined(__GNUC__)

View file

@ -37,10 +37,19 @@
#include "absl/base/macros.h" #include "absl/base/macros.h"
#include "absl/base/port.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> #include <intrin.h>
#pragma intrinsic(_umul128) #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 { namespace absl {
@ -131,7 +140,7 @@ class
constexpr explicit operator unsigned char() const; constexpr explicit operator unsigned char() const;
constexpr explicit operator char16_t() const; constexpr explicit operator char16_t() const;
constexpr explicit operator char32_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) constexpr explicit operator short() const; // NOLINT(runtime/int)
// NOLINTNEXTLINE(runtime/int) // NOLINTNEXTLINE(runtime/int)
constexpr explicit operator unsigned short() const; constexpr explicit operator unsigned short() const;
@ -468,8 +477,8 @@ constexpr uint128::operator char32_t() const {
return static_cast<char32_t>(lo_); return static_cast<char32_t>(lo_);
} }
constexpr uint128::operator wchar_t() const { constexpr uint128::operator ABSL_INTERNAL_WCHAR_T() const {
return static_cast<wchar_t>(lo_); return static_cast<ABSL_INTERNAL_WCHAR_T>(lo_);
} }
// NOLINTNEXTLINE(runtime/int) // NOLINTNEXTLINE(runtime/int)
@ -719,4 +728,6 @@ inline uint128& uint128::operator--() {
} // namespace absl } // namespace absl
#undef ABSL_INTERNAL_WCHAR_T
#endif // ABSL_NUMERIC_INT128_H_ #endif // ABSL_NUMERIC_INT128_H_

View file

@ -15,4 +15,4 @@
// This file contains :int128 implementation details that depend on internal // This file contains :int128 implementation details that depend on internal
// representation when ABSL_HAVE_INTRINSIC_INT128 is defined. This file is // 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.

View file

@ -15,4 +15,4 @@
// This file contains :int128 implementation details that depend on internal // This file contains :int128 implementation details that depend on internal
// representation when ABSL_HAVE_INTRINSIC_INT128 is *not* defined. This file // 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.

View file

@ -17,8 +17,8 @@
// precise values are computed across the full range of doubles. We can't rely // 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 // on the pow() function, because not all standard libraries ship a version
// that is precise. // that is precise.
#ifndef ABSL_STRINGS_POW10_HELPER_H_ #ifndef ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
#define ABSL_STRINGS_POW10_HELPER_H_ #define ABSL_STRINGS_INTERNAL_POW10_HELPER_H_
#include <vector> #include <vector>
@ -33,4 +33,4 @@ double Pow10(int exp);
} // namespace strings_internal } // namespace strings_internal
} // namespace absl } // namespace absl
#endif // ABSL_STRINGS_POW10_HELPER_H_ #endif // ABSL_STRINGS_INTERNAL_POW10_HELPER_H_

View file

@ -14,142 +14,182 @@
# limitations under the License. # limitations under the License.
# #
list(APPEND SYNCHRONIZATION_PUBLIC_HEADERS 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
)
absl_cc_library(
NAME
synchronization
HDRS
"barrier.h" "barrier.h"
"blocking_counter.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" "mutex.h"
"notification.h" "notification.h"
) SRCS
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" "barrier.cc"
"blocking_counter.cc" "blocking_counter.cc"
"internal/create_thread_identity.cc" "internal/create_thread_identity.cc"
"internal/per_thread_sem.cc" "internal/per_thread_sem.cc"
"internal/waiter.cc" "internal/waiter.cc"
"internal/graphcycles.cc"
"notification.cc" "notification.cc"
"mutex.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
) )
set(SYNCHRONIZATION_PUBLIC_LIBRARIES absl::base absl::stacktrace absl::symbolize absl::time) absl_cc_test(
NAME
absl_library(
TARGET
absl_synchronization
SOURCES
${SYNCHRONIZATION_SRC}
PUBLIC_LIBRARIES
${SYNCHRONIZATION_PUBLIC_LIBRARIES}
EXPORT_NAME
synchronization
)
#
## TESTS
#
# test barrier_test
set(BARRIER_TEST_SRC "barrier_test.cc")
set(BARRIER_TEST_PUBLIC_LIBRARIES absl::synchronization)
absl_test(
TARGET
barrier_test barrier_test
SOURCES SRCS
${BARRIER_TEST_SRC} "barrier_test.cc"
PUBLIC_LIBRARIES COPTS
${BARRIER_TEST_PUBLIC_LIBRARIES} ${ABSL_TEST_COPTS}
DEPS
absl::synchronization
absl::time
gmock_main
) )
absl_cc_test(
# test blocking_counter_test NAME
set(BLOCKING_COUNTER_TEST_SRC "blocking_counter_test.cc")
set(BLOCKING_COUNTER_TEST_PUBLIC_LIBRARIES absl::synchronization)
absl_test(
TARGET
blocking_counter_test blocking_counter_test
SOURCES SRCS
${BLOCKING_COUNTER_TEST_SRC} "blocking_counter_test.cc"
PUBLIC_LIBRARIES COPTS
${BLOCKING_COUNTER_TEST_PUBLIC_LIBRARIES} ${ABSL_TEST_COPTS}
DEPS
absl::synchronization
absl::time
gmock_main
) )
absl_cc_test(
# test graphcycles_test NAME
set(GRAPHCYCLES_TEST_SRC "internal/graphcycles_test.cc")
set(GRAPHCYCLES_TEST_PUBLIC_LIBRARIES absl::synchronization)
absl_test(
TARGET
graphcycles_test graphcycles_test
SOURCES SRCS
${GRAPHCYCLES_TEST_SRC} "internal/graphcycles_test.cc"
PUBLIC_LIBRARIES COPTS
${GRAPHCYCLES_TEST_PUBLIC_LIBRARIES} ${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 absl_cc_test(
set(MUTEX_TEST_SRC "mutex_test.cc") NAME
set(MUTEX_TEST_PUBLIC_LIBRARIES absl::synchronization)
absl_test(
TARGET
mutex_test mutex_test
SOURCES SRCS
${MUTEX_TEST_SRC} "mutex_test.cc"
PUBLIC_LIBRARIES COPTS
${MUTEX_TEST_PUBLIC_LIBRARIES} ${ABSL_TEST_COPTS}
DEPS
absl::synchronization
absl::thread_pool
absl::base
absl::core_headers
absl::memory
absl::time
gmock_main
) )
absl_cc_test(
# test notification_test NAME
set(NOTIFICATION_TEST_SRC "notification_test.cc")
set(NOTIFICATION_TEST_PUBLIC_LIBRARIES absl::synchronization)
absl_test(
TARGET
notification_test notification_test
SOURCES SRCS
${NOTIFICATION_TEST_SRC} "notification_test.cc"
PUBLIC_LIBRARIES COPTS
${NOTIFICATION_TEST_PUBLIC_LIBRARIES} ${ABSL_TEST_COPTS}
DEPS
absl::synchronization
absl::time
gmock_main
) )
absl_cc_library(
# test per_thread_sem_test_common NAME
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
per_thread_sem_test_common per_thread_sem_test_common
SOURCES SRCS
${PER_THREAD_SEM_TEST_COMMON_SRC} "internal/per_thread_sem_test.cc"
PUBLIC_LIBRARIES COPTS
${PER_THREAD_SEM_TEST_COMMON_PUBLIC_LIBRARIES} ${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
)

View file

@ -214,6 +214,9 @@ class SynchronizationStorage {
// stack) should use this constructor. // stack) should use this constructor.
explicit SynchronizationStorage(base_internal::LinkerInitialized) {} explicit SynchronizationStorage(base_internal::LinkerInitialized) {}
constexpr explicit SynchronizationStorage(absl::ConstInitType)
: is_dynamic_(false), once_(), space_{{0}} {}
SynchronizationStorage(SynchronizationStorage&) = delete; SynchronizationStorage(SynchronizationStorage&) = delete;
SynchronizationStorage& operator=(SynchronizationStorage&) = delete; SynchronizationStorage& operator=(SynchronizationStorage&) = delete;

View file

@ -17,6 +17,7 @@
#include <type_traits> #include <type_traits>
#include "absl/base/attributes.h" #include "absl/base/attributes.h"
#include "absl/base/const_init.h"
#include "absl/base/internal/raw_logging.h" #include "absl/base/internal/raw_logging.h"
#include "absl/base/thread_annotations.h" #include "absl/base/thread_annotations.h"
#include "absl/synchronization/mutex.h" #include "absl/synchronization/mutex.h"
@ -95,6 +96,10 @@ void TestLocals() {
RunTests(&mutex, &condvar); 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 // Global variables during start and termination
// //
// In a translation unit, static storage duration variables are initialized in // In a translation unit, static storage duration variables are initialized in
@ -117,10 +122,53 @@ class OnDestruction {
Function fn_; 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 } // namespace
int main() { int main() {
TestLocals(); TestLocals();
TestConstInitGlobal();
// Explicitly call exit(0) here, to make it clear that we intend for the // Explicitly call exit(0) here, to make it clear that we intend for the
// above global object destructors to run. // above global object destructors to run.
std::exit(0); std::exit(0);

View file

@ -61,6 +61,7 @@
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include "absl/base/const_init.h"
#include "absl/base/internal/identity.h" #include "absl/base/internal/identity.h"
#include "absl/base/internal/low_level_alloc.h" #include "absl/base/internal/low_level_alloc.h"
#include "absl/base/internal/thread_identity.h" #include "absl/base/internal/thread_identity.h"
@ -136,7 +137,26 @@ struct SynchWaitParams;
class LOCKABLE Mutex { class LOCKABLE Mutex {
public: 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(); 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();
// Mutex::Lock() // Mutex::Lock()
@ -879,10 +899,12 @@ class SCOPED_LOCKABLE ReleasableMutexLock {
}; };
#ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX #ifdef ABSL_INTERNAL_USE_NONPROD_MUTEX
inline constexpr Mutex::Mutex(absl::ConstInitType) : impl_(absl::kConstInit) {}
#else #else
inline Mutex::Mutex() : mu_(0) { inline Mutex::Mutex() : mu_(0) {
ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static); ABSL_TSAN_MUTEX_CREATE(this, __tsan_mutex_not_static);
} }
inline constexpr Mutex::Mutex(absl::ConstInitType) : mu_(0) {}
inline CondVar::CondVar() : cv_(0) {} inline CondVar::CondVar() : cv_(0) {}
#endif #endif

View file

@ -14,28 +14,52 @@
# limitations under the License. # limitations under the License.
# #
list(APPEND TIME_PUBLIC_HEADERS absl_cc_library(
NAME
time
HDRS
"civil_time.h" "civil_time.h"
"clock.h" "clock.h"
"time.h" "time.h"
) SRCS
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
"civil_time.cc" "civil_time.cc"
"time.cc"
"clock.cc" "clock.cc"
"duration.cc" "duration.cc"
"format.cc" "format.cc"
"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
)
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" "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.cc"
"internal/cctz/src/time_zone_fixed.h" "internal/cctz/src/time_zone_fixed.h"
"internal/cctz/src/time_zone_format.cc" "internal/cctz/src/time_zone_format.cc"
@ -52,47 +76,46 @@ list(APPEND TIME_SRC
"internal/cctz/src/time_zone_posix.h" "internal/cctz/src/time_zone_posix.h"
"internal/cctz/src/tzfile.h" "internal/cctz/src/tzfile.h"
"internal/cctz/src/zone_info_source.cc" "internal/cctz/src/zone_info_source.cc"
${TIME_PUBLIC_HEADERS} COPTS
${TIME_INTERNAL_HEADERS} ${ABSL_DEFAULT_COPTS}
)
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
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
)
absl_cc_test(
# NAME
## TESTS time_test
# SRCS
# test time_test
list(APPEND TIME_TEST_SRC
"civil_time_test.cc" "civil_time_test.cc"
"time_test.cc"
"clock_test.cc" "clock_test.cc"
"duration_test.cc" "duration_test.cc"
"format_test.cc" "format_test.cc"
"time_test.cc" "time_test.cc"
"time_zone_test.cc" "time_zone_test.cc"
"internal/test_util.cc" COPTS
${ABSL_TEST_COPTS}
DEPS
absl::test_util
absl::time
absl::base
absl::config
absl::core_headers
absl::time_zone
gmock_main
) )
set(TIME_TEST_PUBLIC_LIBRARIES absl::time)
absl_test(
TARGET
time_test
SOURCES
${TIME_TEST_SRC}
PUBLIC_LIBRARIES
${TIME_TEST_PUBLIC_LIBRARIES}
)