diff --git a/src/core/lib/gprpp/orphanable.h b/src/core/lib/gprpp/orphanable.h index 86319429e5c..5a77ad46b45 100644 --- a/src/core/lib/gprpp/orphanable.h +++ b/src/core/lib/gprpp/orphanable.h @@ -108,6 +108,17 @@ class InternallyRefCounted : public Orphanable { } } + GRPC_MUST_USE_RESULT RefCountedPtr RefIfNonZero() { + return RefCountedPtr(refs_.RefIfNonZero() ? static_cast(this) + : nullptr); + } + GRPC_MUST_USE_RESULT RefCountedPtr RefIfNonZero( + const DebugLocation& location, const char* reason) { + return RefCountedPtr(refs_.RefIfNonZero(location, reason) + ? static_cast(this) + : nullptr); + } + private: void IncrementRefCount() { refs_.Ref(); } void IncrementRefCount(const DebugLocation& location, const char* reason) { diff --git a/test/core/gprpp/orphanable_test.cc b/test/core/gprpp/orphanable_test.cc index e5b74146661..cea10b748f7 100644 --- a/test/core/gprpp/orphanable_test.cc +++ b/test/core/gprpp/orphanable_test.cc @@ -103,6 +103,32 @@ TEST(OrphanablePtr, InternallyRefCountedWithTracing) { baz->FinishWork(); } +class Qux : public InternallyRefCounted { + public: + Qux() : Qux(0) {} + explicit Qux(int value) : InternallyRefCounted("Qux"), value_(value) {} + ~Qux() override { self_ref_ = RefIfNonZero(DEBUG_LOCATION, "extra_work"); } + void Orphan() override { Unref(); } + int value() const { return value_; } + + void StartWork() { self_ref_ = RefIfNonZero(DEBUG_LOCATION, "work"); } + void FinishWork() { + // This is a little ugly, but it makes the logged ref and unref match up. + self_ref_.release(); + Unref(DEBUG_LOCATION, "work"); + } + + private: + int value_; + RefCountedPtr self_ref_; +}; + +TEST(OrphanablePtr, InternallyRefCountedIfNonZero) { + auto qux = MakeOrphanable(); + qux->StartWork(); + qux->FinishWork(); +} + } // namespace } // namespace testing } // namespace grpc_core