123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193 |
- /*
- *
- * Copyright 2017 gRPC authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
- #include "src/core/lib/gprpp/ref_counted.h"
- #include <set>
- #include <gmock/gmock.h>
- #include <gtest/gtest.h>
- #include "src/core/lib/gprpp/memory.h"
- #include "test/core/util/test_config.h"
- namespace grpc_core {
- namespace testing {
- namespace {
- class Foo : public RefCounted<Foo> {
- public:
- Foo() {
- static_assert(std::has_virtual_destructor<Foo>::value,
- "PolymorphicRefCount doesn't have a virtual dtor");
- }
- };
- TEST(RefCounted, Basic) {
- Foo* foo = new Foo();
- foo->Unref();
- }
- TEST(RefCounted, ExtraRef) {
- Foo* foo = new Foo();
- RefCountedPtr<Foo> foop = foo->Ref();
- foop.release();
- foo->Unref();
- foo->Unref();
- }
- class Value : public RefCounted<Value, PolymorphicRefCount, kUnrefNoDelete> {
- public:
- Value(int value, std::set<std::unique_ptr<Value>>* registry) : value_(value) {
- registry->emplace(this);
- }
- int value() const { return value_; }
- private:
- int value_;
- };
- void GarbageCollectRegistry(std::set<std::unique_ptr<Value>>* registry) {
- for (auto it = registry->begin(); it != registry->end();) {
- RefCountedPtr<Value> v = (*it)->RefIfNonZero();
- // Check if the object has any refs remaining.
- if (v != nullptr) {
- // It has refs remaining, so we do not delete it.
- ++it;
- } else {
- // No refs remaining, so remove it from the registry.
- it = registry->erase(it);
- }
- }
- }
- TEST(RefCounted, NoDeleteUponUnref) {
- std::set<std::unique_ptr<Value>> registry;
- // Add two objects to the registry.
- auto v1 = MakeRefCounted<Value>(1, ®istry);
- auto v2 = MakeRefCounted<Value>(2, ®istry);
- EXPECT_THAT(registry,
- ::testing::UnorderedElementsAre(
- ::testing::Pointee(::testing::Property(&Value::value, 1)),
- ::testing::Pointee(::testing::Property(&Value::value, 2))));
- // Running garbage collection should not delete anything, since both
- // entries still have refs.
- GarbageCollectRegistry(®istry);
- EXPECT_THAT(registry,
- ::testing::UnorderedElementsAre(
- ::testing::Pointee(::testing::Property(&Value::value, 1)),
- ::testing::Pointee(::testing::Property(&Value::value, 2))));
- // Unref v2 and run GC to remove it.
- v2.reset();
- GarbageCollectRegistry(®istry);
- EXPECT_THAT(registry, ::testing::UnorderedElementsAre(::testing::Pointee(
- ::testing::Property(&Value::value, 1))));
- // Now unref v1 and run GC again.
- v1.reset();
- GarbageCollectRegistry(®istry);
- EXPECT_THAT(registry, ::testing::UnorderedElementsAre());
- }
- class ValueInExternalAllocation
- : public RefCounted<ValueInExternalAllocation, PolymorphicRefCount,
- kUnrefCallDtor> {
- public:
- explicit ValueInExternalAllocation(int value) : value_(value) {}
- int value() const { return value_; }
- private:
- int value_;
- };
- TEST(RefCounted, CallDtorUponUnref) {
- std::aligned_storage<sizeof(ValueInExternalAllocation),
- alignof(ValueInExternalAllocation)>::type storage;
- RefCountedPtr<ValueInExternalAllocation> value(
- new (&storage) ValueInExternalAllocation(5));
- EXPECT_EQ(value->value(), 5);
- }
- class FooNonPolymorphic
- : public RefCounted<FooNonPolymorphic, NonPolymorphicRefCount> {
- public:
- FooNonPolymorphic() {
- static_assert(!std::has_virtual_destructor<FooNonPolymorphic>::value,
- "NonPolymorphicRefCount has a virtual dtor");
- }
- };
- TEST(RefCountedNonPolymorphic, Basic) {
- FooNonPolymorphic* foo = new FooNonPolymorphic();
- foo->Unref();
- }
- TEST(RefCountedNonPolymorphic, ExtraRef) {
- FooNonPolymorphic* foo = new FooNonPolymorphic();
- RefCountedPtr<FooNonPolymorphic> foop = foo->Ref();
- foop.release();
- foo->Unref();
- foo->Unref();
- }
- class FooWithTracing : public RefCounted<FooWithTracing> {
- public:
- FooWithTracing() : RefCounted("Foo") {}
- };
- TEST(RefCountedWithTracing, Basic) {
- FooWithTracing* foo = new FooWithTracing();
- RefCountedPtr<FooWithTracing> foop = foo->Ref(DEBUG_LOCATION, "extra_ref");
- foop.release();
- foo->Unref(DEBUG_LOCATION, "extra_ref");
- // Can use the no-argument methods, too.
- foop = foo->Ref();
- foop.release();
- foo->Unref();
- foo->Unref(DEBUG_LOCATION, "original_ref");
- }
- class FooNonPolymorphicWithTracing
- : public RefCounted<FooNonPolymorphicWithTracing, NonPolymorphicRefCount> {
- public:
- FooNonPolymorphicWithTracing() : RefCounted("FooNonPolymorphicWithTracing") {}
- };
- TEST(RefCountedNonPolymorphicWithTracing, Basic) {
- FooNonPolymorphicWithTracing* foo = new FooNonPolymorphicWithTracing();
- RefCountedPtr<FooNonPolymorphicWithTracing> foop =
- foo->Ref(DEBUG_LOCATION, "extra_ref");
- foop.release();
- foo->Unref(DEBUG_LOCATION, "extra_ref");
- // Can use the no-argument methods, too.
- foop = foo->Ref();
- foop.release();
- foo->Unref();
- foo->Unref(DEBUG_LOCATION, "original_ref");
- }
- } // namespace
- } // namespace testing
- } // namespace grpc_core
- int main(int argc, char** argv) {
- grpc::testing::TestEnvironment env(argc, argv);
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
- }
|