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

Generated by: LCOV version 1.14