OpenSDN source code
lifetime.cc
Go to the documentation of this file.
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 
14  : ref_(this, actor) {
15 }
16 
18 }
19 
21  : manager_(manager), refcount_(0), shutdown_invoked_(false),
22  delete_paused_(false),
23  create_time_stamp_usecs_(UTCTimestampUsec()),
24  delete_time_stamp_usecs_(0) {
25  deleted_ = false;
26 }
27 
29  assert(refcount_ == 0);
30  assert(dependents_.empty());
31 }
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 //
41  std::scoped_lock lock(mutex_);
42  if (deleted_.exchange(true)) {
43  return;
44  }
46  refcount_++;
48 }
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 //
60  assert(deleted_);
61  std::scoped_lock lock(mutex_);
63  iter != dependents_.end(); ++iter) {
64  iter->Delete();
65  }
66 }
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 //
74  assert(deleted_);
75  manager_->Enqueue(this);
76 }
77 
78 //
79 // Concurrency: called in the context of the LifetimeManager's Task.
80 //
81 // Called immediately before the object is destroyed.
82 //
84 }
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 //
95 }
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 //
104  std::scoped_lock lock(mutex_);
105  assert(!deleted_);
106  delete_paused_ = true;
107 }
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 //
116  std::scoped_lock lock(mutex_);
117  assert(deleted_);
118  delete_paused_ = false;
119  refcount_++;
121 }
122 
123 //
124 // Concurrency: called in the context of any Task.
125 //
126 // Add the LifetimeRef as a dependent for this Actor.
127 //
130  std::scoped_lock lock(mutex_);
131  assert(!deleted_);
132  dependents_.Add(node);
133 }
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 //
144  std::scoped_lock lock(mutex_);
145  dependents_.Remove(node);
146  if (deleted_ && dependents_.empty()) {
147  refcount_++;
149  }
150 }
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.
156  std::scoped_lock lock(mutex_);
157  refcount_++;
158 }
159 
161  std::scoped_lock lock(mutex_);
162  refcount_--;
163  return (refcount_ == 0 && dependents_.empty() && !delete_paused_ &&
164  MayDelete());
165 }
166 
168  : defer_count_(0),
169  queue_(task_id, 0,
170  boost::bind(&LifetimeManager::DeleteExecutor, this, _1)) {
171  queue_.set_name("LifetimeManager");
172 }
173 
175  queue_.Shutdown();
176 }
177 
178 //
179 // Disable/Enable the WorkQueue - testing only.
180 //
181 void LifetimeManager::SetQueueDisable(bool disabled) {
182  queue_.set_disable(disabled);
183 }
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 //
191  LifetimeActorRef actor_ref;
192  actor->ReferenceIncrement();
193  actor_ref.actor = actor;
194  queue_.Enqueue(actor_ref);
195 }
196 
198  LifetimeActorRef actor_ref;
199  actor_ref.actor = actor;
200  queue_.Enqueue(actor_ref);
201 }
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 //
217  LifetimeActor *actor = actor_ref.actor;
218  assert(actor->IsDeleted());
219  if (!actor->shutdown_invoked()) {
220  actor->PropagateDelete();
221  actor->Shutdown();
222  actor->set_shutdown_invoked();
223  }
224  if (!MayDestroy()) {
225  EnqueueNoIncrement(actor);
226  defer_count_++;
227  return false;
228  }
229  if (actor->ReferenceDecrementAndTest()) {
230  actor->DeleteComplete();
231  actor->Destroy();
232  }
233  return true;
234 }
void Add(DependencyRef< NodeType, ObjectType > *node)
Definition: dependency.h:98
void Remove(DependencyRef< NodeType, ObjectType > *node)
Definition: dependency.h:102
iterator end()
Definition: dependency.h:116
bool empty() const
Definition: dependency.h:124
iterator begin()
Definition: dependency.h:115
IteratorBase< LifetimeRefBase, typename List::iterator > iterator
Definition: dependency.h:92
LifetimeManager * manager_
Definition: lifetime.h:170
std::mutex mutex_
Definition: lifetime.h:169
virtual void Shutdown()
Definition: lifetime.cc:94
virtual ~LifetimeActor()
Definition: lifetime.cc:28
virtual void Delete()
Definition: lifetime.cc:40
virtual bool MayDelete() const =0
bool shutdown_invoked()
Definition: lifetime.h:166
void PropagateDelete()
Definition: lifetime.cc:59
bool IsDeleted() const
Definition: lifetime.h:131
void DependencyAdd(DependencyRef< LifetimeRefBase, LifetimeActor > *node)
Definition: lifetime.cc:128
bool ReferenceDecrementAndTest()
Definition: lifetime.cc:160
virtual void Destroy()=0
void RetryDelete()
Definition: lifetime.cc:73
void ReferenceIncrement()
Definition: lifetime.cc:155
void set_shutdown_invoked()
Definition: lifetime.h:167
LifetimeActor(LifetimeManager *manager)
Definition: lifetime.cc:20
virtual void DeleteComplete()
Definition: lifetime.cc:83
std::atomic< bool > deleted_
Definition: lifetime.h:171
void PauseDelete()
Definition: lifetime.cc:103
Dependents dependents_
Definition: lifetime.h:177
void DependencyRemove(DependencyRef< LifetimeRefBase, LifetimeActor > *node)
Definition: lifetime.cc:142
void ResumeDelete()
Definition: lifetime.cc:115
uint64_t delete_time_stamp_usecs_
Definition: lifetime.h:176
bool delete_paused_
Definition: lifetime.h:174
void EnqueueNoIncrement(LifetimeActor *actor)
Definition: lifetime.cc:197
virtual void SetQueueDisable(bool disabled)
Definition: lifetime.cc:181
virtual ~LifetimeManager()
Definition: lifetime.cc:174
WorkQueue< LifetimeActorRef > queue_
Definition: lifetime.h:220
virtual bool MayDestroy()
Definition: lifetime.h:215
LifetimeManager(int task_id)
Definition: lifetime.cc:167
bool DeleteExecutor(LifetimeActorRef actor_ref)
Definition: lifetime.cc:216
void Enqueue(LifetimeActor *actor)
Definition: lifetime.cc:190
LifetimeRefBase(LifetimeActor *actor)
Definition: lifetime.cc:13
virtual ~LifetimeRefBase()
Definition: lifetime.cc:17
static uint64_t UTCTimestampUsec()
Definition: time_util.h:13