1 /*
2  *
3  * Copyright 2017 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include "src/core/lib/gprpp/ref_counted.h"
20 
21 #include <set>
22 
23 #include <gmock/gmock.h>
24 #include <gtest/gtest.h>
25 
26 #include "src/core/lib/gprpp/memory.h"
27 #include "test/core/util/test_config.h"
28 
29 namespace grpc_core {
30 namespace testing {
31 namespace {
32 
33 class Foo : public RefCounted<Foo> {
34  public:
Foo()35   Foo() {
36     static_assert(std::has_virtual_destructor<Foo>::value,
37                   "PolymorphicRefCount doesn't have a virtual dtor");
38   }
39 };
40 
TEST(RefCounted,Basic)41 TEST(RefCounted, Basic) {
42   Foo* foo = new Foo();
43   foo->Unref();
44 }
45 
TEST(RefCounted,ExtraRef)46 TEST(RefCounted, ExtraRef) {
47   Foo* foo = new Foo();
48   RefCountedPtr<Foo> foop = foo->Ref();
49   foop.release();
50   foo->Unref();
51   foo->Unref();
52 }
53 
54 class Value : public RefCounted<Value, PolymorphicRefCount, false> {
55  public:
Value(int value,std::set<std::unique_ptr<Value>> * registry)56   Value(int value, std::set<std::unique_ptr<Value>>* registry) : value_(value) {
57     registry->emplace(this);
58   }
59 
value() const60   int value() const { return value_; }
61 
62  private:
63   int value_;
64 };
65 
GarbageCollectRegistry(std::set<std::unique_ptr<Value>> * registry)66 void GarbageCollectRegistry(std::set<std::unique_ptr<Value>>* registry) {
67   for (auto it = registry->begin(); it != registry->end();) {
68     RefCountedPtr<Value> v = (*it)->RefIfNonZero();
69     // Check if the object has any refs remaining.
70     if (v != nullptr) {
71       // It has refs remaining, so we do not delete it.
72       ++it;
73     } else {
74       // No refs remaining, so remove it from the registry.
75       it = registry->erase(it);
76     }
77   }
78 }
79 
TEST(RefCounted,NoDeleteUponUnref)80 TEST(RefCounted, NoDeleteUponUnref) {
81   std::set<std::unique_ptr<Value>> registry;
82   // Add two objects to the registry.
83   auto v1 = MakeRefCounted<Value>(1, &registry);
84   auto v2 = MakeRefCounted<Value>(2, &registry);
85   EXPECT_THAT(registry,
86               ::testing::UnorderedElementsAre(
87                   ::testing::Pointee(::testing::Property(&Value::value, 1)),
88                   ::testing::Pointee(::testing::Property(&Value::value, 2))));
89   // Running garbage collection should not delete anything, since both
90   // entries still have refs.
91   GarbageCollectRegistry(&registry);
92   EXPECT_THAT(registry,
93               ::testing::UnorderedElementsAre(
94                   ::testing::Pointee(::testing::Property(&Value::value, 1)),
95                   ::testing::Pointee(::testing::Property(&Value::value, 2))));
96   // Unref v2 and run GC to remove it.
97   v2.reset();
98   GarbageCollectRegistry(&registry);
99   EXPECT_THAT(registry, ::testing::UnorderedElementsAre(::testing::Pointee(
100                             ::testing::Property(&Value::value, 1))));
101   // Now unref v1 and run GC again.
102   v1.reset();
103   GarbageCollectRegistry(&registry);
104   EXPECT_THAT(registry, ::testing::UnorderedElementsAre());
105 }
106 
107 class FooNonPolymorphic
108     : public RefCounted<FooNonPolymorphic, NonPolymorphicRefCount> {
109  public:
FooNonPolymorphic()110   FooNonPolymorphic() {
111     static_assert(!std::has_virtual_destructor<FooNonPolymorphic>::value,
112                   "NonPolymorphicRefCount has a virtual dtor");
113   }
114 };
115 
TEST(RefCountedNonPolymorphic,Basic)116 TEST(RefCountedNonPolymorphic, Basic) {
117   FooNonPolymorphic* foo = new FooNonPolymorphic();
118   foo->Unref();
119 }
120 
TEST(RefCountedNonPolymorphic,ExtraRef)121 TEST(RefCountedNonPolymorphic, ExtraRef) {
122   FooNonPolymorphic* foo = new FooNonPolymorphic();
123   RefCountedPtr<FooNonPolymorphic> foop = foo->Ref();
124   foop.release();
125   foo->Unref();
126   foo->Unref();
127 }
128 
129 class FooWithTracing : public RefCounted<FooWithTracing> {
130  public:
FooWithTracing()131   FooWithTracing() : RefCounted("Foo") {}
132 };
133 
TEST(RefCountedWithTracing,Basic)134 TEST(RefCountedWithTracing, Basic) {
135   FooWithTracing* foo = new FooWithTracing();
136   RefCountedPtr<FooWithTracing> foop = foo->Ref(DEBUG_LOCATION, "extra_ref");
137   foop.release();
138   foo->Unref(DEBUG_LOCATION, "extra_ref");
139   // Can use the no-argument methods, too.
140   foop = foo->Ref();
141   foop.release();
142   foo->Unref();
143   foo->Unref(DEBUG_LOCATION, "original_ref");
144 }
145 
146 class FooNonPolymorphicWithTracing
147     : public RefCounted<FooNonPolymorphicWithTracing, NonPolymorphicRefCount> {
148  public:
FooNonPolymorphicWithTracing()149   FooNonPolymorphicWithTracing() : RefCounted("FooNonPolymorphicWithTracing") {}
150 };
151 
TEST(RefCountedNonPolymorphicWithTracing,Basic)152 TEST(RefCountedNonPolymorphicWithTracing, Basic) {
153   FooNonPolymorphicWithTracing* foo = new FooNonPolymorphicWithTracing();
154   RefCountedPtr<FooNonPolymorphicWithTracing> foop =
155       foo->Ref(DEBUG_LOCATION, "extra_ref");
156   foop.release();
157   foo->Unref(DEBUG_LOCATION, "extra_ref");
158   // Can use the no-argument methods, too.
159   foop = foo->Ref();
160   foop.release();
161   foo->Unref();
162   foo->Unref(DEBUG_LOCATION, "original_ref");
163 }
164 
165 }  // namespace
166 }  // namespace testing
167 }  // namespace grpc_core
168 
main(int argc,char ** argv)169 int main(int argc, char** argv) {
170   grpc::testing::TestEnvironment env(argc, argv);
171   ::testing::InitGoogleTest(&argc, argv);
172   return RUN_ALL_TESTS();
173 }
174