• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef GRPC_SRC_CORE_LIB_GPRPP_ORPHANABLE_H
20 #define GRPC_SRC_CORE_LIB_GPRPP_ORPHANABLE_H
21 
22 #include <grpc/support/port_platform.h>
23 
24 #include <cinttypes>
25 #include <memory>
26 #include <utility>
27 
28 #include "src/core/lib/gprpp/debug_location.h"
29 #include "src/core/lib/gprpp/down_cast.h"
30 #include "src/core/lib/gprpp/ref_counted.h"
31 #include "src/core/lib/gprpp/ref_counted_ptr.h"
32 
33 namespace grpc_core {
34 
35 // A base class for orphanable objects, which have one external owner
36 // but are not necessarily destroyed immediately when the external owner
37 // gives up ownership.  Instead, the owner calls the object's Orphan()
38 // method, and the object then takes responsibility for its own cleanup
39 // and destruction.
40 class Orphanable {
41  public:
42   // Gives up ownership of the object.  The implementation must arrange
43   // to eventually destroy the object without further interaction from the
44   // caller.
45   virtual void Orphan() = 0;
46 
47   // Not copyable or movable.
48   Orphanable(const Orphanable&) = delete;
49   Orphanable& operator=(const Orphanable&) = delete;
50 
51  protected:
Orphanable()52   Orphanable() {}
~Orphanable()53   virtual ~Orphanable() {}
54 };
55 
56 class OrphanableDelete {
57  public:
58   template <typename T>
operator()59   void operator()(T* p) {
60     p->Orphan();
61   }
62 };
63 
64 template <typename T, typename Deleter = OrphanableDelete>
65 using OrphanablePtr = std::unique_ptr<T, Deleter>;
66 
67 template <typename T, typename... Args>
MakeOrphanable(Args &&...args)68 inline OrphanablePtr<T> MakeOrphanable(Args&&... args) {
69   return OrphanablePtr<T>(new T(std::forward<Args>(args)...));
70 }
71 
72 // A type of Orphanable with internal ref-counting.
73 template <typename Child, typename UnrefBehavior = UnrefDelete>
74 class InternallyRefCounted : public Orphanable {
75  public:
76   // Not copyable nor movable.
77   InternallyRefCounted(const InternallyRefCounted&) = delete;
78   InternallyRefCounted& operator=(const InternallyRefCounted&) = delete;
79 
80  protected:
81   // Allow RefCountedPtr<> to access Unref() and IncrementRefCount().
82   template <typename T>
83   friend class RefCountedPtr;
84 
85   // Note: Tracing is a no-op on non-debug builds.
86   explicit InternallyRefCounted(const char* trace = nullptr,
87                                 intptr_t initial_refcount = 1)
refs_(initial_refcount,trace)88       : refs_(initial_refcount, trace) {}
89   ~InternallyRefCounted() override = default;
90 
Ref()91   GRPC_MUST_USE_RESULT RefCountedPtr<Child> Ref() {
92     IncrementRefCount();
93     return RefCountedPtr<Child>(static_cast<Child*>(this));
94   }
Ref(const DebugLocation & location,const char * reason)95   GRPC_MUST_USE_RESULT RefCountedPtr<Child> Ref(const DebugLocation& location,
96                                                 const char* reason) {
97     IncrementRefCount(location, reason);
98     return RefCountedPtr<Child>(static_cast<Child*>(this));
99   }
100 
101   template <
102       typename Subclass,
103       std::enable_if_t<std::is_base_of<Child, Subclass>::value, bool> = true>
RefAsSubclass()104   RefCountedPtr<Subclass> RefAsSubclass() {
105     IncrementRefCount();
106     return RefCountedPtr<Subclass>(
107         DownCast<Subclass*>(static_cast<Child*>(this)));
108   }
109   template <
110       typename Subclass,
111       std::enable_if_t<std::is_base_of<Child, Subclass>::value, bool> = true>
RefAsSubclass(const DebugLocation & location,const char * reason)112   RefCountedPtr<Subclass> RefAsSubclass(const DebugLocation& location,
113                                         const char* reason) {
114     IncrementRefCount(location, reason);
115     return RefCountedPtr<Subclass>(
116         DownCast<Subclass*>(static_cast<Child*>(this)));
117   }
118 
RefIfNonZero()119   GRPC_MUST_USE_RESULT RefCountedPtr<Child> RefIfNonZero() {
120     return RefCountedPtr<Child>(refs_.RefIfNonZero() ? static_cast<Child*>(this)
121                                                      : nullptr);
122   }
RefIfNonZero(const DebugLocation & location,const char * reason)123   GRPC_MUST_USE_RESULT RefCountedPtr<Child> RefIfNonZero(
124       const DebugLocation& location, const char* reason) {
125     return RefCountedPtr<Child>(refs_.RefIfNonZero(location, reason)
126                                     ? static_cast<Child*>(this)
127                                     : nullptr);
128   }
129 
Unref()130   void Unref() {
131     if (GPR_UNLIKELY(refs_.Unref())) {
132       unref_behavior_(static_cast<Child*>(this));
133     }
134   }
Unref(const DebugLocation & location,const char * reason)135   void Unref(const DebugLocation& location, const char* reason) {
136     if (GPR_UNLIKELY(refs_.Unref(location, reason))) {
137       unref_behavior_(static_cast<Child*>(this));
138     }
139   }
140 
141  private:
IncrementRefCount()142   void IncrementRefCount() { refs_.Ref(); }
IncrementRefCount(const DebugLocation & location,const char * reason)143   void IncrementRefCount(const DebugLocation& location, const char* reason) {
144     refs_.Ref(location, reason);
145   }
146 
147   RefCount refs_;
148   GPR_NO_UNIQUE_ADDRESS UnrefBehavior unref_behavior_;
149 };
150 
151 }  // namespace grpc_core
152 
153 #endif  // GRPC_SRC_CORE_LIB_GPRPP_ORPHANABLE_H
154