Home | History | Annotate | Download | only in gprpp
      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 <grpc/support/log.h>
     25 #include <grpc/support/sync.h>
     26 
     27 #include <cinttypes>
     28 #include <memory>
     29 
     30 #include "src/core/lib/debug/trace.h"
     31 #include "src/core/lib/gprpp/abstract.h"
     32 #include "src/core/lib/gprpp/debug_location.h"
     33 #include "src/core/lib/gprpp/memory.h"
     34 #include "src/core/lib/gprpp/ref_counted_ptr.h"
     35 
     36 namespace grpc_core {
     37 
     38 // A base class for orphanable objects, which have one external owner
     39 // but are not necessarily destroyed immediately when the external owner
     40 // gives up ownership.  Instead, the owner calls the object's Orphan()
     41 // method, and the object then takes responsibility for its own cleanup
     42 // and destruction.
     43 class Orphanable {
     44  public:
     45   // Gives up ownership of the object.  The implementation must arrange
     46   // to eventually destroy the object without further interaction from the
     47   // caller.
     48   virtual void Orphan() GRPC_ABSTRACT;
     49 
     50   // Not copyable or movable.
     51   Orphanable(const Orphanable&) = delete;
     52   Orphanable& operator=(const Orphanable&) = delete;
     53 
     54   GRPC_ABSTRACT_BASE_CLASS
     55 
     56  protected:
     57   Orphanable() {}
     58   virtual ~Orphanable() {}
     59 };
     60 
     61 template <typename T>
     62 class OrphanableDelete {
     63  public:
     64   void operator()(T* p) { p->Orphan(); }
     65 };
     66 
     67 template <typename T, typename Deleter = OrphanableDelete<T>>
     68 using OrphanablePtr = std::unique_ptr<T, Deleter>;
     69 
     70 template <typename T, typename... Args>
     71 inline OrphanablePtr<T> MakeOrphanable(Args&&... args) {
     72   return OrphanablePtr<T>(New<T>(std::forward<Args>(args)...));
     73 }
     74 
     75 // A type of Orphanable with internal ref-counting.
     76 template <typename Child>
     77 class InternallyRefCounted : public Orphanable {
     78  public:
     79   // Not copyable nor movable.
     80   InternallyRefCounted(const InternallyRefCounted&) = delete;
     81   InternallyRefCounted& operator=(const InternallyRefCounted&) = delete;
     82 
     83   GRPC_ABSTRACT_BASE_CLASS
     84 
     85  protected:
     86   GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
     87 
     88   // Allow RefCountedPtr<> to access Unref() and IncrementRefCount().
     89   template <typename T>
     90   friend class RefCountedPtr;
     91 
     92   InternallyRefCounted() { gpr_ref_init(&refs_, 1); }
     93   virtual ~InternallyRefCounted() {}
     94 
     95   RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
     96     IncrementRefCount();
     97     return RefCountedPtr<Child>(static_cast<Child*>(this));
     98   }
     99 
    100   void Unref() {
    101     if (gpr_unref(&refs_)) {
    102       Delete(static_cast<Child*>(this));
    103     }
    104   }
    105 
    106  private:
    107   void IncrementRefCount() { gpr_ref(&refs_); }
    108 
    109   gpr_refcount refs_;
    110 };
    111 
    112 // An alternative version of the InternallyRefCounted base class that
    113 // supports tracing.  This is intended to be used in cases where the
    114 // object will be handled both by idiomatic C++ code using smart
    115 // pointers and legacy code that is manually calling Ref() and Unref().
    116 // Once all of our code is converted to idiomatic C++, we may be able to
    117 // eliminate this class.
    118 template <typename Child>
    119 class InternallyRefCountedWithTracing : public Orphanable {
    120  public:
    121   // Not copyable nor movable.
    122   InternallyRefCountedWithTracing(const InternallyRefCountedWithTracing&) =
    123       delete;
    124   InternallyRefCountedWithTracing& operator=(
    125       const InternallyRefCountedWithTracing&) = delete;
    126 
    127   GRPC_ABSTRACT_BASE_CLASS
    128 
    129  protected:
    130   GPRC_ALLOW_CLASS_TO_USE_NON_PUBLIC_DELETE
    131 
    132   // Allow RefCountedPtr<> to access Unref() and IncrementRefCount().
    133   template <typename T>
    134   friend class RefCountedPtr;
    135 
    136   InternallyRefCountedWithTracing()
    137       : InternallyRefCountedWithTracing(static_cast<TraceFlag*>(nullptr)) {}
    138 
    139   explicit InternallyRefCountedWithTracing(TraceFlag* trace_flag)
    140       : trace_flag_(trace_flag) {
    141     gpr_ref_init(&refs_, 1);
    142   }
    143 
    144 #ifdef NDEBUG
    145   explicit InternallyRefCountedWithTracing(DebugOnlyTraceFlag* trace_flag)
    146       : InternallyRefCountedWithTracing() {}
    147 #endif
    148 
    149   virtual ~InternallyRefCountedWithTracing() {}
    150 
    151   RefCountedPtr<Child> Ref() GRPC_MUST_USE_RESULT {
    152     IncrementRefCount();
    153     return RefCountedPtr<Child>(static_cast<Child*>(this));
    154   }
    155 
    156   RefCountedPtr<Child> Ref(const DebugLocation& location,
    157                            const char* reason) GRPC_MUST_USE_RESULT {
    158     if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
    159       gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
    160       gpr_log(GPR_INFO, "%s:%p %s:%d ref %" PRIdPTR " -> %" PRIdPTR " %s",
    161               trace_flag_->name(), this, location.file(), location.line(),
    162               old_refs, old_refs + 1, reason);
    163     }
    164     return Ref();
    165   }
    166 
    167   // TODO(roth): Once all of our code is converted to C++ and can use
    168   // RefCountedPtr<> instead of manual ref-counting, make the Unref() methods
    169   // private, since they will only be used by RefCountedPtr<>, which is a
    170   // friend of this class.
    171 
    172   void Unref() {
    173     if (gpr_unref(&refs_)) {
    174       Delete(static_cast<Child*>(this));
    175     }
    176   }
    177 
    178   void Unref(const DebugLocation& location, const char* reason) {
    179     if (location.Log() && trace_flag_ != nullptr && trace_flag_->enabled()) {
    180       gpr_atm old_refs = gpr_atm_no_barrier_load(&refs_.count);
    181       gpr_log(GPR_INFO, "%s:%p %s:%d unref %" PRIdPTR " -> %" PRIdPTR " %s",
    182               trace_flag_->name(), this, location.file(), location.line(),
    183               old_refs, old_refs - 1, reason);
    184     }
    185     Unref();
    186   }
    187 
    188  private:
    189   void IncrementRefCount() { gpr_ref(&refs_); }
    190 
    191   TraceFlag* trace_flag_ = nullptr;
    192   gpr_refcount refs_;
    193 };
    194 
    195 }  // namespace grpc_core
    196 
    197 #endif /* GRPC_CORE_LIB_GPRPP_ORPHANABLE_H */
    198