Line data Source code
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 <atomic>
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:
54 : /** Default construct, initializing the reference counts to 1.
55 : The strong references collectively hold one weak reference. When the
56 : strong reference count goes to zero, the collectively held weak
57 : reference is released.
58 : */
59 2 : SkWeakRefCnt() : SkRefCnt(), fWeakCnt(1) {}
60 :
61 : /** Destruct, asserting that the weak reference count is 1.
62 : */
63 0 : ~SkWeakRefCnt() override {
64 : #ifdef SK_DEBUG
65 0 : SkASSERT(getWeakCnt() == 1);
66 0 : fWeakCnt.store(0, std::memory_order_relaxed);
67 : #endif
68 0 : }
69 :
70 : #ifdef SK_DEBUG
71 : /** Return the weak reference count. */
72 0 : int32_t getWeakCnt() const {
73 0 : return fWeakCnt.load(std::memory_order_relaxed);
74 : }
75 :
76 : void validate() const {
77 : this->INHERITED::validate();
78 : SkASSERT(getWeakCnt() > 0);
79 : }
80 : #endif
81 :
82 : private:
83 : /** If fRefCnt is 0, returns 0.
84 : * Otherwise increments fRefCnt, acquires, and returns the old value.
85 : */
86 : int32_t atomic_conditional_acquire_strong_ref() const {
87 : int32_t prev = fRefCnt.load(std::memory_order_relaxed);
88 : do {
89 : if (0 == prev) {
90 : break;
91 : }
92 : } while(!fRefCnt.compare_exchange_weak(prev, prev+1, std::memory_order_acquire,
93 : std::memory_order_relaxed));
94 : return prev;
95 : }
96 :
97 : public:
98 : /** Creates a strong reference from a weak reference, if possible. The
99 : caller must already be an owner. If try_ref() returns true the owner
100 : is in posession of an additional strong reference. Both the original
101 : reference and new reference must be properly unreferenced. If try_ref()
102 : returns false, no strong reference could be created and the owner's
103 : reference is in the same state as before the call.
104 : */
105 : bool SK_WARN_UNUSED_RESULT try_ref() const {
106 : if (atomic_conditional_acquire_strong_ref() != 0) {
107 : // Acquire barrier (L/SL), if not provided above.
108 : // Prevents subsequent code from happening before the increment.
109 : return true;
110 : }
111 : return false;
112 : }
113 :
114 : /** Increment the weak reference count. Must be balanced by a call to
115 : weak_unref().
116 : */
117 : void weak_ref() const {
118 : SkASSERT(getRefCnt() > 0);
119 : SkASSERT(getWeakCnt() > 0);
120 : // No barrier required.
121 : (void)fWeakCnt.fetch_add(+1, std::memory_order_relaxed);
122 : }
123 :
124 : /** Decrement the weak reference count. If the weak reference count is 1
125 : before the decrement, then call delete on the object. Note that if this
126 : is the case, then the object needs to have been allocated via new, and
127 : not on the stack.
128 : */
129 0 : void weak_unref() const {
130 0 : SkASSERT(getWeakCnt() > 0);
131 : // A release here acts in place of all releases we "should" have been doing in ref().
132 0 : if (1 == fWeakCnt.fetch_add(-1, std::memory_order_acq_rel)) {
133 : // Like try_ref(), the acquire is only needed on success, to make sure
134 : // code in internal_dispose() doesn't happen before the decrement.
135 : #ifdef SK_DEBUG
136 : // so our destructor won't complain
137 0 : fWeakCnt.store(1, std::memory_order_relaxed);
138 : #endif
139 0 : this->INHERITED::internal_dispose();
140 : }
141 0 : }
142 :
143 : /** Returns true if there are no strong references to the object. When this
144 : is the case all future calls to try_ref() will return false.
145 : */
146 : bool weak_expired() const {
147 : return fRefCnt.load(std::memory_order_relaxed) == 0;
148 : }
149 :
150 : protected:
151 : /** Called when the strong reference count goes to zero. This allows the
152 : object to free any resources it may be holding. Weak references may
153 : still exist and their level of allowed access to the object is defined
154 : by the object's class.
155 : */
156 0 : virtual void weak_dispose() const {
157 0 : }
158 :
159 : private:
160 : /** Called when the strong reference count goes to zero. Calls weak_dispose
161 : on the object and releases the implicit weak reference held
162 : collectively by the strong references.
163 : */
164 0 : void internal_dispose() const override {
165 0 : weak_dispose();
166 0 : weak_unref();
167 0 : }
168 :
169 : /* Invariant: fWeakCnt = #weak + (fRefCnt > 0 ? 1 : 0) */
170 : mutable std::atomic<int32_t> fWeakCnt;
171 :
172 : typedef SkRefCnt INHERITED;
173 : };
174 :
175 : #endif
|