Line data Source code
1 : /* 2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. 3 : */ 4 : 5 : #ifndef __BASE__LIFETIME_H__ 6 : #define __BASE__LIFETIME_H__ 7 : 8 : #include <atomic> 9 : #include <mutex> 10 : 11 : #include "base/dependency.h" 12 : #include "base/queue_task.h" 13 : #include "base/util.h" 14 : 15 : class LifetimeActor; 16 : class LifetimeManager; 17 : 18 : // 19 : // The Lifetime management framework enables a structured approach to the 20 : // problem of tracking inter-dependencies between objects for the purpose 21 : // of orderly deletion and cleanup. The dependencies are represented as 22 : // an acyclic graph with LifetimeActors being the nodes and LifetimeRefs 23 : // being the links. The dependency tracker lets us implement "on delete 24 : // cascade" behavior wherein the deletion of an object triggers deletion 25 : // of all it's dependents, the dependents' dependents and so on. 26 : // 27 : // Each object that requires lifetime management contains an instance of 28 : // a derived class of LifetimeActor embedded in it. The derived class is 29 : // specific to the object type and typically contains a back pointer to 30 : // the object. The convention is to name the derived class as DeleteActor 31 : // and the instance of it as deleter_. 32 : // 33 : // Each managed object (other than the root object) contains one or more 34 : // LifetimeRef instances. A LifetimeRef instance corresponds to a parent 35 : // object on which the object is dependent. The LifetimeRef instances are 36 : // normally created and linked to the parent objects' LifetimeActor when 37 : // the managed object is constructed. Each LifetimeRef contains a back 38 : // pointer to the managed object. The convention is to name the members 39 : // as xxx_delete_ref_, where xxx corresponds to the parent object class. 40 : // 41 : // The deletion of a managed object can be triggered by calling Delete on 42 : // it's actor from any thread. This in turn results in cascaded calls to 43 : // Delete as described above. Further, the LifetimeActor also enqueues a 44 : // a delete event to the LifetimeManager for deferred processing. This 45 : // event is processed by the LifetimeManager in the desired Task context. 46 : // 47 : // When a managed object is destroyed, all the LifetimeRefs to it's parent 48 : // objects are also destroyed. This automatically causes the LifetimeRefs 49 : // to get removed from the list of dependents in the parents' DeleteActor. 50 : // This in turn also enqueues a delete event to the parent DeleteActor's 51 : // LifetimeManager if appropriate i.e. if the parent DeleteActor's list of 52 : // dependents has become empty. 53 : // 54 : // The LifetimeManager DeleteExecutor processes delete events for Actors 55 : // in the context of the desired Task. It makes sure that there are no 56 : // dependents and that all relevant state in the DeleteActor's object has 57 : // been cleaned up i.e. the object may be deleted, before destroying the 58 : // object. 59 : // 60 : // Note that object deletes are triggered from top to bottom while object 61 : // destruction happens in the reverse order. 62 : // 63 : // In addition to having other managed objects as dependents it's common 64 : // to also have other lightweight objects as dependents. These lightweight 65 : // dependents should not be tracked using LifetimeRefs, but can instead be 66 : // tracked using simple reference counts. When the reference count becomes 67 : // 0, a delete event for the actor should be posted to the LifetimeManager. 68 : // 69 : 70 : // 71 : // Base class for a reference to a managed lifetime object. 72 : // 73 : class LifetimeRefBase { 74 : public: 75 : LifetimeRefBase(LifetimeActor *actor); 76 : virtual ~LifetimeRefBase(); 77 : 78 : // called when the lifetime actor delete is called. 79 : // implements "ON DELETE CASCADE" semantics. 80 : virtual void Delete() = 0; 81 : 82 709373 : void Reset(LifetimeActor *actor) { 83 709373 : ref_.reset(actor); 84 709379 : } 85 : 86 : bool IsSet() const { return ref_.get() != NULL; } 87 : 88 : private: 89 : DependencyRef<LifetimeRefBase, LifetimeActor> ref_; 90 : DISALLOW_COPY_AND_ASSIGN(LifetimeRefBase); 91 : }; 92 : 93 : // 94 : // Class template to create LifetimeRefs for specific object types. 95 : // 96 : // Ref is the type of the dependent object. 97 : // The LifetimeActor parameter is the actor for the parent object. 98 : // 99 : template <class Ref> 100 : class LifetimeRef : public LifetimeRefBase { 101 : public: 102 1139171 : LifetimeRef(Ref *ptr, LifetimeActor *actor) 103 1139171 : : LifetimeRefBase(actor), ptr_(ptr) { 104 1139222 : } 105 : 106 1047401 : virtual void Delete() { 107 1047401 : ptr_->ManagedDelete(); 108 1047401 : } 109 : 110 : private: 111 : Ref *ptr_; 112 : DISALLOW_COPY_AND_ASSIGN(LifetimeRef); 113 : }; 114 : 115 : // Member of an object that has managed lifetime. 116 : class LifetimeActor { 117 : public: 118 : LifetimeActor(LifetimeManager *manager); 119 : virtual ~LifetimeActor(); 120 : 121 : // Trigger the deletion of an object. 122 : // May be called from any thread. 123 : virtual void Delete(); 124 : 125 : void RetryDelete(); 126 : 127 : // Prevent/Resume deletion of object - for testing only. 128 : void PauseDelete(); 129 : void ResumeDelete(); 130 : 131 5053706 : bool IsDeleted() const { return deleted_; } 132 48 : bool HasDependents() const { return !dependents_.empty(); } 133 0 : bool HasRefcount() const { return refcount_; } 134 : 135 : const uint64_t create_time_stamp_usecs() const { 136 : return create_time_stamp_usecs_; 137 : } 138 17412 : const uint64_t delete_time_stamp_usecs() const { 139 17412 : return delete_time_stamp_usecs_; 140 : } 141 : 142 : private: 143 : typedef DependencyList<LifetimeRefBase, LifetimeActor> Dependents; 144 : friend class DependencyRef<LifetimeRefBase, LifetimeActor>; 145 : friend class LifetimeManager; 146 : 147 : // Called to check dependencies. 148 : virtual bool MayDelete() const = 0; 149 : 150 : // Called under the manager thread in order to remove the object state. 151 : virtual void Shutdown(); 152 : 153 : // Called immediately before the object is destroyed. 154 : virtual void DeleteComplete(); 155 : 156 : // Must be called under a specific Task. 157 : virtual void Destroy() = 0; 158 : 159 : void PropagateDelete(); 160 : void DependencyAdd(DependencyRef<LifetimeRefBase, LifetimeActor> *node); 161 : void DependencyRemove(DependencyRef<LifetimeRefBase, LifetimeActor> *node); 162 : 163 : void ReferenceIncrement(); 164 : bool ReferenceDecrementAndTest(); 165 : 166 2353818 : bool shutdown_invoked() { return shutdown_invoked_; } 167 1032058 : void set_shutdown_invoked() { shutdown_invoked_ = true; } 168 : 169 : std::mutex mutex_; 170 : LifetimeManager *manager_; 171 : std::atomic<bool> deleted_; 172 : int refcount_; 173 : bool shutdown_invoked_; 174 : bool delete_paused_; 175 : uint64_t create_time_stamp_usecs_; 176 : uint64_t delete_time_stamp_usecs_; 177 : Dependents dependents_; 178 : 179 : DISALLOW_COPY_AND_ASSIGN(LifetimeActor); 180 : }; 181 : 182 : // 183 : // Handles deletion in the correct task context. 184 : // 185 : // The pointer to the actor is wrapped inside a LifetimeActorRef to prevent 186 : // the WorkQueue from deleting the actor. 187 : // 188 : class LifetimeManager { 189 : public: 190 : LifetimeManager(int task_id); 191 : virtual ~LifetimeManager(); 192 : 193 : // Return the number of times work queue task executions were deferred. 194 2 : size_t GetQueueDeferCount() { return defer_count_; } 195 : 196 : protected: 197 : virtual void SetQueueDisable(bool disabled); 198 : 199 : private: 200 : friend class LifetimeActor; 201 : 202 : struct LifetimeActorRef { 203 : LifetimeActor *actor; 204 : }; 205 : 206 : // Enqueue Delete event. 207 : void Enqueue(LifetimeActor *actor); 208 : 209 : // Enqueue Delete event. Used by the actor code which has already 210 : // incremented the reference count. 211 : void EnqueueNoIncrement(LifetimeActor *actor); 212 : 213 : // Check if global (not per-actor) conditions for destruction are 214 : // satisfied. Should be over-ridden by derived class if required. 215 136157 : virtual bool MayDestroy() { return true; } 216 : 217 : bool DeleteExecutor(LifetimeActorRef actor_ref); 218 : 219 : int defer_count_; 220 : WorkQueue<LifetimeActorRef> queue_; 221 : 222 : DISALLOW_COPY_AND_ASSIGN(LifetimeManager); 223 : }; 224 : 225 : #endif