LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/base - lifetime.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 109 109 100.0 %
Date: 2026-08-03 02:19:58 Functions: 22 24 91.7 %
Legend: Lines: hit not hit

          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             : }

Generated by: LCOV version 1.14