Merge branch 'arena-counting' into arena-test

pull/36772/head
Craig Tiller 8 months ago
commit 3cded84c73
  1. 1
      src/core/BUILD
  2. 18
      src/core/lib/gprpp/dual_ref_counted.h
  3. 38
      test/core/gprpp/dual_ref_counted_test.cc

@ -1236,6 +1236,7 @@ grpc_cc_library(
public_hdrs = ["lib/gprpp/dual_ref_counted.h"], public_hdrs = ["lib/gprpp/dual_ref_counted.h"],
deps = [ deps = [
"down_cast", "down_cast",
"ref_counted",
"//:debug_location", "//:debug_location",
"//:gpr", "//:gpr",
"//:orphanable", "//:orphanable",

@ -28,6 +28,7 @@
#include "src/core/lib/gprpp/debug_location.h" #include "src/core/lib/gprpp/debug_location.h"
#include "src/core/lib/gprpp/down_cast.h" #include "src/core/lib/gprpp/down_cast.h"
#include "src/core/lib/gprpp/orphanable.h" #include "src/core/lib/gprpp/orphanable.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "src/core/lib/gprpp/ref_counted_ptr.h" #include "src/core/lib/gprpp/ref_counted_ptr.h"
namespace grpc_core { namespace grpc_core {
@ -46,15 +47,16 @@ namespace grpc_core {
// //
// This will be used by CRTP (curiously-recurring template pattern), e.g.: // This will be used by CRTP (curiously-recurring template pattern), e.g.:
// class MyClass : public RefCounted<MyClass> { ... }; // class MyClass : public RefCounted<MyClass> { ... };
template <typename Child> //
class DualRefCounted { // Impl & UnrefBehavior are as per RefCounted.
template <typename Child, typename Impl = PolymorphicRefCount,
typename UnrefBehavior = UnrefDelete>
class DualRefCounted : public Impl {
public: public:
// Not copyable nor movable. // Not copyable nor movable.
DualRefCounted(const DualRefCounted&) = delete; DualRefCounted(const DualRefCounted&) = delete;
DualRefCounted& operator=(const DualRefCounted&) = delete; DualRefCounted& operator=(const DualRefCounted&) = delete;
virtual ~DualRefCounted() = default;
GRPC_MUST_USE_RESULT RefCountedPtr<Child> Ref() { GRPC_MUST_USE_RESULT RefCountedPtr<Child> Ref() {
IncrementRefCount(); IncrementRefCount();
return RefCountedPtr<Child>(static_cast<Child*>(this)); return RefCountedPtr<Child>(static_cast<Child*>(this));
@ -215,7 +217,7 @@ class DualRefCounted {
CHECK_GT(weak_refs, 0u); CHECK_GT(weak_refs, 0u);
#endif #endif
if (GPR_UNLIKELY(prev_ref_pair == MakeRefPair(0, 1))) { if (GPR_UNLIKELY(prev_ref_pair == MakeRefPair(0, 1))) {
delete static_cast<Child*>(this); unref_behavior_(static_cast<Child*>(this));
} }
} }
void WeakUnref(const DebugLocation& location, const char* reason) { void WeakUnref(const DebugLocation& location, const char* reason) {
@ -242,7 +244,7 @@ class DualRefCounted {
(void)reason; (void)reason;
#endif #endif
if (GPR_UNLIKELY(prev_ref_pair == MakeRefPair(0, 1))) { if (GPR_UNLIKELY(prev_ref_pair == MakeRefPair(0, 1))) {
delete static_cast<Child*>(this); unref_behavior_(static_cast<const Child*>(this));
} }
} }
@ -266,6 +268,9 @@ class DualRefCounted {
// Ref count has dropped to zero, so the object is now orphaned. // Ref count has dropped to zero, so the object is now orphaned.
virtual void Orphaned() = 0; virtual void Orphaned() = 0;
// Note: Depending on the Impl used, this dtor can be implicitly virtual.
~DualRefCounted() = default;
private: private:
// Allow RefCountedPtr<> to access IncrementRefCount(). // Allow RefCountedPtr<> to access IncrementRefCount().
template <typename T> template <typename T>
@ -358,6 +363,7 @@ class DualRefCounted {
const char* trace_; const char* trace_;
#endif #endif
std::atomic<uint64_t> refs_{0}; std::atomic<uint64_t> refs_{0};
GPR_NO_UNIQUE_ADDRESS UnrefBehavior unref_behavior_;
}; };
} // namespace grpc_core } // namespace grpc_core

@ -21,6 +21,8 @@
#include "absl/log/check.h" #include "absl/log/check.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
#include "src/core/lib/gprpp/manual_constructor.h"
#include "src/core/lib/gprpp/ref_counted.h"
#include "test/core/test_util/test_config.h" #include "test/core/test_util/test_config.h"
namespace grpc_core { namespace grpc_core {
@ -115,6 +117,42 @@ TEST(DualRefCountedWithTracing, Basic) {
foo->Unref(DEBUG_LOCATION, "original_ref"); foo->Unref(DEBUG_LOCATION, "original_ref");
} }
class FooWithNoDelete final
: public DualRefCounted<FooWithNoDelete, NonPolymorphicRefCount,
UnrefCallDtor> {
public:
FooWithNoDelete(bool* orphaned_called, bool* destructor_called)
: DualRefCounted<FooWithNoDelete, NonPolymorphicRefCount, UnrefCallDtor>(
"FooWithNoDelete"),
orphaned_called_(orphaned_called),
destructor_called_(destructor_called) {}
~FooWithNoDelete() { *destructor_called_ = true; }
void Orphaned() override { *orphaned_called_ = true; }
private:
bool* const orphaned_called_;
bool* const destructor_called_;
};
TEST(DualRefCountedWithNoDelete, Basic) {
ManualConstructor<FooWithNoDelete> foo;
bool destructor_called = false;
bool orphaned_called = false;
foo.Init(&orphaned_called, &destructor_called);
EXPECT_FALSE(orphaned_called);
EXPECT_FALSE(destructor_called);
foo->WeakRef().release();
EXPECT_FALSE(orphaned_called);
EXPECT_FALSE(destructor_called);
foo->Unref();
EXPECT_TRUE(orphaned_called);
EXPECT_FALSE(destructor_called);
foo->WeakUnref();
EXPECT_TRUE(orphaned_called);
EXPECT_TRUE(destructor_called);
}
} // namespace } // namespace
} // namespace testing } // namespace testing
} // namespace grpc_core } // namespace grpc_core

Loading…
Cancel
Save