1 //
2 // Copyright 2020 gRPC authors.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16
17 #include "src/core/util/dual_ref_counted.h"
18
19 #include <memory>
20
21 #include "absl/log/check.h"
22 #include "gtest/gtest.h"
23 #include "src/core/util/manual_constructor.h"
24 #include "src/core/util/ref_counted.h"
25 #include "test/core/test_util/test_config.h"
26
27 namespace grpc_core {
28 namespace testing {
29 namespace {
30
31 class Foo : public DualRefCounted<Foo> {
32 public:
33 Foo() = default;
~Foo()34 ~Foo() override { CHECK(shutting_down_); }
35
Orphaned()36 void Orphaned() override { shutting_down_ = true; }
37
38 private:
39 bool shutting_down_ = false;
40 };
41
TEST(DualRefCounted,Basic)42 TEST(DualRefCounted, Basic) {
43 Foo* foo = new Foo();
44 foo->Unref();
45 }
46
TEST(DualRefCounted,ExtraRef)47 TEST(DualRefCounted, ExtraRef) {
48 Foo* foo = new Foo();
49 foo->Ref().release();
50 foo->Unref();
51 foo->Unref();
52 }
53
TEST(DualRefCounted,ExtraWeakRef)54 TEST(DualRefCounted, ExtraWeakRef) {
55 Foo* foo = new Foo();
56 foo->WeakRef().release();
57 foo->Unref();
58 foo->WeakUnref();
59 }
60
TEST(DualRefCounted,RefIfNonZero)61 TEST(DualRefCounted, RefIfNonZero) {
62 Foo* foo = new Foo();
63 foo->WeakRef().release();
64 {
65 RefCountedPtr<Foo> foop = foo->RefIfNonZero();
66 EXPECT_NE(foop.get(), nullptr);
67 }
68 foo->Unref();
69 {
70 RefCountedPtr<Foo> foop = foo->RefIfNonZero();
71 EXPECT_EQ(foop.get(), nullptr);
72 }
73 foo->WeakUnref();
74 }
75
TEST(DualRefCounted,RefAndWeakRefAsSubclass)76 TEST(DualRefCounted, RefAndWeakRefAsSubclass) {
77 class Bar : public Foo {};
78 Foo* foo = new Bar();
79 RefCountedPtr<Bar> barp = foo->RefAsSubclass<Bar>();
80 barp.release();
81 barp = foo->RefAsSubclass<Bar>(DEBUG_LOCATION, "test");
82 barp.release();
83 WeakRefCountedPtr<Bar> weak_barp = foo->WeakRefAsSubclass<Bar>();
84 weak_barp.release();
85 weak_barp = foo->WeakRefAsSubclass<Bar>(DEBUG_LOCATION, "test");
86 weak_barp.release();
87 foo->WeakUnref();
88 foo->WeakUnref();
89 foo->Unref();
90 foo->Unref();
91 foo->Unref();
92 }
93
94 class FooWithTracing : public DualRefCounted<FooWithTracing> {
95 public:
FooWithTracing()96 FooWithTracing() : DualRefCounted("FooWithTracing") {}
~FooWithTracing()97 ~FooWithTracing() override { CHECK(shutting_down_); }
98
Orphaned()99 void Orphaned() override { shutting_down_ = true; }
100
101 private:
102 bool shutting_down_ = false;
103 };
104
TEST(DualRefCountedWithTracing,Basic)105 TEST(DualRefCountedWithTracing, Basic) {
106 FooWithTracing* foo = new FooWithTracing();
107 foo->Ref(DEBUG_LOCATION, "extra_ref").release();
108 foo->Unref(DEBUG_LOCATION, "extra_ref");
109 foo->WeakRef(DEBUG_LOCATION, "extra_ref").release();
110 foo->WeakUnref(DEBUG_LOCATION, "extra_ref");
111 // Can use the no-argument methods, too.
112 foo->Ref().release();
113 foo->Unref();
114 foo->WeakRef().release();
115 foo->WeakUnref();
116 foo->Unref(DEBUG_LOCATION, "original_ref");
117 }
118
119 class FooWithNoDelete final
120 : public DualRefCounted<FooWithNoDelete, NonPolymorphicRefCount,
121 UnrefCallDtor> {
122 public:
FooWithNoDelete(bool * orphaned_called,bool * destructor_called)123 FooWithNoDelete(bool* orphaned_called, bool* destructor_called)
124 : DualRefCounted<FooWithNoDelete, NonPolymorphicRefCount, UnrefCallDtor>(
125 "FooWithNoDelete"),
126 orphaned_called_(orphaned_called),
127 destructor_called_(destructor_called) {}
~FooWithNoDelete()128 ~FooWithNoDelete() { *destructor_called_ = true; }
129
Orphaned()130 void Orphaned() override { *orphaned_called_ = true; }
131
132 private:
133 bool* const orphaned_called_;
134 bool* const destructor_called_;
135 };
136
TEST(DualRefCountedWithNoDelete,Basic)137 TEST(DualRefCountedWithNoDelete, Basic) {
138 ManualConstructor<FooWithNoDelete> foo;
139 bool destructor_called = false;
140 bool orphaned_called = false;
141 foo.Init(&orphaned_called, &destructor_called);
142 EXPECT_FALSE(orphaned_called);
143 EXPECT_FALSE(destructor_called);
144 foo->WeakRef().release();
145 EXPECT_FALSE(orphaned_called);
146 EXPECT_FALSE(destructor_called);
147 foo->Unref();
148 EXPECT_TRUE(orphaned_called);
149 EXPECT_FALSE(destructor_called);
150 foo->WeakUnref();
151 EXPECT_TRUE(orphaned_called);
152 EXPECT_TRUE(destructor_called);
153 }
154
155 } // namespace
156 } // namespace testing
157 } // namespace grpc_core
158
main(int argc,char ** argv)159 int main(int argc, char** argv) {
160 grpc::testing::TestEnvironment env(&argc, argv);
161 ::testing::InitGoogleTest(&argc, argv);
162 return RUN_ALL_TESTS();
163 }
164