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:

committed by
Chromium LUCI CQ

parent
e2b8d8360f
commit
79a40941bd
DEPS
styleguide/c++
third_party/abseil-cpp
BUILD.gn
CMake
README.chromiumabsl
base
debugging
internal
meta
random
internal
synchronization
1
DEPS
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.
|
||||
***
|
||||
|
2
third_party/abseil-cpp/BUILD.gn
vendored
2
third_party/abseil-cpp/BUILD.gn
vendored
@ -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.
|
||||
|
2
third_party/abseil-cpp/CMake/AbseilDll.cmake
vendored
2
third_party/abseil-cpp/CMake/AbseilDll.cmake
vendored
@ -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"
|
||||
|
2
third_party/abseil-cpp/README.chromium
vendored
2
third_party/abseil-cpp/README.chromium
vendored
@ -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:
|
||||
|
22
third_party/abseil-cpp/absl/base/BUILD.bazel
vendored
22
third_party/abseil-cpp/absl/base/BUILD.bazel
vendored
@ -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"],
|
||||
|
17
third_party/abseil-cpp/absl/base/BUILD.gn
vendored
17
third_party/abseil-cpp/absl/base/BUILD.gn
vendored
@ -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",
|
||||
]
|
||||
}
|
||||
|
27
third_party/abseil-cpp/absl/base/CMakeLists.txt
vendored
27
third_party/abseil-cpp/absl/base/CMakeLists.txt
vendored
@ -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
|
||||
|
106
third_party/abseil-cpp/absl/base/internal/nullability_impl.h
vendored
Normal file
106
third_party/abseil-cpp/absl/base/internal/nullability_impl.h
vendored
Normal file
@ -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.
|
||||
|
224
third_party/abseil-cpp/absl/base/nullability.h
vendored
Normal file
224
third_party/abseil-cpp/absl/base/nullability.h
vendored
Normal file
@ -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_
|
129
third_party/abseil-cpp/absl/base/nullability_test.cc
vendored
Normal file
129
third_party/abseil-cpp/absl/base/nullability_test.cc
vendored
Normal file
@ -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.
|
||||
|
714
third_party/abseil-cpp/absl/synchronization/mutex.cc
vendored
714
third_party/abseil-cpp/absl/synchronization/mutex.cc
vendored
File diff suppressed because it is too large
Load Diff
187
third_party/abseil-cpp/absl/synchronization/mutex.h
vendored
187
third_party/abseil-cpp/absl/synchronization/mutex.h
vendored
@ -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
|
||||
|
Reference in New Issue
Block a user