LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/base - lifetime.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 17 18 94.4 %
Date: 2026-11-09 02:10:49 Functions: 83 85 97.6 %
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             : #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

Generated by: LCOV version 1.14