1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "chromecast/base/component/component.h"
6 
7 #include <set>
8 #include <utility>
9 
10 #include "base/atomicops.h"
11 #include "base/bind.h"
12 #include "base/callback_helpers.h"
13 #include "base/location.h"
14 #include "base/single_thread_task_runner.h"
15 #include "base/threading/thread_task_runner_handle.h"
16 
17 namespace chromecast {
18 
19 namespace {
20 
21 const base::subtle::AtomicWord kEnabledBit = 0x40000000;
22 
23 }  // namespace
24 
25 namespace subtle {
26 
27 class DependencyCount : public base::RefCountedThreadSafe<DependencyCount> {
28  public:
DependencyCount(ComponentBase * component)29   explicit DependencyCount(ComponentBase* component)
30       : component_(component),
31         task_runner_(base::ThreadTaskRunnerHandle::Get()),
32         dep_count_(0),
33         disabling_(false) {
34     DCHECK(component_);
35   }
36 
Detach()37   void Detach() {
38     DCHECK(task_runner_->BelongsToCurrentThread());
39     component_ = nullptr;
40   }
41 
Disable()42   void Disable() {
43     DCHECK(task_runner_->BelongsToCurrentThread());
44     DCHECK(!disabling_);
45     disabling_ = true;
46 
47     std::set<DependencyBase*> dependents(strong_dependents_);
48     for (DependencyBase* dependent : dependents)
49       dependent->Disable();
50 
51     while (true) {
52       AtomicWord deps = base::subtle::NoBarrier_Load(&dep_count_);
53       AtomicWord old_deps = base::subtle::Acquire_CompareAndSwap(
54           &dep_count_, deps, deps & ~kEnabledBit);
55       if (old_deps == deps) {
56         if ((deps & ~kEnabledBit) == 0)
57           DisableComplete();
58         return;
59       }
60     }
61   }
62 
Enable()63   void Enable() {
64     DCHECK(task_runner_->BelongsToCurrentThread());
65     disabling_ = false;
66     while (true) {
67       AtomicWord deps = base::subtle::NoBarrier_Load(&dep_count_);
68       DCHECK(!(deps & kEnabledBit));
69       AtomicWord old_deps = base::subtle::Release_CompareAndSwap(
70           &dep_count_, deps, deps | kEnabledBit);
71       if (old_deps == deps)
72         break;
73     }
74 
75     for (DependencyBase* dependent : strong_dependents_)
76       dependent->Ready(component_);
77   }
78 
WeakAcquireDep()79   ComponentBase* WeakAcquireDep() {
80     while (true) {
81       AtomicWord deps = base::subtle::NoBarrier_Load(&dep_count_);
82       if (!(deps & kEnabledBit))
83         return nullptr;
84       AtomicWord old_deps =
85           base::subtle::Acquire_CompareAndSwap(&dep_count_, deps, deps + 1);
86       // We depend on the fact that a component must be disabled (meaning that
87       // we will never reach this point) before it is destroyed. Therefore if
88       // we do reach this point, it is safe to return the raw pointer.
89       if (old_deps == deps)
90         return component_;
91     }
92   }
93 
StrongAcquireDep(DependencyBase * dependent)94   void StrongAcquireDep(DependencyBase* dependent) {
95     DCHECK(dependent);
96     DCHECK(task_runner_->BelongsToCurrentThread());
97     if (!component_) {
98       dependent->Disable();
99       return;
100     }
101 
102     strong_dependents_.insert(dependent);
103     AtomicWord count = base::subtle::NoBarrier_AtomicIncrement(&dep_count_, 1);
104     DCHECK_GT(count, 0);
105 
106     if (count & kEnabledBit) {
107       dependent->Ready(component_);
108     } else {
109       component_->Enable();
110     }
111   }
112 
StrongReleaseDep(DependencyBase * dependent)113   void StrongReleaseDep(DependencyBase* dependent) {
114     DCHECK(dependent);
115     DCHECK(task_runner_->BelongsToCurrentThread());
116     strong_dependents_.erase(dependent);
117     ReleaseDep();
118   }
119 
ReleaseDep()120   void ReleaseDep() {
121     AtomicWord after = base::subtle::Barrier_AtomicIncrement(&dep_count_, -1);
122     DCHECK_GE(after, 0);
123     if (after == 0)
124       DisableComplete();
125   }
126 
DependsOn(ComponentBase * component)127   bool DependsOn(ComponentBase* component) {
128     DCHECK(task_runner_->BelongsToCurrentThread());
129     if (!component_)
130       return false;
131     if (component_ == component)
132       return true;
133     return component_->DependsOn(component);
134   }
135 
136  private:
137   friend class base::RefCountedThreadSafe<DependencyCount>;
138   using AtomicWord = base::subtle::AtomicWord;
139 
~DependencyCount()140   ~DependencyCount() {}
141 
DisableComplete()142   void DisableComplete() {
143     if (!task_runner_->BelongsToCurrentThread()) {
144       task_runner_->PostTask(
145           FROM_HERE, base::BindOnce(&DependencyCount::DisableComplete, this));
146       return;
147     }
148     // Need to make sure that Enable() was not called in the meantime.
149     if (base::subtle::NoBarrier_Load(&dep_count_) != 0 || !disabling_)
150       return;
151     // Ensure that we don't call DisableComplete() more than once per Disable().
152     disabling_ = false;
153     DCHECK(component_);
154     DCHECK(strong_dependents_.empty());
155     component_->DependencyCountDisableComplete();
156   }
157 
158   ComponentBase* component_;
159   const scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
160   AtomicWord dep_count_;
161   bool disabling_;
162   std::set<DependencyBase*> strong_dependents_;
163 
164   DISALLOW_COPY_AND_ASSIGN(DependencyCount);
165 };
166 
DependencyBase(const WeakReferenceBase & dependency,ComponentBase * dependent)167 DependencyBase::DependencyBase(const WeakReferenceBase& dependency,
168                                ComponentBase* dependent)
169     : dependent_(dependent),
170       dependency_(nullptr),
171       counter_(dependency.counter_) {
172   DCHECK(dependent_);
173   dependent_->AddDependency(this);
174 }
175 
~DependencyBase()176 DependencyBase::~DependencyBase() {}
177 
StartUsing()178 void DependencyBase::StartUsing() {
179   DCHECK(thread_checker_.CalledOnValidThread());
180   DCHECK(!dependency_);
181   counter_->StrongAcquireDep(this);
182 }
183 
StopUsing()184 void DependencyBase::StopUsing() {
185   DCHECK(thread_checker_.CalledOnValidThread());
186   if (!dependency_)
187     return;
188   dependency_ = nullptr;
189   counter_->StrongReleaseDep(this);
190 }
191 
Ready(ComponentBase * dependency)192 void DependencyBase::Ready(ComponentBase* dependency) {
193   DCHECK(thread_checker_.CalledOnValidThread());
194   DCHECK(!dependency_);
195   DCHECK(dependency);
196   dependency_ = dependency;
197   dependent_->DependencyReady();
198 }
199 
Disable()200 void DependencyBase::Disable() {
201   DCHECK(thread_checker_.CalledOnValidThread());
202   dependent_->Disable();
203 }
204 
DependsOn(ComponentBase * component)205 bool DependencyBase::DependsOn(ComponentBase* component) {
206   return counter_->DependsOn(component);
207 }
208 
WeakReferenceBase(const ComponentBase & dependency)209 WeakReferenceBase::WeakReferenceBase(const ComponentBase& dependency)
210     : counter_(dependency.counter_) {
211   DCHECK(counter_);
212 }
213 
WeakReferenceBase(const DependencyBase & dependency)214 WeakReferenceBase::WeakReferenceBase(const DependencyBase& dependency)
215     : counter_(dependency.counter_) {
216   DCHECK(counter_);
217 }
218 
WeakReferenceBase(const WeakReferenceBase & other)219 WeakReferenceBase::WeakReferenceBase(const WeakReferenceBase& other)
220     : counter_(other.counter_) {
221   DCHECK(counter_);
222 }
223 
WeakReferenceBase(WeakReferenceBase && other)224 WeakReferenceBase::WeakReferenceBase(WeakReferenceBase&& other)
225     : counter_(std::move(other.counter_)) {
226   DCHECK(counter_);
227 }
228 
~WeakReferenceBase()229 WeakReferenceBase::~WeakReferenceBase() {}
230 
ScopedReferenceBase(const scoped_refptr<DependencyCount> & counter)231 ScopedReferenceBase::ScopedReferenceBase(
232     const scoped_refptr<DependencyCount>& counter)
233     : counter_(counter) {
234   DCHECK(counter_);
235   dependency_ = counter_->WeakAcquireDep();
236 }
237 
ScopedReferenceBase(ScopedReferenceBase && other)238 ScopedReferenceBase::ScopedReferenceBase(ScopedReferenceBase&& other)
239     : counter_(std::move(other.counter_)), dependency_(other.dependency_) {
240   DCHECK(counter_);
241   other.dependency_ = nullptr;
242 }
243 
~ScopedReferenceBase()244 ScopedReferenceBase::~ScopedReferenceBase() {
245   if (dependency_)
246     counter_->ReleaseDep();
247 }
248 
249 }  // namespace subtle
250 
ComponentBase()251 ComponentBase::ComponentBase()
252     : task_runner_(base::ThreadTaskRunnerHandle::Get()),
253       state_(kStateDisabled),
254       async_call_in_progress_(false),
255       pending_dependency_count_(0),
256       observers_(new base::ObserverListThreadSafe<Observer>()) {
257   counter_ = new subtle::DependencyCount(this);
258 }
259 
~ComponentBase()260 ComponentBase::~ComponentBase() {
261   DCHECK(task_runner_->BelongsToCurrentThread());
262   DCHECK_EQ(kStateDisabled, state_) << "Components must be disabled "
263                                     << "before being destroyed";
264   counter_->Detach();
265 }
266 
Enable()267 void ComponentBase::Enable() {
268   DCHECK(task_runner_->BelongsToCurrentThread());
269   if (state_ == kStateEnabling || state_ == kStateEnabled ||
270       state_ == kStateDestroying) {
271     return;
272   }
273   state_ = kStateEnabling;
274 
275   if (strong_dependencies_.empty()) {
276     TryOnEnable();
277   } else {
278     // Enable all strong dependencies first.
279     pending_dependency_count_ = strong_dependencies_.size();
280     for (subtle::DependencyBase* dependency : strong_dependencies_)
281       dependency->StartUsing();
282   }
283 }
284 
DependencyReady()285 void ComponentBase::DependencyReady() {
286   DCHECK(task_runner_->BelongsToCurrentThread());
287   if (state_ != kStateEnabling)
288     return;
289   DCHECK_GT(pending_dependency_count_, 0);
290   --pending_dependency_count_;
291   if (pending_dependency_count_ == 0)
292     TryOnEnable();
293 }
294 
TryOnEnable()295 void ComponentBase::TryOnEnable() {
296   DCHECK_EQ(kStateEnabling, state_);
297   if (async_call_in_progress_)
298     return;
299   async_call_in_progress_ = true;
300   OnEnable();
301 }
302 
OnEnableComplete(bool success)303 void ComponentBase::OnEnableComplete(bool success) {
304   // Always post a task, to prevent the stack from getting too deep.
305   task_runner_->PostTask(
306       FROM_HERE, base::BindOnce(&ComponentBase::OnEnableCompleteInternal,
307                                 base::Unretained(this), success));
308 }
309 
OnEnableCompleteInternal(bool success)310 void ComponentBase::OnEnableCompleteInternal(bool success) {
311   async_call_in_progress_ = false;
312   DCHECK(state_ == kStateEnabling || state_ == kStateDisabling ||
313          state_ == kStateDestroying);
314   if (state_ != kStateEnabling) {
315     if (success) {
316       TryOnDisable();
317     } else {
318       OnDisableCompleteInternal();
319     }
320     return;
321   }
322 
323   if (success) {
324     state_ = kStateEnabled;
325     counter_->Enable();
326   } else {
327     Disable();
328   }
329   observers_->Notify(FROM_HERE, &Observer::OnComponentEnabled, this, success);
330 }
331 
Destroy()332 void ComponentBase::Destroy() {
333   DCHECK(task_runner_->BelongsToCurrentThread());
334   DCHECK_NE(kStateDestroying, state_);
335   if (state_ == kStateDisabled) {
336     delete this;
337   } else {
338     bool should_disable = (state_ != kStateDisabling);
339     state_ = kStateDestroying;
340     if (should_disable)
341       counter_->Disable();
342   }
343 }
344 
AddObserver(Observer * observer)345 void ComponentBase::AddObserver(Observer* observer) {
346   DCHECK(observer);
347   observers_->AddObserver(observer);
348 }
349 
RemoveObserver(Observer * observer)350 void ComponentBase::RemoveObserver(Observer* observer) {
351   observers_->RemoveObserver(observer);
352 }
353 
Disable()354 void ComponentBase::Disable() {
355   DCHECK(task_runner_->BelongsToCurrentThread());
356   if (state_ == kStateDisabling || state_ == kStateDisabled ||
357       state_ == kStateDestroying) {
358     return;
359   }
360   state_ = kStateDisabling;
361   counter_->Disable();
362 }
363 
DependencyCountDisableComplete()364 void ComponentBase::DependencyCountDisableComplete() {
365   DCHECK(task_runner_->BelongsToCurrentThread());
366   if (state_ == kStateDisabling || state_ == kStateDestroying)
367     TryOnDisable();
368 }
369 
TryOnDisable()370 void ComponentBase::TryOnDisable() {
371   DCHECK(state_ == kStateDisabling || state_ == kStateDestroying);
372   if (async_call_in_progress_)
373     return;
374   async_call_in_progress_ = true;
375   OnDisable();
376 }
377 
OnDisableComplete()378 void ComponentBase::OnDisableComplete() {
379   // Always post a task, to prevent calls to Disable() from within Enable().
380   task_runner_->PostTask(
381       FROM_HERE, base::BindOnce(&ComponentBase::OnDisableCompleteInternal,
382                                 base::Unretained(this)));
383 }
384 
OnDisableCompleteInternal()385 void ComponentBase::OnDisableCompleteInternal() {
386   async_call_in_progress_ = false;
387   DCHECK(state_ == kStateEnabling || state_ == kStateDisabling ||
388          state_ == kStateDestroying);
389   if (state_ == kStateEnabling) {
390     TryOnEnable();
391     return;
392   }
393 
394   if (state_ == kStateDestroying) {
395     StopUsingDependencies();
396     observers_->Notify(FROM_HERE, &Observer::OnComponentDisabled, this);
397     state_ = kStateDisabled;
398     delete this;
399   } else {
400     state_ = kStateDisabled;
401     StopUsingDependencies();
402     observers_->Notify(FROM_HERE, &Observer::OnComponentDisabled, this);
403   }
404 }
405 
AddDependency(subtle::DependencyBase * dependency)406 void ComponentBase::AddDependency(subtle::DependencyBase* dependency) {
407   DCHECK_EQ(kStateDisabled, state_);
408   DCHECK(!dependency->DependsOn(this)) << "Circular dependency detected";
409   strong_dependencies_.push_back(dependency);
410 }
411 
StopUsingDependencies()412 void ComponentBase::StopUsingDependencies() {
413   for (subtle::DependencyBase* dependency : strong_dependencies_)
414     dependency->StopUsing();
415 }
416 
DependsOn(ComponentBase * component)417 bool ComponentBase::DependsOn(ComponentBase* component) {
418   for (subtle::DependencyBase* dependency : strong_dependencies_) {
419     if (dependency->DependsOn(component))
420       return true;
421   }
422   return false;
423 }
424 
425 }  // namespace chromecast
426