Line data Source code
1 : /* 2 : * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved. 3 : */ 4 : 5 : #include "base/lifetime.h" 6 : 7 : #include <boost/bind/bind.hpp> 8 : #include "base/backtrace.h" 9 : #include "base/time_util.h" 10 : 11 : using namespace boost::placeholders; 12 : 13 1216441 : LifetimeRefBase::LifetimeRefBase(LifetimeActor *actor) 14 1216441 : : ref_(this, actor) { 15 1216500 : } 16 : 17 1216991 : LifetimeRefBase::~LifetimeRefBase() { 18 1216991 : } 19 : 20 1033200 : LifetimeActor::LifetimeActor(LifetimeManager *manager) 21 1033093 : : manager_(manager), refcount_(0), shutdown_invoked_(false), 22 1033093 : delete_paused_(false), 23 1033093 : create_time_stamp_usecs_(UTCTimestampUsec()), 24 2066603 : delete_time_stamp_usecs_(0) { 25 1033131 : deleted_ = false; 26 1033553 : } 27 : 28 1033608 : LifetimeActor::~LifetimeActor() { 29 1033608 : assert(refcount_ == 0); 30 1033608 : assert(dependents_.empty()); 31 1033608 : } 32 : 33 : // 34 : // Concurrency: called in the context of any Task or the main thread. 35 : // 36 : // Used to trigger delete for managed object and it's dependents. Enqueue 37 : // this actor to the Lifetime Manager. Propagation of the delete operation 38 : // to dependents happens in the context of the LifetimeManager's Task. 39 : // 40 1056435 : void LifetimeActor::Delete() { 41 1056435 : std::scoped_lock lock(mutex_); 42 1056435 : if (deleted_.exchange(true)) { 43 24377 : return; 44 : } 45 1032058 : delete_time_stamp_usecs_ = UTCTimestampUsec(); 46 1032058 : refcount_++; 47 1032058 : manager_->EnqueueNoIncrement(this); 48 1056435 : } 49 : 50 : // 51 : // Concurrency: called in the context of the LifetimeManager's Task. 52 : // 53 : // Used to propagate delete for a managed object to it's dependents. 54 : // 55 : // Walk the list of dependent LifetimeRefs and propagate the delete. A mutex is 56 : // used to ensure that the dependent list does not change while we are walking 57 : // through it. 58 : // 59 1032058 : void LifetimeActor::PropagateDelete() { 60 1032058 : assert(deleted_); 61 1032058 : std::scoped_lock lock(mutex_); 62 1032058 : for (Dependents::iterator iter = dependents_.begin(); 63 2156731 : iter != dependents_.end(); ++iter) { 64 1124673 : iter->Delete(); 65 : } 66 1032058 : } 67 : 68 : // 69 : // Concurrency: called in the context of any Task or the main thread. 70 : // 71 : // Enqueue a delete event for this actor to the LifetimeManager. 72 : // 73 443312 : void LifetimeActor::RetryDelete() { 74 443312 : assert(deleted_); 75 443312 : manager_->Enqueue(this); 76 443328 : } 77 : 78 : // 79 : // Concurrency: called in the context of the LifetimeManager's Task. 80 : // 81 : // Called immediately before the object is destroyed. 82 : // 83 1032056 : void LifetimeActor::DeleteComplete() { 84 1032056 : } 85 : 86 : // 87 : // Concurrency: called in the context of the LifetimeManager's Task. 88 : // 89 : // Can be called multiple times - when the managed object is initially deleted 90 : // and whenever a delete event is enqueued to the Lifetime Manager. The latter 91 : // happens when the list of dependents becomes empty or the refcount of the 92 : // lightweight dependents goes to 0. 93 : // 94 171776 : void LifetimeActor::Shutdown() { 95 171776 : } 96 : 97 : // 98 : // Concurrency: called in the context of main thread. 99 : // TaskScheduler should be stopped prior to invoking this method. 100 : // 101 : // Prevent object from getting destroyed - testing only. 102 : // 103 2617 : void LifetimeActor::PauseDelete() { 104 2617 : std::scoped_lock lock(mutex_); 105 2617 : assert(!deleted_); 106 2617 : delete_paused_ = true; 107 2617 : } 108 : 109 : // 110 : // Concurrency: called in the context of main thread. 111 : // TaskScheduler should be stopped prior to invoking this method. 112 : // 113 : // Allow object to get destroyed - testing only. 114 : // 115 2617 : void LifetimeActor::ResumeDelete() { 116 2617 : std::scoped_lock lock(mutex_); 117 2617 : assert(deleted_); 118 2617 : delete_paused_ = false; 119 2617 : refcount_++; 120 2617 : manager_->EnqueueNoIncrement(this); 121 2617 : } 122 : 123 : // 124 : // Concurrency: called in the context of any Task. 125 : // 126 : // Add the LifetimeRef as a dependent for this Actor. 127 : // 128 1204225 : void LifetimeActor::DependencyAdd( 129 : DependencyRef<LifetimeRefBase, LifetimeActor> *node) { 130 1204225 : std::scoped_lock lock(mutex_); 131 1204381 : assert(!deleted_); 132 1204229 : dependents_.Add(node); 133 1204034 : } 134 : 135 : // 136 : // Concurrency: called in the context of the LifetimeManager's Task. 137 : // 138 : // Remove the LifetimeRef as a dependent of this Actor. Note that this can 139 : // happen when the dependent object itself is being deleted i.e. this actor 140 : // itself need not be marked deleted. 141 : // 142 1204545 : void LifetimeActor::DependencyRemove( 143 : DependencyRef<LifetimeRefBase, LifetimeActor> *node) { 144 1204545 : std::scoped_lock lock(mutex_); 145 1204549 : dependents_.Remove(node); 146 1204544 : if (deleted_ && dependents_.empty()) { 147 357058 : refcount_++; 148 357058 : manager_->EnqueueNoIncrement(this); 149 : } 150 1204545 : } 151 : 152 : // When the actor is placed in the queue the caller must still hold an 153 : // "lock" on the object in the form of either a dependency or an 154 : // explicit test performed by the derived class MayDelete() method. 155 443310 : void LifetimeActor::ReferenceIncrement() { 156 443310 : std::scoped_lock lock(mutex_); 157 443325 : refcount_++; 158 443325 : } 159 : 160 1835062 : bool LifetimeActor::ReferenceDecrementAndTest() { 161 1835062 : std::scoped_lock lock(mutex_); 162 1835062 : refcount_--; 163 2899123 : return (refcount_ == 0 && dependents_.empty() && !delete_paused_ && 164 2899123 : MayDelete()); 165 1835062 : } 166 : 167 17441 : LifetimeManager::LifetimeManager(int task_id) 168 17441 : : defer_count_(0), 169 17441 : queue_(task_id, 0, 170 17441 : boost::bind(&LifetimeManager::DeleteExecutor, this, _1)) { 171 17441 : queue_.set_name("LifetimeManager"); 172 17441 : } 173 : 174 22949 : LifetimeManager::~LifetimeManager() { 175 17426 : queue_.Shutdown(); 176 22949 : } 177 : 178 : // 179 : // Disable/Enable the WorkQueue - testing only. 180 : // 181 96 : void LifetimeManager::SetQueueDisable(bool disabled) { 182 96 : queue_.set_disable(disabled); 183 96 : } 184 : 185 : // 186 : // Concurrency: called in the context of any Task or the main thread. 187 : // 188 : // Enqueue a delete event for the actor. 189 : // 190 443311 : void LifetimeManager::Enqueue(LifetimeActor *actor) { 191 : LifetimeActorRef actor_ref; 192 443311 : actor->ReferenceIncrement(); 193 443323 : actor_ref.actor = actor; 194 443323 : queue_.Enqueue(actor_ref); 195 443328 : } 196 : 197 1910489 : void LifetimeManager::EnqueueNoIncrement(LifetimeActor *actor) { 198 : LifetimeActorRef actor_ref; 199 1910489 : actor_ref.actor = actor; 200 1910489 : queue_.Enqueue(actor_ref); 201 1910490 : } 202 : 203 : // 204 : // Concurrency: called in the context of the LifetimeManager's Task. 205 : // 206 : // If this is the first time that the delete actor is being processed, we 207 : // propagate the delete to it's dependents and ask the managed object to 208 : // shut itself i.e. take care of cleaning up any state not represented as 209 : // an explicit LifetimeRef dependent. 210 : // 211 : // If global conditions for object destruction are not satisfied, enqueue 212 : // the delete actor again and defer processing of the queue. Do not bump 213 : // up the refcount in this case. 214 : // Else go ahead and destroy the object if all conditions are satisfied. 215 : // 216 2353818 : bool LifetimeManager::DeleteExecutor(LifetimeActorRef actor_ref) { 217 2353818 : LifetimeActor *actor = actor_ref.actor; 218 2353818 : assert(actor->IsDeleted()); 219 2353818 : if (!actor->shutdown_invoked()) { 220 1032058 : actor->PropagateDelete(); 221 1032058 : actor->Shutdown(); 222 1032058 : actor->set_shutdown_invoked(); 223 : } 224 2353818 : if (!MayDestroy()) { 225 518756 : EnqueueNoIncrement(actor); 226 518756 : defer_count_++; 227 518756 : return false; 228 : } 229 1835062 : if (actor->ReferenceDecrementAndTest()) { 230 1032056 : actor->DeleteComplete(); 231 1032056 : actor->Destroy(); 232 : } 233 1835062 : return true; 234 : }