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