1 /* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 #ifndef SkWeakRefCnt_DEFINED 9 #define SkWeakRefCnt_DEFINED 10 11 #include "SkRefCnt.h" 12 #include "SkThread.h" 13 14 /** \class SkWeakRefCnt 15 16 SkWeakRefCnt is the base class for objects that may be shared by multiple 17 objects. When an existing strong owner wants to share a reference, it calls 18 ref(). When a strong owner wants to release its reference, it calls 19 unref(). When the shared object's strong reference count goes to zero as 20 the result of an unref() call, its (virtual) weak_dispose method is called. 21 It is an error for the destructor to be called explicitly (or via the 22 object going out of scope on the stack or calling delete) if 23 getRefCnt() > 1. 24 25 In addition to strong ownership, an owner may instead obtain a weak 26 reference by calling weak_ref(). A call to weak_ref() must be balanced by a 27 call to weak_unref(). To obtain a strong reference from a weak reference, 28 call try_ref(). If try_ref() returns true, the owner's pointer is now also 29 a strong reference on which unref() must be called. Note that this does not 30 affect the original weak reference, weak_unref() must still be called. When 31 the weak reference count goes to zero, the object is deleted. While the 32 weak reference count is positive and the strong reference count is zero the 33 object still exists, but will be in the disposed state. It is up to the 34 object to define what this means. 35 36 Note that a strong reference implicitly implies a weak reference. As a 37 result, it is allowable for the owner of a strong ref to call try_ref(). 38 This will have the same effect as calling ref(), but may be more expensive. 39 40 Example: 41 42 SkWeakRefCnt myRef = strongRef.weak_ref(); 43 ... // strongRef.unref() may or may not be called 44 if (myRef.try_ref()) { 45 ... // use myRef 46 myRef.unref(); 47 } else { 48 // myRef is in the disposed state 49 } 50 myRef.weak_unref(); 51 */ 52 class SK_API SkWeakRefCnt : public SkRefCnt { 53 public: SK_DECLARE_INST_COUNT(SkWeakRefCnt)54 SK_DECLARE_INST_COUNT(SkWeakRefCnt) 55 56 /** Default construct, initializing the reference counts to 1. 57 The strong references collectively hold one weak reference. When the 58 strong reference count goes to zero, the collectively held weak 59 reference is released. 60 */ 61 SkWeakRefCnt() : SkRefCnt(), fWeakCnt(1) {} 62 63 /** Destruct, asserting that the weak reference count is 1. 64 */ ~SkWeakRefCnt()65 virtual ~SkWeakRefCnt() { 66 #ifdef SK_DEBUG 67 SkASSERT(fWeakCnt == 1); 68 fWeakCnt = 0; 69 #endif 70 } 71 72 /** Return the weak reference count. 73 */ getWeakCnt()74 int32_t getWeakCnt() const { return fWeakCnt; } 75 76 #ifdef SK_DEBUG validate()77 void validate() const { 78 this->INHERITED::validate(); 79 SkASSERT(fWeakCnt > 0); 80 } 81 #endif 82 83 /** Creates a strong reference from a weak reference, if possible. The 84 caller must already be an owner. If try_ref() returns true the owner 85 is in posession of an additional strong reference. Both the original 86 reference and new reference must be properly unreferenced. If try_ref() 87 returns false, no strong reference could be created and the owner's 88 reference is in the same state as before the call. 89 */ try_ref()90 bool SK_WARN_UNUSED_RESULT try_ref() const { 91 if (sk_atomic_conditional_inc(&fRefCnt) != 0) { 92 // Acquire barrier (L/SL), if not provided above. 93 // Prevents subsequent code from happening before the increment. 94 sk_membar_acquire__after_atomic_conditional_inc(); 95 return true; 96 } 97 return false; 98 } 99 100 /** Increment the weak reference count. Must be balanced by a call to 101 weak_unref(). 102 */ weak_ref()103 void weak_ref() const { 104 SkASSERT(fRefCnt > 0); 105 SkASSERT(fWeakCnt > 0); 106 sk_atomic_inc(&fWeakCnt); // No barrier required. 107 } 108 109 /** Decrement the weak reference count. If the weak reference count is 1 110 before the decrement, then call delete on the object. Note that if this 111 is the case, then the object needs to have been allocated via new, and 112 not on the stack. 113 */ weak_unref()114 void weak_unref() const { 115 SkASSERT(fWeakCnt > 0); 116 // Release barrier (SL/S), if not provided below. 117 if (sk_atomic_dec(&fWeakCnt) == 1) { 118 // Acquire barrier (L/SL), if not provided above. 119 // Prevents code in destructor from happening before the decrement. 120 sk_membar_acquire__after_atomic_dec(); 121 #ifdef SK_DEBUG 122 // so our destructor won't complain 123 fWeakCnt = 1; 124 #endif 125 this->INHERITED::internal_dispose(); 126 } 127 } 128 129 /** Returns true if there are no strong references to the object. When this 130 is the case all future calls to try_ref() will return false. 131 */ weak_expired()132 bool weak_expired() const { 133 return fRefCnt == 0; 134 } 135 136 protected: 137 /** Called when the strong reference count goes to zero. This allows the 138 object to free any resources it may be holding. Weak references may 139 still exist and their level of allowed access to the object is defined 140 by the object's class. 141 */ weak_dispose()142 virtual void weak_dispose() const { 143 } 144 145 private: 146 /** Called when the strong reference count goes to zero. Calls weak_dispose 147 on the object and releases the implicit weak reference held 148 collectively by the strong references. 149 */ internal_dispose()150 void internal_dispose() const override { 151 weak_dispose(); 152 weak_unref(); 153 } 154 155 /* Invariant: fWeakCnt = #weak + (fRefCnt > 0 ? 1 : 0) */ 156 mutable int32_t fWeakCnt; 157 158 typedef SkRefCnt INHERITED; 159 }; 160 161 #endif 162