1*635a8641SAndroid Build Coastguard Worker // Copyright 2018 The Chromium Authors. All rights reserved. 2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file. 4*635a8641SAndroid Build Coastguard Worker 5*635a8641SAndroid Build Coastguard Worker #ifndef BASE_TASK_SCHEDULER_TRACKED_REF_H_ 6*635a8641SAndroid Build Coastguard Worker #define BASE_TASK_SCHEDULER_TRACKED_REF_H_ 7*635a8641SAndroid Build Coastguard Worker 8*635a8641SAndroid Build Coastguard Worker #include <memory> 9*635a8641SAndroid Build Coastguard Worker 10*635a8641SAndroid Build Coastguard Worker #include "base/atomic_ref_count.h" 11*635a8641SAndroid Build Coastguard Worker #include "base/gtest_prod_util.h" 12*635a8641SAndroid Build Coastguard Worker #include "base/logging.h" 13*635a8641SAndroid Build Coastguard Worker #include "base/macros.h" 14*635a8641SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h" 15*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/waitable_event.h" 16*635a8641SAndroid Build Coastguard Worker 17*635a8641SAndroid Build Coastguard Worker namespace base { 18*635a8641SAndroid Build Coastguard Worker namespace internal { 19*635a8641SAndroid Build Coastguard Worker 20*635a8641SAndroid Build Coastguard Worker // TrackedRefs are effectively a ref-counting scheme for objects that have a 21*635a8641SAndroid Build Coastguard Worker // single owner. 22*635a8641SAndroid Build Coastguard Worker // 23*635a8641SAndroid Build Coastguard Worker // Deletion is still controlled by the single owner but ~T() itself will block 24*635a8641SAndroid Build Coastguard Worker // until all the TrackedRefs handed by its TrackedRefFactory have been released 25*635a8641SAndroid Build Coastguard Worker // (by ~TrackedRef<T>()). 26*635a8641SAndroid Build Coastguard Worker // 27*635a8641SAndroid Build Coastguard Worker // Just like WeakPtrFactory: TrackedRefFactory<T> should be the last member of T 28*635a8641SAndroid Build Coastguard Worker // to ensure ~TrackedRefFactory<T>() runs first in ~T(). 29*635a8641SAndroid Build Coastguard Worker // 30*635a8641SAndroid Build Coastguard Worker // The owner of a T should hence be certain that the last TrackedRefs to T are 31*635a8641SAndroid Build Coastguard Worker // already gone or on their way out before destroying it or ~T() will hang 32*635a8641SAndroid Build Coastguard Worker // (indicating a bug in the tear down logic -- proper refcounting on the other 33*635a8641SAndroid Build Coastguard Worker // hand would result in a leak). 34*635a8641SAndroid Build Coastguard Worker // 35*635a8641SAndroid Build Coastguard Worker // TrackedRefFactory only makes sense to use on types that are always leaked in 36*635a8641SAndroid Build Coastguard Worker // production but need to be torn down in tests (blocking destruction is 37*635a8641SAndroid Build Coastguard Worker // impractical in production -- ref. ScopedAllowBaseSyncPrimitivesForTesting 38*635a8641SAndroid Build Coastguard Worker // below). 39*635a8641SAndroid Build Coastguard Worker // 40*635a8641SAndroid Build Coastguard Worker // Why would we ever need such a thing? In task_scheduler there is a clear 41*635a8641SAndroid Build Coastguard Worker // ownership hierarchy with mostly single owners and little refcounting. In 42*635a8641SAndroid Build Coastguard Worker // production nothing is ever torn down so this isn't a problem. In tests 43*635a8641SAndroid Build Coastguard Worker // however we must JoinForTesting(). At that point, all the raw back T* refs 44*635a8641SAndroid Build Coastguard Worker // used by the worker threads are problematic because they can result in use- 45*635a8641SAndroid Build Coastguard Worker // after-frees if a worker outlives the deletion of its corresponding 46*635a8641SAndroid Build Coastguard Worker // TaskScheduler/TaskTracker/SchedulerWorkerPool/etc. 47*635a8641SAndroid Build Coastguard Worker // 48*635a8641SAndroid Build Coastguard Worker // JoinForTesting() isn't so hard when all workers are managed. But with cleanup 49*635a8641SAndroid Build Coastguard Worker // semantics (reclaiming a worker who's been idle for too long) it becomes 50*635a8641SAndroid Build Coastguard Worker // tricky because workers can go unaccounted for before they exit their main 51*635a8641SAndroid Build Coastguard Worker // (https://crbug.com/827615). 52*635a8641SAndroid Build Coastguard Worker // 53*635a8641SAndroid Build Coastguard Worker // For that reason and to clearly document the ownership model, task_scheduler 54*635a8641SAndroid Build Coastguard Worker // uses TrackedRefs. 55*635a8641SAndroid Build Coastguard Worker // 56*635a8641SAndroid Build Coastguard Worker // On top of being a clearer ownership model than proper refcounting, a hang in 57*635a8641SAndroid Build Coastguard Worker // tear down in a test with out-of-order tear down logic is much preferred to 58*635a8641SAndroid Build Coastguard Worker // letting its worker thread and associated constructs outlive the test 59*635a8641SAndroid Build Coastguard Worker // (potentially resulting in flakes in unrelated tests running later in the same 60*635a8641SAndroid Build Coastguard Worker // process). 61*635a8641SAndroid Build Coastguard Worker // 62*635a8641SAndroid Build Coastguard Worker // Note: While there's nothing task_scheduler specific about TrackedRefs it 63*635a8641SAndroid Build Coastguard Worker // requires an ownership model where all the TrackedRefs are released on other 64*635a8641SAndroid Build Coastguard Worker // threads in sync with ~T(). This isn't a typical use case beyond shutting down 65*635a8641SAndroid Build Coastguard Worker // TaskScheduler in tests and as such this is kept internal here for now. 66*635a8641SAndroid Build Coastguard Worker 67*635a8641SAndroid Build Coastguard Worker template <class T> 68*635a8641SAndroid Build Coastguard Worker class TrackedRefFactory; 69*635a8641SAndroid Build Coastguard Worker 70*635a8641SAndroid Build Coastguard Worker // TrackedRef<T> can be used like a T*. 71*635a8641SAndroid Build Coastguard Worker template <class T> 72*635a8641SAndroid Build Coastguard Worker class TrackedRef { 73*635a8641SAndroid Build Coastguard Worker public: 74*635a8641SAndroid Build Coastguard Worker // Moveable and copyable. TrackedRef(TrackedRef<T> && other)75*635a8641SAndroid Build Coastguard Worker TrackedRef(TrackedRef<T>&& other) 76*635a8641SAndroid Build Coastguard Worker : ptr_(other.ptr_), factory_(other.factory_) { 77*635a8641SAndroid Build Coastguard Worker // Null out |other_|'s factory so its destructor doesn't decrement 78*635a8641SAndroid Build Coastguard Worker // |live_tracked_refs_|. 79*635a8641SAndroid Build Coastguard Worker other.factory_ = nullptr; 80*635a8641SAndroid Build Coastguard Worker } TrackedRef(const TrackedRef<T> & other)81*635a8641SAndroid Build Coastguard Worker TrackedRef(const TrackedRef<T>& other) 82*635a8641SAndroid Build Coastguard Worker : ptr_(other.ptr_), factory_(other.factory_) { 83*635a8641SAndroid Build Coastguard Worker factory_->live_tracked_refs_.Increment(); 84*635a8641SAndroid Build Coastguard Worker } 85*635a8641SAndroid Build Coastguard Worker 86*635a8641SAndroid Build Coastguard Worker // Intentionally not assignable for now because it makes the logic slightly 87*635a8641SAndroid Build Coastguard Worker // convoluted and it's not a use case that makes sense for the types using 88*635a8641SAndroid Build Coastguard Worker // this at the moment. 89*635a8641SAndroid Build Coastguard Worker TrackedRef& operator=(TrackedRef<T>&& other) = delete; 90*635a8641SAndroid Build Coastguard Worker TrackedRef& operator=(const TrackedRef<T>& other) = delete; 91*635a8641SAndroid Build Coastguard Worker ~TrackedRef()92*635a8641SAndroid Build Coastguard Worker ~TrackedRef() { 93*635a8641SAndroid Build Coastguard Worker if (factory_ && !factory_->live_tracked_refs_.Decrement()) { 94*635a8641SAndroid Build Coastguard Worker DCHECK(factory_->ready_to_destroy_); 95*635a8641SAndroid Build Coastguard Worker DCHECK(!factory_->ready_to_destroy_->IsSignaled()); 96*635a8641SAndroid Build Coastguard Worker factory_->ready_to_destroy_->Signal(); 97*635a8641SAndroid Build Coastguard Worker } 98*635a8641SAndroid Build Coastguard Worker } 99*635a8641SAndroid Build Coastguard Worker 100*635a8641SAndroid Build Coastguard Worker T& operator*() const { return *ptr_; } 101*635a8641SAndroid Build Coastguard Worker 102*635a8641SAndroid Build Coastguard Worker T* operator->() const { return ptr_; } 103*635a8641SAndroid Build Coastguard Worker 104*635a8641SAndroid Build Coastguard Worker explicit operator bool() const { return ptr_ != nullptr; } 105*635a8641SAndroid Build Coastguard Worker 106*635a8641SAndroid Build Coastguard Worker private: 107*635a8641SAndroid Build Coastguard Worker friend class TrackedRefFactory<T>; 108*635a8641SAndroid Build Coastguard Worker TrackedRef(T * ptr,TrackedRefFactory<T> * factory)109*635a8641SAndroid Build Coastguard Worker TrackedRef(T* ptr, TrackedRefFactory<T>* factory) 110*635a8641SAndroid Build Coastguard Worker : ptr_(ptr), factory_(factory) { 111*635a8641SAndroid Build Coastguard Worker factory_->live_tracked_refs_.Increment(); 112*635a8641SAndroid Build Coastguard Worker } 113*635a8641SAndroid Build Coastguard Worker 114*635a8641SAndroid Build Coastguard Worker T* ptr_; 115*635a8641SAndroid Build Coastguard Worker TrackedRefFactory<T>* factory_; 116*635a8641SAndroid Build Coastguard Worker }; 117*635a8641SAndroid Build Coastguard Worker 118*635a8641SAndroid Build Coastguard Worker // TrackedRefFactory<T> should be the last member of T. 119*635a8641SAndroid Build Coastguard Worker template <class T> 120*635a8641SAndroid Build Coastguard Worker class TrackedRefFactory { 121*635a8641SAndroid Build Coastguard Worker public: TrackedRefFactory(T * ptr)122*635a8641SAndroid Build Coastguard Worker TrackedRefFactory(T* ptr) 123*635a8641SAndroid Build Coastguard Worker : ptr_(ptr), self_ref_(WrapUnique(new TrackedRef<T>(ptr_, this))) { 124*635a8641SAndroid Build Coastguard Worker DCHECK(ptr_); 125*635a8641SAndroid Build Coastguard Worker } 126*635a8641SAndroid Build Coastguard Worker ~TrackedRefFactory()127*635a8641SAndroid Build Coastguard Worker ~TrackedRefFactory() { 128*635a8641SAndroid Build Coastguard Worker // Enter the destruction phase. 129*635a8641SAndroid Build Coastguard Worker ready_to_destroy_ = std::make_unique<WaitableEvent>(); 130*635a8641SAndroid Build Coastguard Worker 131*635a8641SAndroid Build Coastguard Worker // Release self-ref (if this was the last one it will signal the event right 132*635a8641SAndroid Build Coastguard Worker // away). 133*635a8641SAndroid Build Coastguard Worker self_ref_.reset(); 134*635a8641SAndroid Build Coastguard Worker 135*635a8641SAndroid Build Coastguard Worker ready_to_destroy_->Wait(); 136*635a8641SAndroid Build Coastguard Worker } 137*635a8641SAndroid Build Coastguard Worker GetTrackedRef()138*635a8641SAndroid Build Coastguard Worker TrackedRef<T> GetTrackedRef() { 139*635a8641SAndroid Build Coastguard Worker // TrackedRefs cannot be obtained after |live_tracked_refs_| has already 140*635a8641SAndroid Build Coastguard Worker // reached zero. In other words, the owner of a TrackedRefFactory shouldn't 141*635a8641SAndroid Build Coastguard Worker // vend new TrackedRefs while it's being destroyed (owners of TrackedRefs 142*635a8641SAndroid Build Coastguard Worker // may still copy/move their refs around during the destruction phase). 143*635a8641SAndroid Build Coastguard Worker DCHECK(!live_tracked_refs_.IsZero()); 144*635a8641SAndroid Build Coastguard Worker return TrackedRef<T>(ptr_, this); 145*635a8641SAndroid Build Coastguard Worker } 146*635a8641SAndroid Build Coastguard Worker 147*635a8641SAndroid Build Coastguard Worker private: 148*635a8641SAndroid Build Coastguard Worker friend class TrackedRef<T>; 149*635a8641SAndroid Build Coastguard Worker FRIEND_TEST_ALL_PREFIXES(TrackedRefTest, CopyAndMoveSemantics); 150*635a8641SAndroid Build Coastguard Worker 151*635a8641SAndroid Build Coastguard Worker T* const ptr_; 152*635a8641SAndroid Build Coastguard Worker 153*635a8641SAndroid Build Coastguard Worker // The number of live TrackedRefs vended by this factory. 154*635a8641SAndroid Build Coastguard Worker AtomicRefCount live_tracked_refs_{0}; 155*635a8641SAndroid Build Coastguard Worker 156*635a8641SAndroid Build Coastguard Worker // Non-null during the destruction phase. Signaled once |live_tracked_refs_| 157*635a8641SAndroid Build Coastguard Worker // reaches 0. Note: while this could a direct member, only initializing it in 158*635a8641SAndroid Build Coastguard Worker // the destruction phase avoids keeping a handle open for the entire session. 159*635a8641SAndroid Build Coastguard Worker std::unique_ptr<WaitableEvent> ready_to_destroy_; 160*635a8641SAndroid Build Coastguard Worker 161*635a8641SAndroid Build Coastguard Worker // TrackedRefFactory holds a TrackedRef as well to prevent 162*635a8641SAndroid Build Coastguard Worker // |live_tracked_refs_| from ever reaching zero before ~TrackedRefFactory(). 163*635a8641SAndroid Build Coastguard Worker std::unique_ptr<TrackedRef<T>> self_ref_; 164*635a8641SAndroid Build Coastguard Worker 165*635a8641SAndroid Build Coastguard Worker DISALLOW_COPY_AND_ASSIGN(TrackedRefFactory); 166*635a8641SAndroid Build Coastguard Worker }; 167*635a8641SAndroid Build Coastguard Worker 168*635a8641SAndroid Build Coastguard Worker } // namespace internal 169*635a8641SAndroid Build Coastguard Worker } // namespace base 170*635a8641SAndroid Build Coastguard Worker 171*635a8641SAndroid Build Coastguard Worker #endif // BASE_TASK_SCHEDULER_TRACKED_REF_H_ 172