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