0

Roll abseil_revision 049aa40e7e..166d71d18f

Change Log:
049aa40e7e..166d71d18f
Full diff:
049aa40e7e..166d71d18f

No .def changes

Bug: None
Change-Id: Ic5c8c93ce285933bd4c2a0fac40e2e331ecc3565
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4629756
Auto-Submit: Danil Chapovalov <danilchap@chromium.org>
Reviewed-by: Nico Weber <thakis@chromium.org>
Commit-Queue: Nico Weber <thakis@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1160761}
This commit is contained in:
Danil Chapovalov
2023-06-21 18:35:30 +00:00
committed by Chromium LUCI CQ
parent e2b8d8360f
commit 79a40941bd
20 changed files with 1049 additions and 476 deletions

1
DEPS

@ -4426,6 +4426,7 @@ include_rules = [
# //styleguide/c++/c++-features.md.
'+third_party/abseil-cpp',
'-third_party/abseil-cpp/absl/algorithm/container.h',
'-third_party/abseil-cpp/absl/base/nullability.h',
'-third_party/abseil-cpp/absl/container',
'-third_party/abseil-cpp/absl/crc',
'-third_party/abseil-cpp/absl/flags',

@ -39,6 +39,7 @@ The current status of existing standards and Abseil features is:
* absl::AnyInvocable: Initially supported June 20, 2022
* Log library: Initially supported Aug 31, 2022
* CRC32C library: Initially supported Dec 5, 2022
* Nullability annotation: Initially supported Jun 21, 2023
[TOC]
@ -1872,3 +1873,23 @@ absl::AddLogSink(&custom_sink_to_capture_absl_logs);
*** promo
Overlaps and uses same macros names as `base/logging.h`.
***
### Nullability annotations <sup>[tbd]</sup>
```c++
void PaySalary(absl::NotNull<Employee *> employee) {
pay(*employee); // OK to dereference
}
```
**Description:** Annotations to more clearly specify contracts
**Documentation:**
[nullability.h](https://source.chromium.org/chromium/chromium/src/+/main:third_party/abseil-cpp/absl/base/nullability.h)
**Notes:**
*** promo
These nullability annotations are primarily a human readable signal about the
intended contract of the pointer. They are not *types* and do not currently
provide any correctness guarantees.
***

@ -61,6 +61,7 @@ group("absl_component_deps") {
"//third_party/abseil-cpp/absl/base",
"//third_party/abseil-cpp/absl/base:config",
"//third_party/abseil-cpp/absl/base:core_headers",
"//third_party/abseil-cpp/absl/base:nullability",
"//third_party/abseil-cpp/absl/base:prefetch",
"//third_party/abseil-cpp/absl/cleanup",
"//third_party/abseil-cpp/absl/container:btree",
@ -189,6 +190,7 @@ if (build_with_chromium) {
"absl/algorithm:algorithm_test",
"absl/algorithm:container_test",
"absl/base:config_test",
"absl/base:nullability_test",
"absl/base:prefetch_test",
"absl/cleanup:cleanup_test",
# TODO(mbonadei): Fix issue with EXPECT_DEATH and uncomment.

@ -25,6 +25,7 @@ set(ABSL_INTERNAL_DLL_FILES
"base/internal/low_level_alloc.cc"
"base/internal/low_level_alloc.h"
"base/internal/low_level_scheduling.h"
"base/internal/nullability_impl.h"
"base/internal/per_thread_tls.h"
"base/internal/prefetch.h"
"base/prefetch.h"
@ -54,6 +55,7 @@ set(ABSL_INTERNAL_DLL_FILES
"base/log_severity.cc"
"base/log_severity.h"
"base/macros.h"
"base/nullability.h"
"base/optimization.h"
"base/options.h"
"base/policy_checks.h"

@ -4,7 +4,7 @@ URL: https://github.com/abseil/abseil-cpp
License: Apache 2.0
License File: LICENSE
Version: 0
Revision: 049aa40e7ec9e37ed47c4dd2452affb13cd62ebe
Revision: 166d71d18f01aa73fd35aae611692320952a75b5
Security Critical: yes
Description:

@ -62,6 +62,18 @@ cc_library(
],
)
cc_library(
name = "nullability",
srcs = ["internal/nullability_impl.h"],
hdrs = ["nullability.h"],
copts = ABSL_DEFAULT_COPTS,
linkopts = ABSL_DEFAULT_LINKOPTS,
deps = [
":core_headers",
"//absl/meta:type_traits",
],
)
cc_library(
name = "raw_logging_internal",
srcs = ["internal/raw_logging.cc"],
@ -546,6 +558,16 @@ cc_test(
],
)
cc_test(
name = "nullability_test",
srcs = ["nullability_test.cc"],
deps = [
":core_headers",
":nullability",
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "raw_logging_test",
srcs = ["raw_logging_test.cc"],

@ -28,6 +28,15 @@ absl_source_set("log_severity") {
]
}
absl_source_set("nullability") {
sources = [ "internal/nullability_impl.h" ]
public = [ "nullability.h" ]
deps = [
":core_headers",
"//third_party/abseil-cpp/absl/meta:type_traits",
]
}
absl_source_set("raw_logging_internal") {
sources = [ "internal/raw_logging.cc" ]
public = [ "internal/raw_logging.h" ]
@ -294,3 +303,11 @@ absl_test("config_test") {
"//third_party/abseil-cpp/absl/synchronization:thread_pool",
]
}
absl_test("nullability_test") {
sources = [ "nullability_test.cc" ]
deps = [
":core_headers",
":nullability",
]
}

@ -54,6 +54,33 @@ absl_cc_library(
${ABSL_DEFAULT_COPTS}
)
absl_cc_library(
NAME
nullability
HDRS
"nullability.h"
SRCS
"internal/nullability_impl.h"
DEPS
absl::core_headers
absl::type_traits
COPTS
${ABSL_DEFAULT_COPTS}
)
absl_cc_test(
NAME
nullability_test
SRCS
"nullability_test.cc"
COPTS
${ABSL_TEST_COPTS}
DEPS
absl::core_headers
absl::nullability
GTest::gtest_main
)
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME

@ -0,0 +1,106 @@
// Copyright 2023 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
//
// https://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.
#ifndef ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_
#define ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_
#include <memory>
#include <type_traits>
#include "absl/base/attributes.h"
#include "absl/meta/type_traits.h"
namespace absl {
namespace nullability_internal {
// `IsNullabilityCompatible` checks whether its first argument is a class
// explicitly tagged as supporting nullability annotations. The tag is the type
// declaration `absl_nullability_compatible`.
template <typename, typename = void>
struct IsNullabilityCompatible : std::false_type {};
template <typename T>
struct IsNullabilityCompatible<
T, absl::void_t<typename T::absl_nullability_compatible>> : std::true_type {
};
template <typename T>
constexpr bool IsSupportedType = IsNullabilityCompatible<T>::value;
template <typename T>
constexpr bool IsSupportedType<T*> = true;
template <typename T, typename U>
constexpr bool IsSupportedType<T U::*> = true;
template <typename T, typename... Deleter>
constexpr bool IsSupportedType<std::unique_ptr<T, Deleter...>> = true;
template <typename T>
constexpr bool IsSupportedType<std::shared_ptr<T>> = true;
template <typename T>
struct EnableNullable {
static_assert(nullability_internal::IsSupportedType<std::remove_cv_t<T>>,
"Template argument must be a raw or supported smart pointer "
"type. See absl/base/nullability.h.");
using type = T;
};
template <typename T>
struct EnableNonNull {
static_assert(nullability_internal::IsSupportedType<std::remove_cv_t<T>>,
"Template argument must be a raw or supported smart pointer "
"type. See absl/base/nullability.h.");
using type = T;
};
template <typename T>
struct EnableNullabilityUnknown {
static_assert(nullability_internal::IsSupportedType<std::remove_cv_t<T>>,
"Template argument must be a raw or supported smart pointer "
"type. See absl/base/nullability.h.");
using type = T;
};
// Note: we do not apply Clang nullability attributes (e.g. _Nullable). These
// only support raw pointers, and conditionally enabling them only for raw
// pointers inhibits template arg deduction. Ideally, they would support all
// pointer-like types.
template <typename T, typename = typename EnableNullable<T>::type>
using NullableImpl
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
[[clang::annotate("Nullable")]]
#endif
= T;
template <typename T, typename = typename EnableNonNull<T>::type>
using NonNullImpl
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
[[clang::annotate("Nonnull")]]
#endif
= T;
template <typename T, typename = typename EnableNullabilityUnknown<T>::type>
using NullabilityUnknownImpl
#if ABSL_HAVE_CPP_ATTRIBUTE(clang::annotate)
[[clang::annotate("Nullability_Unspecified")]]
#endif
= T;
} // namespace nullability_internal
} // namespace absl
#endif // ABSL_BASE_INTERNAL_NULLABILITY_IMPL_H_

@ -58,18 +58,19 @@ void AllocateThreadIdentityKey(ThreadIdentityReclaimerFunction reclaimer) {
// that protected visibility is unsupported.
ABSL_CONST_INIT // Must come before __attribute__((visibility("protected")))
#if ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__)
__attribute__((visibility("protected")))
__attribute__((visibility("protected")))
#endif // ABSL_HAVE_ATTRIBUTE(visibility) && !defined(__APPLE__)
#if ABSL_PER_THREAD_TLS
// Prefer __thread to thread_local as benchmarks indicate it is a bit faster.
ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr = nullptr;
// Prefer __thread to thread_local as benchmarks indicate it is a bit
// faster.
ABSL_PER_THREAD_TLS_KEYWORD ThreadIdentity* thread_identity_ptr = nullptr;
#elif defined(ABSL_HAVE_THREAD_LOCAL)
thread_local ThreadIdentity* thread_identity_ptr = nullptr;
thread_local ThreadIdentity* thread_identity_ptr = nullptr;
#endif // ABSL_PER_THREAD_TLS
#endif // TLS or CPP11
void SetCurrentThreadIdentity(
ThreadIdentity* identity, ThreadIdentityReclaimerFunction reclaimer) {
void SetCurrentThreadIdentity(ThreadIdentity* identity,
ThreadIdentityReclaimerFunction reclaimer) {
assert(CurrentThreadIdentityIfPresent() == nullptr);
// Associate our destructor.
// NOTE: This call to pthread_setspecific is currently the only immovable
@ -134,7 +135,7 @@ void ClearCurrentThreadIdentity() {
ABSL_THREAD_IDENTITY_MODE == ABSL_THREAD_IDENTITY_MODE_USE_CPP11
thread_identity_ptr = nullptr;
#elif ABSL_THREAD_IDENTITY_MODE == \
ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
ABSL_THREAD_IDENTITY_MODE_USE_POSIX_SETSPECIFIC
// pthread_setspecific expected to clear value on destruction
assert(CurrentThreadIdentityIfPresent() == nullptr);
#endif

@ -62,8 +62,8 @@ struct PerThreadSynch {
return reinterpret_cast<ThreadIdentity*>(this);
}
PerThreadSynch *next; // Circular waiter queue; initialized to 0.
PerThreadSynch *skip; // If non-zero, all entries in Mutex queue
PerThreadSynch* next; // Circular waiter queue; initialized to 0.
PerThreadSynch* skip; // If non-zero, all entries in Mutex queue
// up to and including "skip" have same
// condition as this, and will be woken later
bool may_skip; // if false while on mutex queue, a mutex unlocker
@ -104,10 +104,7 @@ struct PerThreadSynch {
//
// Transitions from kAvailable to kQueued require no barrier, they
// are externally ordered by the Mutex.
enum State {
kAvailable,
kQueued
};
enum State { kAvailable, kQueued };
std::atomic<State> state;
// The wait parameters of the current wait. waitp is null if the
@ -122,14 +119,14 @@ struct PerThreadSynch {
// pointer unchanged.
SynchWaitParams* waitp;
intptr_t readers; // Number of readers in mutex.
intptr_t readers; // Number of readers in mutex.
// When priority will next be read (cycles).
int64_t next_priority_read_cycles;
// Locks held; used during deadlock detection.
// Allocated in Synch_GetAllLocks() and freed in ReclaimThreadIdentity().
SynchLocksHeld *all_locks;
SynchLocksHeld* all_locks;
};
// The instances of this class are allocated in NewThreadIdentity() with an
@ -220,7 +217,7 @@ void ClearCurrentThreadIdentity();
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
#elif defined(__APPLE__) && defined(ABSL_HAVE_THREAD_LOCAL)
#define ABSL_THREAD_IDENTITY_MODE ABSL_THREAD_IDENTITY_MODE_USE_CPP11
#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
#elif ABSL_PER_THREAD_TLS && defined(__GOOGLE_GRTE_VERSION__) && \
(__GOOGLE_GRTE_VERSION__ >= 20140228L)
// Support for async-safe TLS was specifically added in GRTEv4. It's not
// present in the upstream eglibc.

@ -0,0 +1,224 @@
// Copyright 2023 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
//
// https://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.
//
// -----------------------------------------------------------------------------
// File: nullability.h
// -----------------------------------------------------------------------------
//
// This header file defines a set of "templated annotations" for designating the
// expected nullability of pointers. These annotations allow you to designate
// pointers in one of three classification states:
//
// * "Non-null" (for pointers annotated `NonNull<T>`), indicating that it is
// invalid for the given pointer to ever be null.
// * "Nullable" (for pointers annotated `Nullable<T>`), indicating that it is
// valid for the given pointer to be null.
// * "Unknown" (for pointers annotated `NullabilityUnknown<T>`), indicating
// that the given pointer has not been yet classified as either nullable or
// non-null. This is the default state of unannotated pointers.
//
// NOTE: unannotated pointers implicitly bear the annotation
// `NullabilityUnknown<T>`; you should rarely, if ever, see this annotation used
// in the codebase explicitly.
//
// -----------------------------------------------------------------------------
// Nullability and Contracts
// -----------------------------------------------------------------------------
//
// These nullability annotations allow you to more clearly specify contracts on
// software components by narrowing the *preconditions*, *postconditions*, and
// *invariants* of pointer state(s) in any given interface. It then depends on
// context who is responsible for fulfilling the annotation's requirements.
//
// For example, a function may receive a pointer argument. Designating that
// pointer argument as "non-null" tightens the precondition of the contract of
// that function. It is then the responsibility of anyone calling such a
// function to ensure that the passed pointer is not null.
//
// Similarly, a function may have a pointer as a return value. Designating that
// return value as "non-null" tightens the postcondition of the contract of that
// function. In this case, however, it is the responsibility of the function
// itself to ensure that the returned pointer is not null.
//
// Clearly defining these contracts allows providers (and consumers) of such
// pointers to have more confidence in their null state. If a function declares
// a return value as "non-null", for example, the caller should not need to
// check whether the returned value is `nullptr`; it can simply assume the
// pointer is valid.
//
// Of course most interfaces already have expectations on the nullability state
// of pointers, and these expectations are, in effect, a contract; often,
// however, those contracts are either poorly or partially specified, assumed,
// or misunderstood. These nullability annotations are designed to allow you to
// formalize those contracts within the codebase.
//
// -----------------------------------------------------------------------------
// Using Nullability Annotations
// -----------------------------------------------------------------------------
//
// It is important to note that these annotations are not distinct strong
// *types*. They are alias templates defined to be equal to the underlying
// pointer type. A pointer annotated `NonNull<T*>`, for example, is simply a
// pointer of type `T*`. Each annotation acts as a form of documentation about
// the contract for the given pointer. Each annotation requires providers or
// consumers of these pointers across API boundaries to take appropriate steps
// when setting or using these pointers:
//
// * "Non-null" pointers should never be null. It is the responsibility of the
// provider of this pointer to ensure that the pointer may never be set to
// null. Consumers of such pointers can treat such pointers as non-null.
// * "Nullable" pointers may or may not be null. Consumers of such pointers
// should precede any usage of that pointer (e.g. a dereference operation)
// with a a `nullptr` check.
// * "Unknown" pointers may be either "non-null" or "nullable" but have not been
// definitively determined to be in either classification state. Providers of
// such pointers across API boundaries should determine -- over time -- to
// annotate the pointer in either of the above two states. Consumers of such
// pointers across an API boundary should continue to treat such pointers as
// they currently do.
//
// Example:
//
// // PaySalary() requires the passed pointer to an `Employee` to be non-null.
// void PaySalary(absl::NonNull<Employee *> e) {
// pay(e->salary); // OK to dereference
// }
//
// // CompleteTransaction() guarantees the returned pointer to an `Account` to
// // be non-null.
// absl::NonNull<Account *> balance CompleteTransaction(double fee) {
// ...
// }
//
// // Note that specifying a nullability annotation does not prevent someone
// // from violating the contract:
//
// Nullable<Employee *> find(Map& employees, std::string_view name);
//
// void g(Map& employees) {
// Employee *e = find(employees, "Pat");
// // `e` can now be null.
// PaySalary(e); // Violates contract, but compiles!
// }
//
// Nullability annotations, in other words, are useful for defining and
// narrowing contracts; *enforcement* of those contracts depends on use and any
// additional (static or dynamic analysis) tooling.
//
// NOTE: The "unknown" annotation state indicates that a pointer's contract has
// not yet been positively identified. The unknown state therefore acts as a
// form of documentation of your technical debt, and a codebase that adopts
// nullability annotations should aspire to annotate every pointer as either
// "non-null" or "nullable".
//
// -----------------------------------------------------------------------------
// Applicability of Nullability Annotations
// -----------------------------------------------------------------------------
//
// By default, nullability annotations are applicable to raw and smart
// pointers. User-defined types can indicate compatibility with nullability
// annotations by providing an `absl_nullability_compatible` nested type. The
// actual definition of this inner type is not relevant as it is used merely as
// a marker. It is common to use a using declaration of
// `absl_nullability_compatible` set to void.
//
// // Example:
// struct MyPtr {
// using absl_nullability_compatible = void;
// ...
// };
//
// DISCLAIMER:
// ===========================================================================
// These nullability annotations are primarily a human readable signal about the
// intended contract of the pointer. They are not *types* and do not currently
// provide any correctness guarantees. For example, a pointer annotated as
// `NonNull<T*>` is *not guaranteed* to be non-null, and the compiler won't
// alert or prevent assignment of a `Nullable<T*>` to a `NonNull<T*>`.
// ===========================================================================
#ifndef ABSL_BASE_NULLABILITY_H_
#define ABSL_BASE_NULLABILITY_H_
#include "absl/base/internal/nullability_impl.h"
namespace absl {
// absl::NonNull
//
// The indicated pointer is never null. It is the responsibility of the provider
// of this pointer across an API boundary to ensure that the pointer is never be
// set to null. Consumers of this pointer across an API boundary may safely
// dereference the pointer.
//
// Example:
//
// // `employee` is designated as not null.
// void PaySalary(absl::NotNull<Employee *> employee) {
// pay(*employee); // OK to dereference
// }
template <typename T>
using NonNull = nullability_internal::NonNullImpl<T>;
// absl::Nullable
//
// The indicated pointer may, by design, be either null or non-null. Consumers
// of this pointer across an API boundary should perform a `nullptr` check
// before performing any operation using the pointer.
//
// Example:
//
// // `employee` may be null.
// void PaySalary(absl::Nullable<Employee *> employee) {
// if (employee != nullptr) {
// Pay(*employee); // OK to dereference
// }
// }
template <typename T>
using Nullable = nullability_internal::NullableImpl<T>;
// absl::NullabilityUnknown (default)
//
// The indicated pointer has not yet been determined to be definitively
// "non-null" or "nullable." Providers of such pointers across API boundaries
// should, over time, annotate such pointers as either "non-null" or "nullable."
// Consumers of these pointers across an API boundary should treat such pointers
// with the same caution they treat currently unannotated pointers. Most
// existing code will have "unknown" pointers, which should eventually be
// migrated into one of the above two nullability states: `NonNull<T>` or
// `Nullable<T>`.
//
// NOTE: Because this annotation is the global default state, pointers without
// any annotation are assumed to have "unknown" semantics. This assumption is
// designed to minimize churn and reduce clutter within the codebase.
//
// Example:
//
// // `employee`s nullability state is unknown.
// void PaySalary(absl::NullabilityUnknown<Employee *> employee) {
// Pay(*employee); // Potentially dangerous. API provider should investigate.
// }
//
// Note that a pointer without an annotation, by default, is assumed to have the
// annotation `NullabilityUnknown`.
//
// // `employee`s nullability state is unknown.
// void PaySalary(Employee* employee) {
// Pay(*employee); // Potentially dangerous. API provider should investigate.
// }
template <typename T>
using NullabilityUnknown = nullability_internal::NullabilityUnknownImpl<T>;
} // namespace absl
#endif // ABSL_BASE_NULLABILITY_H_

@ -0,0 +1,129 @@
// Copyright 2023 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
//
// https://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.
#include "absl/base/nullability.h"
#include <cassert>
#include <memory>
#include <utility>
#include "gtest/gtest.h"
#include "absl/base/attributes.h"
namespace {
using ::absl::NonNull;
using ::absl::NullabilityUnknown;
using ::absl::Nullable;
void funcWithNonnullArg(NonNull<int*> /*arg*/) {}
template <typename T>
void funcWithDeducedNonnullArg(NonNull<T*> /*arg*/) {}
TEST(NonNullTest, NonNullArgument) {
int var = 0;
funcWithNonnullArg(&var);
funcWithDeducedNonnullArg(&var);
}
NonNull<int*> funcWithNonnullReturn() {
static int var = 0;
return &var;
}
TEST(NonNullTest, NonNullReturn) {
auto var = funcWithNonnullReturn();
(void)var;
}
TEST(PassThroughTest, PassesThroughRawPointerToInt) {
EXPECT_TRUE((std::is_same<NonNull<int*>, int*>::value));
EXPECT_TRUE((std::is_same<Nullable<int*>, int*>::value));
EXPECT_TRUE((std::is_same<NullabilityUnknown<int*>, int*>::value));
}
TEST(PassThroughTest, PassesThroughRawPointerToVoid) {
EXPECT_TRUE((std::is_same<NonNull<void*>, void*>::value));
EXPECT_TRUE((std::is_same<Nullable<void*>, void*>::value));
EXPECT_TRUE((std::is_same<NullabilityUnknown<void*>, void*>::value));
}
TEST(PassThroughTest, PassesThroughUniquePointerToInt) {
using T = std::unique_ptr<int>;
EXPECT_TRUE((std::is_same<NonNull<T>, T>::value));
EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
}
TEST(PassThroughTest, PassesThroughSharedPointerToInt) {
using T = std::shared_ptr<int>;
EXPECT_TRUE((std::is_same<NonNull<T>, T>::value));
EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
}
TEST(PassThroughTest, PassesThroughSharedPointerToVoid) {
using T = std::shared_ptr<void>;
EXPECT_TRUE((std::is_same<NonNull<T>, T>::value));
EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
}
TEST(PassThroughTest, PassesThroughPointerToMemberObject) {
using T = decltype(&std::pair<int, int>::first);
EXPECT_TRUE((std::is_same<NonNull<T>, T>::value));
EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
}
TEST(PassThroughTest, PassesThroughPointerToMemberFunction) {
using T = decltype(&std::unique_ptr<int>::reset);
EXPECT_TRUE((std::is_same<NonNull<T>, T>::value));
EXPECT_TRUE((std::is_same<Nullable<T>, T>::value));
EXPECT_TRUE((std::is_same<NullabilityUnknown<T>, T>::value));
}
} // namespace
// Nullable ADL lookup test
namespace util {
// Helper for NullableAdlTest. Returns true, denoting that argument-dependent
// lookup found this implementation of DidAdlWin. Must be in namespace
// util itself, not a nested anonymous namespace.
template <typename T>
bool DidAdlWin(T*) {
return true;
}
// Because this type is defined in namespace util, an unqualified call to
// DidAdlWin with a pointer to MakeAdlWin will find the above implementation.
struct MakeAdlWin {};
} // namespace util
namespace {
// Returns false, denoting that ADL did not inspect namespace util. If it
// had, the better match (T*) above would have won out over the (...) here.
bool DidAdlWin(...) { return false; }
TEST(NullableAdlTest, NullableAddsNothingToArgumentDependentLookup) {
// Treatment: util::Nullable<int*> contributes nothing to ADL because
// int* itself doesn't.
EXPECT_FALSE(DidAdlWin((int*)nullptr));
EXPECT_FALSE(DidAdlWin((Nullable<int*>)nullptr));
// Control: Argument-dependent lookup does find the implementation in
// namespace util when the underlying pointee type resides there.
EXPECT_TRUE(DidAdlWin((util::MakeAdlWin*)nullptr));
EXPECT_TRUE(DidAdlWin((Nullable<util::MakeAdlWin*>)nullptr));
}
} // namespace

@ -13,6 +13,7 @@
#include <cassert>
#include <cstdint>
#include <iostream>
#include <limits>
#include "absl/base/attributes.h"
#include "absl/debugging/internal/address_is_readable.h"

@ -500,8 +500,12 @@ using swap_internal::StdSwapIsUnconstrained;
// there.
//
// TODO(b/275003464): remove the opt-out once the bug is fixed.
#if ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && \
!(defined(__clang__) && (defined(_WIN32) || defined(_WIN64)))
//
// According to https://github.com/abseil/abseil-cpp/issues/1479, this does not
// work with NVCC either.
#if ABSL_HAVE_BUILTIN(__is_trivially_relocatable) && \
!(defined(__clang__) && (defined(_WIN32) || defined(_WIN64))) && \
!defined(__NVCC__)
template <class T>
struct is_trivially_relocatable
: std::integral_constant<bool, __is_trivially_relocatable(T)> {};

@ -47,8 +47,10 @@ static constexpr size_t kSeedSizeT = Randen::kSeedBytes / sizeof(uint32_t);
// Randen implementation benchmarks.
template <typename T>
struct AbsorbFn : public T {
mutable uint64_t state[kStateSizeT] = {};
mutable uint32_t seed[kSeedSizeT] = {};
// These are both cast to uint128* in the RandenHwAes implementation, so
// ensure they are 16 byte aligned.
alignas(16) mutable uint64_t state[kStateSizeT] = {};
alignas(16) mutable uint32_t seed[kSeedSizeT] = {};
static constexpr size_t bytes() { return sizeof(seed); }

@ -13,6 +13,7 @@
// limitations under the License.
#include <stdint.h>
#include <new>
// This file is a no-op if the required LowLevelAlloc support is missing.

File diff suppressed because it is too large Load Diff

@ -141,8 +141,9 @@ struct SynchWaitParams;
// issues that could potentially result in race conditions and deadlocks.
//
// For more information about the lock annotations, please see
// [Thread Safety Analysis](http://clang.llvm.org/docs/ThreadSafetyAnalysis.html)
// in the Clang documentation.
// [Thread Safety
// Analysis](http://clang.llvm.org/docs/ThreadSafetyAnalysis.html) in the Clang
// documentation.
//
// See also `MutexLock`, below, for scoped `Mutex` acquisition.
@ -323,7 +324,7 @@ class ABSL_LOCKABLE Mutex {
// `true`, `Await()` *may* skip the release/re-acquire step.
//
// `Await()` requires that this thread holds this `Mutex` in some mode.
void Await(const Condition &cond);
void Await(const Condition& cond);
// Mutex::LockWhen()
// Mutex::ReaderLockWhen()
@ -333,11 +334,11 @@ class ABSL_LOCKABLE Mutex {
// be acquired, then atomically acquires this `Mutex`. `LockWhen()` is
// logically equivalent to `*Lock(); Await();` though they may have different
// performance characteristics.
void LockWhen(const Condition &cond) ABSL_EXCLUSIVE_LOCK_FUNCTION();
void LockWhen(const Condition& cond) ABSL_EXCLUSIVE_LOCK_FUNCTION();
void ReaderLockWhen(const Condition &cond) ABSL_SHARED_LOCK_FUNCTION();
void ReaderLockWhen(const Condition& cond) ABSL_SHARED_LOCK_FUNCTION();
void WriterLockWhen(const Condition &cond) ABSL_EXCLUSIVE_LOCK_FUNCTION() {
void WriterLockWhen(const Condition& cond) ABSL_EXCLUSIVE_LOCK_FUNCTION() {
this->LockWhen(cond);
}
@ -362,9 +363,9 @@ class ABSL_LOCKABLE Mutex {
// Negative timeouts are equivalent to a zero timeout.
//
// This method requires that this thread holds this `Mutex` in some mode.
bool AwaitWithTimeout(const Condition &cond, absl::Duration timeout);
bool AwaitWithTimeout(const Condition& cond, absl::Duration timeout);
bool AwaitWithDeadline(const Condition &cond, absl::Time deadline);
bool AwaitWithDeadline(const Condition& cond, absl::Time deadline);
// Mutex::LockWhenWithTimeout()
// Mutex::ReaderLockWhenWithTimeout()
@ -377,11 +378,11 @@ class ABSL_LOCKABLE Mutex {
// `true` on return.
//
// Negative timeouts are equivalent to a zero timeout.
bool LockWhenWithTimeout(const Condition &cond, absl::Duration timeout)
bool LockWhenWithTimeout(const Condition& cond, absl::Duration timeout)
ABSL_EXCLUSIVE_LOCK_FUNCTION();
bool ReaderLockWhenWithTimeout(const Condition &cond, absl::Duration timeout)
bool ReaderLockWhenWithTimeout(const Condition& cond, absl::Duration timeout)
ABSL_SHARED_LOCK_FUNCTION();
bool WriterLockWhenWithTimeout(const Condition &cond, absl::Duration timeout)
bool WriterLockWhenWithTimeout(const Condition& cond, absl::Duration timeout)
ABSL_EXCLUSIVE_LOCK_FUNCTION() {
return this->LockWhenWithTimeout(cond, timeout);
}
@ -397,11 +398,11 @@ class ABSL_LOCKABLE Mutex {
// on return.
//
// Deadlines in the past are equivalent to an immediate deadline.
bool LockWhenWithDeadline(const Condition &cond, absl::Time deadline)
bool LockWhenWithDeadline(const Condition& cond, absl::Time deadline)
ABSL_EXCLUSIVE_LOCK_FUNCTION();
bool ReaderLockWhenWithDeadline(const Condition &cond, absl::Time deadline)
bool ReaderLockWhenWithDeadline(const Condition& cond, absl::Time deadline)
ABSL_SHARED_LOCK_FUNCTION();
bool WriterLockWhenWithDeadline(const Condition &cond, absl::Time deadline)
bool WriterLockWhenWithDeadline(const Condition& cond, absl::Time deadline)
ABSL_EXCLUSIVE_LOCK_FUNCTION() {
return this->LockWhenWithDeadline(cond, deadline);
}
@ -423,7 +424,7 @@ class ABSL_LOCKABLE Mutex {
// substantially reduce `Mutex` performance; it should be set only for
// non-production runs. Optimization options may also disable invariant
// checks.
void EnableInvariantDebugging(void (*invariant)(void *), void *arg);
void EnableInvariantDebugging(void (*invariant)(void*), void* arg);
// Mutex::EnableDebugLog()
//
@ -432,7 +433,7 @@ class ABSL_LOCKABLE Mutex {
// call to `EnableInvariantDebugging()` or `EnableDebugLog()` has been made.
//
// Note: This method substantially reduces `Mutex` performance.
void EnableDebugLog(const char *name);
void EnableDebugLog(const char* name);
// Deadlock detection
@ -460,7 +461,7 @@ class ABSL_LOCKABLE Mutex {
// A `MuHow` is a constant that indicates how a lock should be acquired.
// Internal implementation detail. Clients should ignore.
typedef const struct MuHowS *MuHow;
typedef const struct MuHowS* MuHow;
// Mutex::InternalAttemptToUseMutexInFatalSignalHandler()
//
@ -482,37 +483,37 @@ class ABSL_LOCKABLE Mutex {
// Post()/Wait() versus associated PerThreadSem; in class for required
// friendship with PerThreadSem.
static void IncrementSynchSem(Mutex *mu, base_internal::PerThreadSynch *w);
static bool DecrementSynchSem(Mutex *mu, base_internal::PerThreadSynch *w,
static void IncrementSynchSem(Mutex* mu, base_internal::PerThreadSynch* w);
static bool DecrementSynchSem(Mutex* mu, base_internal::PerThreadSynch* w,
synchronization_internal::KernelTimeout t);
// slow path acquire
void LockSlowLoop(SynchWaitParams *waitp, int flags);
void LockSlowLoop(SynchWaitParams* waitp, int flags);
// wrappers around LockSlowLoop()
bool LockSlowWithDeadline(MuHow how, const Condition *cond,
bool LockSlowWithDeadline(MuHow how, const Condition* cond,
synchronization_internal::KernelTimeout t,
int flags);
void LockSlow(MuHow how, const Condition *cond,
void LockSlow(MuHow how, const Condition* cond,
int flags) ABSL_ATTRIBUTE_COLD;
// slow path release
void UnlockSlow(SynchWaitParams *waitp) ABSL_ATTRIBUTE_COLD;
void UnlockSlow(SynchWaitParams* waitp) ABSL_ATTRIBUTE_COLD;
// Common code between Await() and AwaitWithTimeout/Deadline()
bool AwaitCommon(const Condition &cond,
bool AwaitCommon(const Condition& cond,
synchronization_internal::KernelTimeout t);
// Attempt to remove thread s from queue.
void TryRemove(base_internal::PerThreadSynch *s);
void TryRemove(base_internal::PerThreadSynch* s);
// Block a thread on mutex.
void Block(base_internal::PerThreadSynch *s);
void Block(base_internal::PerThreadSynch* s);
// Wake a thread; return successor.
base_internal::PerThreadSynch *Wakeup(base_internal::PerThreadSynch *w);
base_internal::PerThreadSynch* Wakeup(base_internal::PerThreadSynch* w);
friend class CondVar; // for access to Trans()/Fer().
void Trans(MuHow how); // used for CondVar->Mutex transfer
void Fer(
base_internal::PerThreadSynch *w); // used for CondVar->Mutex transfer
base_internal::PerThreadSynch* w); // used for CondVar->Mutex transfer
// Catch the error of writing Mutex when intending MutexLock.
Mutex(const volatile Mutex * /*ignored*/) {} // NOLINT(runtime/explicit)
explicit Mutex(const volatile Mutex* /*ignored*/) {}
Mutex(const Mutex&) = delete;
Mutex& operator=(const Mutex&) = delete;
@ -547,28 +548,28 @@ class ABSL_SCOPED_LOCKABLE MutexLock {
// Calls `mu->Lock()` and returns when that call returns. That is, `*mu` is
// guaranteed to be locked when this object is constructed. Requires that
// `mu` be dereferenceable.
explicit MutexLock(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
explicit MutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu) : mu_(mu) {
this->mu_->Lock();
}
// Like above, but calls `mu->LockWhen(cond)` instead. That is, in addition to
// the above, the condition given by `cond` is also guaranteed to hold when
// this object is constructed.
explicit MutexLock(Mutex *mu, const Condition &cond)
explicit MutexLock(Mutex* mu, const Condition& cond)
ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
this->mu_->LockWhen(cond);
}
MutexLock(const MutexLock &) = delete; // NOLINT(runtime/mutex)
MutexLock(MutexLock&&) = delete; // NOLINT(runtime/mutex)
MutexLock(const MutexLock&) = delete; // NOLINT(runtime/mutex)
MutexLock(MutexLock&&) = delete; // NOLINT(runtime/mutex)
MutexLock& operator=(const MutexLock&) = delete;
MutexLock& operator=(MutexLock&&) = delete;
~MutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->Unlock(); }
private:
Mutex *const mu_;
Mutex* const mu_;
};
// ReaderMutexLock
@ -577,11 +578,11 @@ class ABSL_SCOPED_LOCKABLE MutexLock {
// releases a shared lock on a `Mutex` via RAII.
class ABSL_SCOPED_LOCKABLE ReaderMutexLock {
public:
explicit ReaderMutexLock(Mutex *mu) ABSL_SHARED_LOCK_FUNCTION(mu) : mu_(mu) {
explicit ReaderMutexLock(Mutex* mu) ABSL_SHARED_LOCK_FUNCTION(mu) : mu_(mu) {
mu->ReaderLock();
}
explicit ReaderMutexLock(Mutex *mu, const Condition &cond)
explicit ReaderMutexLock(Mutex* mu, const Condition& cond)
ABSL_SHARED_LOCK_FUNCTION(mu)
: mu_(mu) {
mu->ReaderLockWhen(cond);
@ -595,7 +596,7 @@ class ABSL_SCOPED_LOCKABLE ReaderMutexLock {
~ReaderMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->ReaderUnlock(); }
private:
Mutex *const mu_;
Mutex* const mu_;
};
// WriterMutexLock
@ -604,12 +605,12 @@ class ABSL_SCOPED_LOCKABLE ReaderMutexLock {
// releases a write (exclusive) lock on a `Mutex` via RAII.
class ABSL_SCOPED_LOCKABLE WriterMutexLock {
public:
explicit WriterMutexLock(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
explicit WriterMutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
mu->WriterLock();
}
explicit WriterMutexLock(Mutex *mu, const Condition &cond)
explicit WriterMutexLock(Mutex* mu, const Condition& cond)
ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
mu->WriterLockWhen(cond);
@ -623,7 +624,7 @@ class ABSL_SCOPED_LOCKABLE WriterMutexLock {
~WriterMutexLock() ABSL_UNLOCK_FUNCTION() { this->mu_->WriterUnlock(); }
private:
Mutex *const mu_;
Mutex* const mu_;
};
// -----------------------------------------------------------------------------
@ -681,7 +682,7 @@ class ABSL_SCOPED_LOCKABLE WriterMutexLock {
class Condition {
public:
// A Condition that returns the result of "(*func)(arg)"
Condition(bool (*func)(void *), void *arg);
Condition(bool (*func)(void*), void* arg);
// Templated version for people who are averse to casts.
//
@ -692,8 +693,8 @@ class Condition {
// Note: lambdas in this case must contain no bound variables.
//
// See class comment for performance advice.
template<typename T>
Condition(bool (*func)(T *), T *arg);
template <typename T>
Condition(bool (*func)(T*), T* arg);
// Same as above, but allows for cases where `arg` comes from a pointer that
// is convertible to the function parameter type `T*` but not an exact match.
@ -707,7 +708,7 @@ class Condition {
// a function template is passed as `func`. Also, the dummy `typename = void`
// template parameter exists just to work around a MSVC mangling bug.
template <typename T, typename = void>
Condition(bool (*func)(T *), typename absl::internal::identity<T>::type *arg);
Condition(bool (*func)(T*), typename absl::internal::identity<T>::type* arg);
// Templated version for invoking a method that returns a `bool`.
//
@ -717,16 +718,16 @@ class Condition {
// Implementation Note: `absl::internal::identity` is used to allow methods to
// come from base classes. A simpler signature like
// `Condition(T*, bool (T::*)())` does not suffice.
template<typename T>
Condition(T *object, bool (absl::internal::identity<T>::type::* method)());
template <typename T>
Condition(T* object, bool (absl::internal::identity<T>::type::*method)());
// Same as above, for const members
template<typename T>
Condition(const T *object,
bool (absl::internal::identity<T>::type::* method)() const);
template <typename T>
Condition(const T* object,
bool (absl::internal::identity<T>::type::*method)() const);
// A Condition that returns the value of `*cond`
explicit Condition(const bool *cond);
explicit Condition(const bool* cond);
// Templated version for invoking a functor that returns a `bool`.
// This approach accepts pointers to non-mutable lambdas, `std::function`,
@ -753,9 +754,9 @@ class Condition {
// Implementation note: The second template parameter ensures that this
// constructor doesn't participate in overload resolution if T doesn't have
// `bool operator() const`.
template <typename T, typename E = decltype(
static_cast<bool (T::*)() const>(&T::operator()))>
explicit Condition(const T *obj)
template <typename T, typename E = decltype(static_cast<bool (T::*)() const>(
&T::operator()))>
explicit Condition(const T* obj)
: Condition(obj, static_cast<bool (T::*)() const>(&T::operator())) {}
// A Condition that always returns `true`.
@ -771,7 +772,7 @@ class Condition {
// Two `Condition` values are guaranteed equal if both their `func` and `arg`
// components are the same. A null pointer is equivalent to a `true`
// condition.
static bool GuaranteedEqual(const Condition *a, const Condition *b);
static bool GuaranteedEqual(const Condition* a, const Condition* b);
private:
// Sizing an allocation for a method pointer can be subtle. In the Itanium
@ -799,12 +800,14 @@ class Condition {
bool (*eval_)(const Condition*) = nullptr;
// Either an argument for a function call or an object for a method call.
void *arg_ = nullptr;
void* arg_ = nullptr;
// Various functions eval_ can point to:
static bool CallVoidPtrFunction(const Condition*);
template <typename T> static bool CastAndCallFunction(const Condition* c);
template <typename T> static bool CastAndCallMethod(const Condition* c);
template <typename T>
static bool CastAndCallFunction(const Condition* c);
template <typename T>
static bool CastAndCallMethod(const Condition* c);
// Helper methods for storing, validating, and reading callback arguments.
template <typename T>
@ -816,7 +819,7 @@ class Condition {
}
template <typename T>
inline void ReadCallback(T *callback) const {
inline void ReadCallback(T* callback) const {
std::memcpy(callback, callback_, sizeof(*callback));
}
@ -873,7 +876,7 @@ class CondVar {
// spurious wakeup), then reacquires the `Mutex` and returns.
//
// Requires and ensures that the current thread holds the `Mutex`.
void Wait(Mutex *mu);
void Wait(Mutex* mu);
// CondVar::WaitWithTimeout()
//
@ -888,7 +891,7 @@ class CondVar {
// to return `true` or `false`.
//
// Requires and ensures that the current thread holds the `Mutex`.
bool WaitWithTimeout(Mutex *mu, absl::Duration timeout);
bool WaitWithTimeout(Mutex* mu, absl::Duration timeout);
// CondVar::WaitWithDeadline()
//
@ -905,7 +908,7 @@ class CondVar {
// to return `true` or `false`.
//
// Requires and ensures that the current thread holds the `Mutex`.
bool WaitWithDeadline(Mutex *mu, absl::Time deadline);
bool WaitWithDeadline(Mutex* mu, absl::Time deadline);
// CondVar::Signal()
//
@ -922,18 +925,17 @@ class CondVar {
// Causes all subsequent uses of this `CondVar` to be logged via
// `ABSL_RAW_LOG(INFO)`. Log entries are tagged with `name` if `name != 0`.
// Note: this method substantially reduces `CondVar` performance.
void EnableDebugLog(const char *name);
void EnableDebugLog(const char* name);
private:
bool WaitCommon(Mutex *mutex, synchronization_internal::KernelTimeout t);
void Remove(base_internal::PerThreadSynch *s);
void Wakeup(base_internal::PerThreadSynch *w);
bool WaitCommon(Mutex* mutex, synchronization_internal::KernelTimeout t);
void Remove(base_internal::PerThreadSynch* s);
void Wakeup(base_internal::PerThreadSynch* w);
std::atomic<intptr_t> cv_; // Condition variable state.
CondVar(const CondVar&) = delete;
CondVar& operator=(const CondVar&) = delete;
};
// Variants of MutexLock.
//
// If you find yourself using one of these, consider instead using
@ -944,14 +946,14 @@ class CondVar {
// MutexLockMaybe is like MutexLock, but is a no-op when mu is null.
class ABSL_SCOPED_LOCKABLE MutexLockMaybe {
public:
explicit MutexLockMaybe(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
explicit MutexLockMaybe(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
if (this->mu_ != nullptr) {
this->mu_->Lock();
}
}
explicit MutexLockMaybe(Mutex *mu, const Condition &cond)
explicit MutexLockMaybe(Mutex* mu, const Condition& cond)
ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
if (this->mu_ != nullptr) {
@ -960,11 +962,13 @@ class ABSL_SCOPED_LOCKABLE MutexLockMaybe {
}
~MutexLockMaybe() ABSL_UNLOCK_FUNCTION() {
if (this->mu_ != nullptr) { this->mu_->Unlock(); }
if (this->mu_ != nullptr) {
this->mu_->Unlock();
}
}
private:
Mutex *const mu_;
Mutex* const mu_;
MutexLockMaybe(const MutexLockMaybe&) = delete;
MutexLockMaybe(MutexLockMaybe&&) = delete;
MutexLockMaybe& operator=(const MutexLockMaybe&) = delete;
@ -977,25 +981,27 @@ class ABSL_SCOPED_LOCKABLE MutexLockMaybe {
// mutex before destruction. `Release()` may be called at most once.
class ABSL_SCOPED_LOCKABLE ReleasableMutexLock {
public:
explicit ReleasableMutexLock(Mutex *mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
explicit ReleasableMutexLock(Mutex* mu) ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
this->mu_->Lock();
}
explicit ReleasableMutexLock(Mutex *mu, const Condition &cond)
explicit ReleasableMutexLock(Mutex* mu, const Condition& cond)
ABSL_EXCLUSIVE_LOCK_FUNCTION(mu)
: mu_(mu) {
this->mu_->LockWhen(cond);
}
~ReleasableMutexLock() ABSL_UNLOCK_FUNCTION() {
if (this->mu_ != nullptr) { this->mu_->Unlock(); }
if (this->mu_ != nullptr) {
this->mu_->Unlock();
}
}
void Release() ABSL_UNLOCK_FUNCTION();
private:
Mutex *mu_;
Mutex* mu_;
ReleasableMutexLock(const ReleasableMutexLock&) = delete;
ReleasableMutexLock(ReleasableMutexLock&&) = delete;
ReleasableMutexLock& operator=(const ReleasableMutexLock&) = delete;
@ -1012,8 +1018,8 @@ inline CondVar::CondVar() : cv_(0) {}
// static
template <typename T>
bool Condition::CastAndCallMethod(const Condition *c) {
T *object = static_cast<T *>(c->arg_);
bool Condition::CastAndCallMethod(const Condition* c) {
T* object = static_cast<T*>(c->arg_);
bool (T::*method_pointer)();
c->ReadCallback(&method_pointer);
return (object->*method_pointer)();
@ -1021,44 +1027,43 @@ bool Condition::CastAndCallMethod(const Condition *c) {
// static
template <typename T>
bool Condition::CastAndCallFunction(const Condition *c) {
bool (*function)(T *);
bool Condition::CastAndCallFunction(const Condition* c) {
bool (*function)(T*);
c->ReadCallback(&function);
T *argument = static_cast<T *>(c->arg_);
T* argument = static_cast<T*>(c->arg_);
return (*function)(argument);
}
template <typename T>
inline Condition::Condition(bool (*func)(T *), T *arg)
inline Condition::Condition(bool (*func)(T*), T* arg)
: eval_(&CastAndCallFunction<T>),
arg_(const_cast<void *>(static_cast<const void *>(arg))) {
arg_(const_cast<void*>(static_cast<const void*>(arg))) {
static_assert(sizeof(&func) <= sizeof(callback_),
"An overlarge function pointer was passed to Condition.");
StoreCallback(func);
}
template <typename T, typename>
inline Condition::Condition(bool (*func)(T *),
typename absl::internal::identity<T>::type *arg)
inline Condition::Condition(bool (*func)(T*),
typename absl::internal::identity<T>::type* arg)
// Just delegate to the overload above.
: Condition(func, arg) {}
template <typename T>
inline Condition::Condition(T *object,
inline Condition::Condition(T* object,
bool (absl::internal::identity<T>::type::*method)())
: eval_(&CastAndCallMethod<T>),
arg_(object) {
: eval_(&CastAndCallMethod<T>), arg_(object) {
static_assert(sizeof(&method) <= sizeof(callback_),
"An overlarge method pointer was passed to Condition.");
StoreCallback(method);
}
template <typename T>
inline Condition::Condition(const T *object,
inline Condition::Condition(const T* object,
bool (absl::internal::identity<T>::type::*method)()
const)
: eval_(&CastAndCallMethod<T>),
arg_(reinterpret_cast<void *>(const_cast<T *>(object))) {
arg_(reinterpret_cast<void*>(const_cast<T*>(object))) {
StoreCallback(method);
}
@ -1088,7 +1093,7 @@ void RegisterMutexProfiler(void (*fn)(int64_t wait_cycles));
//
// This has the same ordering and single-use limitations as
// RegisterMutexProfiler() above.
void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj,
void RegisterMutexTracer(void (*fn)(const char* msg, const void* obj,
int64_t wait_cycles));
// Register a hook for CondVar tracing.
@ -1103,7 +1108,7 @@ void RegisterMutexTracer(void (*fn)(const char *msg, const void *obj,
//
// This has the same ordering and single-use limitations as
// RegisterMutexProfiler() above.
void RegisterCondVarTracer(void (*fn)(const char *msg, const void *cv));
void RegisterCondVarTracer(void (*fn)(const char* msg, const void* cv));
// EnableMutexInvariantDebugging()
//
@ -1120,7 +1125,7 @@ void EnableMutexInvariantDebugging(bool enabled);
enum class OnDeadlockCycle {
kIgnore, // Neither report on nor attempt to track cycles in lock ordering
kReport, // Report lock cycles to stderr when detected
kAbort, // Report lock cycles to stderr when detected, then abort
kAbort, // Report lock cycles to stderr when detected, then abort
};
// SetMutexDeadlockDetectionMode()

@ -1868,4 +1868,29 @@ TEST(Mutex, WriterPriority) {
EXPECT_TRUE(saw_wrote.load());
}
TEST(Mutex, LockWhenWithTimeoutResult) {
// Check various corner cases for Await/LockWhen return value
// with always true/always false conditions.
absl::Mutex mu;
const bool kAlwaysTrue = true, kAlwaysFalse = false;
const absl::Condition kTrueCond(&kAlwaysTrue), kFalseCond(&kAlwaysFalse);
EXPECT_TRUE(mu.LockWhenWithTimeout(kTrueCond, absl::Milliseconds(1)));
mu.Unlock();
EXPECT_FALSE(mu.LockWhenWithTimeout(kFalseCond, absl::Milliseconds(1)));
EXPECT_TRUE(mu.AwaitWithTimeout(kTrueCond, absl::Milliseconds(1)));
EXPECT_FALSE(mu.AwaitWithTimeout(kFalseCond, absl::Milliseconds(1)));
std::thread th1([&]() {
EXPECT_TRUE(mu.LockWhenWithTimeout(kTrueCond, absl::Milliseconds(1)));
mu.Unlock();
});
std::thread th2([&]() {
EXPECT_FALSE(mu.LockWhenWithTimeout(kFalseCond, absl::Milliseconds(1)));
mu.Unlock();
});
absl::SleepFor(absl::Milliseconds(100));
mu.Unlock();
th1.join();
th2.join();
}
} // namespace