File indexing completed on 2026-01-09 09:40:44
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
0016 #define ABSL_BASE_INTERNAL_ATOMIC_HOOK_H_
0017
0018 #include <atomic>
0019 #include <cassert>
0020 #include <cstdint>
0021 #include <utility>
0022
0023 #include "absl/base/attributes.h"
0024 #include "absl/base/config.h"
0025
0026 #if defined(_MSC_VER) && !defined(__clang__)
0027 #define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 0
0028 #else
0029 #define ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT 1
0030 #endif
0031
0032 #if defined(_MSC_VER)
0033 #define ABSL_HAVE_WORKING_ATOMIC_POINTER 0
0034 #else
0035 #define ABSL_HAVE_WORKING_ATOMIC_POINTER 1
0036 #endif
0037
0038 namespace absl {
0039 ABSL_NAMESPACE_BEGIN
0040 namespace base_internal {
0041
0042 template <typename T>
0043 class AtomicHook;
0044
0045
0046
0047
0048 #if ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
0049 #define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES ABSL_CONST_INIT
0050 #else
0051 #define ABSL_INTERNAL_ATOMIC_HOOK_ATTRIBUTES
0052 #endif
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071 template <typename ReturnType, typename... Args>
0072 class AtomicHook<ReturnType (*)(Args...)> {
0073 public:
0074 using FnPtr = ReturnType (*)(Args...);
0075
0076
0077
0078 constexpr AtomicHook() : AtomicHook(DummyFunction) {}
0079
0080
0081
0082 #if ABSL_HAVE_WORKING_ATOMIC_POINTER && ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
0083 explicit constexpr AtomicHook(FnPtr default_fn)
0084 : hook_(default_fn), default_fn_(default_fn) {}
0085 #elif ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
0086 explicit constexpr AtomicHook(FnPtr default_fn)
0087 : hook_(kUninitialized), default_fn_(default_fn) {}
0088 #else
0089
0090
0091
0092
0093
0094
0095 explicit constexpr AtomicHook(FnPtr default_fn)
0096 : default_fn_(default_fn) {
0097 static_assert(kUninitialized == 0, "here we rely on zero-initialization");
0098 }
0099 #endif
0100
0101
0102
0103
0104
0105
0106
0107 void Store(FnPtr fn) {
0108 bool success = DoStore(fn);
0109 static_cast<void>(success);
0110 assert(success);
0111 }
0112
0113
0114
0115 template <typename... CallArgs>
0116 ReturnType operator()(CallArgs&&... args) const {
0117 return DoLoad()(std::forward<CallArgs>(args)...);
0118 }
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129 FnPtr Load() const {
0130 FnPtr ptr = DoLoad();
0131 return (ptr == DummyFunction) ? nullptr : ptr;
0132 }
0133
0134 private:
0135 static ReturnType DummyFunction(Args...) {
0136 return ReturnType();
0137 }
0138
0139
0140
0141
0142
0143
0144
0145
0146 #if ABSL_HAVE_WORKING_ATOMIC_POINTER
0147
0148 FnPtr DoLoad() const { return hook_.load(std::memory_order_acquire); }
0149
0150
0151
0152 bool DoStore(FnPtr fn) {
0153 assert(fn);
0154 FnPtr expected = default_fn_;
0155 const bool store_succeeded = hook_.compare_exchange_strong(
0156 expected, fn, std::memory_order_acq_rel, std::memory_order_acquire);
0157 const bool same_value_already_stored = (expected == fn);
0158 return store_succeeded || same_value_already_stored;
0159 }
0160
0161 std::atomic<FnPtr> hook_;
0162 #else
0163
0164 static constexpr intptr_t kUninitialized = 0;
0165
0166 static_assert(sizeof(intptr_t) >= sizeof(FnPtr),
0167 "intptr_t can't contain a function pointer");
0168
0169 FnPtr DoLoad() const {
0170 const intptr_t value = hook_.load(std::memory_order_acquire);
0171 if (value == kUninitialized) {
0172 return default_fn_;
0173 }
0174 return reinterpret_cast<FnPtr>(value);
0175 }
0176
0177 bool DoStore(FnPtr fn) {
0178 assert(fn);
0179 const auto value = reinterpret_cast<intptr_t>(fn);
0180 intptr_t expected = kUninitialized;
0181 const bool store_succeeded = hook_.compare_exchange_strong(
0182 expected, value, std::memory_order_acq_rel, std::memory_order_acquire);
0183 const bool same_value_already_stored = (expected == value);
0184 return store_succeeded || same_value_already_stored;
0185 }
0186
0187 std::atomic<intptr_t> hook_;
0188 #endif
0189
0190 const FnPtr default_fn_;
0191 };
0192
0193 #undef ABSL_HAVE_WORKING_ATOMIC_POINTER
0194 #undef ABSL_HAVE_WORKING_CONSTEXPR_STATIC_INIT
0195
0196 }
0197 ABSL_NAMESPACE_END
0198 }
0199
0200 #endif