ref_counted_test.cc 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  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. #include "src/core/lib/gprpp/ref_counted.h"
  19. #include <set>
  20. #include <gmock/gmock.h>
  21. #include <gtest/gtest.h>
  22. #include "src/core/lib/gprpp/memory.h"
  23. #include "test/core/util/test_config.h"
  24. namespace grpc_core {
  25. namespace testing {
  26. namespace {
  27. class Foo : public RefCounted<Foo> {
  28. public:
  29. Foo() {
  30. static_assert(std::has_virtual_destructor<Foo>::value,
  31. "PolymorphicRefCount doesn't have a virtual dtor");
  32. }
  33. };
  34. TEST(RefCounted, Basic) {
  35. Foo* foo = new Foo();
  36. foo->Unref();
  37. }
  38. TEST(RefCounted, ExtraRef) {
  39. Foo* foo = new Foo();
  40. RefCountedPtr<Foo> foop = foo->Ref();
  41. foop.release();
  42. foo->Unref();
  43. foo->Unref();
  44. }
  45. class Value : public RefCounted<Value, PolymorphicRefCount, kUnrefNoDelete> {
  46. public:
  47. Value(int value, std::set<std::unique_ptr<Value>>* registry) : value_(value) {
  48. registry->emplace(this);
  49. }
  50. int value() const { return value_; }
  51. private:
  52. int value_;
  53. };
  54. void GarbageCollectRegistry(std::set<std::unique_ptr<Value>>* registry) {
  55. for (auto it = registry->begin(); it != registry->end();) {
  56. RefCountedPtr<Value> v = (*it)->RefIfNonZero();
  57. // Check if the object has any refs remaining.
  58. if (v != nullptr) {
  59. // It has refs remaining, so we do not delete it.
  60. ++it;
  61. } else {
  62. // No refs remaining, so remove it from the registry.
  63. it = registry->erase(it);
  64. }
  65. }
  66. }
  67. TEST(RefCounted, NoDeleteUponUnref) {
  68. std::set<std::unique_ptr<Value>> registry;
  69. // Add two objects to the registry.
  70. auto v1 = MakeRefCounted<Value>(1, &registry);
  71. auto v2 = MakeRefCounted<Value>(2, &registry);
  72. EXPECT_THAT(registry,
  73. ::testing::UnorderedElementsAre(
  74. ::testing::Pointee(::testing::Property(&Value::value, 1)),
  75. ::testing::Pointee(::testing::Property(&Value::value, 2))));
  76. // Running garbage collection should not delete anything, since both
  77. // entries still have refs.
  78. GarbageCollectRegistry(&registry);
  79. EXPECT_THAT(registry,
  80. ::testing::UnorderedElementsAre(
  81. ::testing::Pointee(::testing::Property(&Value::value, 1)),
  82. ::testing::Pointee(::testing::Property(&Value::value, 2))));
  83. // Unref v2 and run GC to remove it.
  84. v2.reset();
  85. GarbageCollectRegistry(&registry);
  86. EXPECT_THAT(registry, ::testing::UnorderedElementsAre(::testing::Pointee(
  87. ::testing::Property(&Value::value, 1))));
  88. // Now unref v1 and run GC again.
  89. v1.reset();
  90. GarbageCollectRegistry(&registry);
  91. EXPECT_THAT(registry, ::testing::UnorderedElementsAre());
  92. }
  93. class ValueInExternalAllocation
  94. : public RefCounted<ValueInExternalAllocation, PolymorphicRefCount,
  95. kUnrefCallDtor> {
  96. public:
  97. explicit ValueInExternalAllocation(int value) : value_(value) {}
  98. int value() const { return value_; }
  99. private:
  100. int value_;
  101. };
  102. TEST(RefCounted, CallDtorUponUnref) {
  103. std::aligned_storage<sizeof(ValueInExternalAllocation),
  104. alignof(ValueInExternalAllocation)>::type storage;
  105. RefCountedPtr<ValueInExternalAllocation> value(
  106. new (&storage) ValueInExternalAllocation(5));
  107. EXPECT_EQ(value->value(), 5);
  108. }
  109. class FooNonPolymorphic
  110. : public RefCounted<FooNonPolymorphic, NonPolymorphicRefCount> {
  111. public:
  112. FooNonPolymorphic() {
  113. static_assert(!std::has_virtual_destructor<FooNonPolymorphic>::value,
  114. "NonPolymorphicRefCount has a virtual dtor");
  115. }
  116. };
  117. TEST(RefCountedNonPolymorphic, Basic) {
  118. FooNonPolymorphic* foo = new FooNonPolymorphic();
  119. foo->Unref();
  120. }
  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. class FooWithTracing : public RefCounted<FooWithTracing> {
  129. public:
  130. FooWithTracing() : RefCounted("Foo") {}
  131. };
  132. TEST(RefCountedWithTracing, Basic) {
  133. FooWithTracing* foo = new FooWithTracing();
  134. RefCountedPtr<FooWithTracing> foop = foo->Ref(DEBUG_LOCATION, "extra_ref");
  135. foop.release();
  136. foo->Unref(DEBUG_LOCATION, "extra_ref");
  137. // Can use the no-argument methods, too.
  138. foop = foo->Ref();
  139. foop.release();
  140. foo->Unref();
  141. foo->Unref(DEBUG_LOCATION, "original_ref");
  142. }
  143. class FooNonPolymorphicWithTracing
  144. : public RefCounted<FooNonPolymorphicWithTracing, NonPolymorphicRefCount> {
  145. public:
  146. FooNonPolymorphicWithTracing() : RefCounted("FooNonPolymorphicWithTracing") {}
  147. };
  148. TEST(RefCountedNonPolymorphicWithTracing, Basic) {
  149. FooNonPolymorphicWithTracing* foo = new FooNonPolymorphicWithTracing();
  150. RefCountedPtr<FooNonPolymorphicWithTracing> foop =
  151. foo->Ref(DEBUG_LOCATION, "extra_ref");
  152. foop.release();
  153. foo->Unref(DEBUG_LOCATION, "extra_ref");
  154. // Can use the no-argument methods, too.
  155. foop = foo->Ref();
  156. foop.release();
  157. foo->Unref();
  158. foo->Unref(DEBUG_LOCATION, "original_ref");
  159. }
  160. } // namespace
  161. } // namespace testing
  162. } // namespace grpc_core
  163. int main(int argc, char** argv) {
  164. grpc::testing::TestEnvironment env(argc, argv);
  165. ::testing::InitGoogleTest(&argc, argv);
  166. return RUN_ALL_TESTS();
  167. }