[dual-ref-counted] Add tuning knobs per RefCounted (#36754)
Imbue `DualRefCounted` with the same customization arguments as `RefCounted`.
Closes #36754
COPYBARA_INTEGRATE_REVIEW=https://github.com/grpc/grpc/pull/36754 from ctiller:duality 24e7755287
PiperOrigin-RevId: 638724845
This commit is contained in:
parent
1a96ce7620
commit
4423bfd0c6
|
|
@ -1236,6 +1236,7 @@ grpc_cc_library(
|
|||
public_hdrs = ["lib/gprpp/dual_ref_counted.h"],
|
||||
deps = [
|
||||
"down_cast",
|
||||
"ref_counted",
|
||||
"//:debug_location",
|
||||
"//:gpr",
|
||||
"//:orphanable",
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "src/core/lib/gprpp/debug_location.h"
|
||||
#include "src/core/lib/gprpp/down_cast.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"
|
||||
|
||||
namespace grpc_core {
|
||||
|
|
@ -46,15 +47,16 @@ namespace grpc_core {
|
|||
//
|
||||
// This will be used by CRTP (curiously-recurring template pattern), e.g.:
|
||||
// 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:
|
||||
// Not copyable nor movable.
|
||||
DualRefCounted(const DualRefCounted&) = delete;
|
||||
DualRefCounted& operator=(const DualRefCounted&) = delete;
|
||||
|
||||
virtual ~DualRefCounted() = default;
|
||||
|
||||
GRPC_MUST_USE_RESULT RefCountedPtr<Child> Ref() {
|
||||
IncrementRefCount();
|
||||
return RefCountedPtr<Child>(static_cast<Child*>(this));
|
||||
|
|
@ -215,7 +217,7 @@ class DualRefCounted {
|
|||
CHECK_GT(weak_refs, 0u);
|
||||
#endif
|
||||
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) {
|
||||
|
|
@ -242,7 +244,7 @@ class DualRefCounted {
|
|||
(void)reason;
|
||||
#endif
|
||||
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.
|
||||
virtual void Orphaned() = 0;
|
||||
|
||||
// Note: Depending on the Impl used, this dtor can be implicitly virtual.
|
||||
~DualRefCounted() = default;
|
||||
|
||||
private:
|
||||
// Allow RefCountedPtr<> to access IncrementRefCount().
|
||||
template <typename T>
|
||||
|
|
@ -358,6 +363,7 @@ class DualRefCounted {
|
|||
const char* trace_;
|
||||
#endif
|
||||
std::atomic<uint64_t> refs_{0};
|
||||
GPR_NO_UNIQUE_ADDRESS UnrefBehavior unref_behavior_;
|
||||
};
|
||||
|
||||
} // namespace grpc_core
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@
|
|||
#include "absl/log/check.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"
|
||||
|
||||
namespace grpc_core {
|
||||
|
|
@ -115,6 +117,42 @@ TEST(DualRefCountedWithTracing, Basic) {
|
|||
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 testing
|
||||
} // namespace grpc_core
|
||||
|
|
|
|||
Loading…
Reference in New Issue