OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2006 The Android Open Source Project | 2 * Copyright 2006 The Android Open Source Project |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #ifndef SkRefCnt_DEFINED | 8 #ifndef SkRefCnt_DEFINED |
9 #define SkRefCnt_DEFINED | 9 #define SkRefCnt_DEFINED |
10 | 10 |
11 #include "../private/SkAtomics.h" | |
12 #include "../private/SkTLogic.h" | 11 #include "../private/SkTLogic.h" |
13 #include "SkTypes.h" | 12 #include "SkTypes.h" |
| 13 #include <atomic> |
14 #include <functional> | 14 #include <functional> |
15 #include <memory> | 15 #include <memory> |
16 #include <utility> | 16 #include <utility> |
17 | 17 |
18 #define SK_SUPPORT_TRANSITION_TO_SP_INTERFACES | 18 #define SK_SUPPORT_TRANSITION_TO_SP_INTERFACES |
19 | 19 |
20 /** \class SkRefCntBase | 20 /** \class SkRefCntBase |
21 | 21 |
22 SkRefCntBase is the base class for objects that may be shared by multiple | 22 SkRefCntBase is the base class for objects that may be shared by multiple |
23 objects. When an existing owner wants to share a reference, it calls ref(). | 23 objects. When an existing owner wants to share a reference, it calls ref(). |
24 When an owner wants to release its reference, it calls unref(). When the | 24 When an owner wants to release its reference, it calls unref(). When the |
25 shared object's reference count goes to zero as the result of an unref() | 25 shared object's reference count goes to zero as the result of an unref() |
26 call, its (virtual) destructor is called. It is an error for the | 26 call, its (virtual) destructor is called. It is an error for the |
27 destructor to be called explicitly (or via the object going out of scope on | 27 destructor to be called explicitly (or via the object going out of scope on |
28 the stack or calling delete) if getRefCnt() > 1. | 28 the stack or calling delete) if getRefCnt() > 1. |
29 */ | 29 */ |
30 class SK_API SkRefCntBase : SkNoncopyable { | 30 class SK_API SkRefCntBase : SkNoncopyable { |
31 public: | 31 public: |
32 /** Default construct, initializing the reference count to 1. | 32 /** Default construct, initializing the reference count to 1. |
33 */ | 33 */ |
34 SkRefCntBase() : fRefCnt(1) {} | 34 SkRefCntBase() : fRefCnt(1) {} |
35 | 35 |
36 /** Destruct, asserting that the reference count is 1. | 36 /** Destruct, asserting that the reference count is 1. |
37 */ | 37 */ |
38 virtual ~SkRefCntBase() { | 38 virtual ~SkRefCntBase() { |
39 #ifdef SK_DEBUG | 39 #ifdef SK_DEBUG |
40 SkASSERTF(fRefCnt == 1, "fRefCnt was %d", fRefCnt); | 40 SkASSERTF(getRefCnt() == 1, "fRefCnt was %d", getRefCnt()); |
41 fRefCnt = 0; // illegal value, to catch us if we reuse after delete | 41 // illegal value, to catch us if we reuse after delete |
| 42 fRefCnt.store(0, std::memory_order_relaxed); |
42 #endif | 43 #endif |
43 } | 44 } |
44 | 45 |
45 #ifdef SK_DEBUG | 46 #ifdef SK_DEBUG |
46 /** Return the reference count. Use only for debugging. */ | 47 /** Return the reference count. Use only for debugging. */ |
47 int32_t getRefCnt() const { return fRefCnt; } | 48 int32_t getRefCnt() const { |
| 49 return fRefCnt.load(std::memory_order_relaxed); |
| 50 } |
| 51 |
| 52 void validate() const { |
| 53 SkASSERT(getRefCnt() > 0); |
| 54 } |
48 #endif | 55 #endif |
49 | 56 |
50 /** May return true if the caller is the only owner. | 57 /** May return true if the caller is the only owner. |
51 * Ensures that all previous owner's actions are complete. | 58 * Ensures that all previous owner's actions are complete. |
52 */ | 59 */ |
53 bool unique() const { | 60 bool unique() const { |
54 if (1 == sk_atomic_load(&fRefCnt, sk_memory_order_acquire)) { | 61 if (1 == fRefCnt.load(std::memory_order_acquire)) { |
55 // The acquire barrier is only really needed if we return true. It | 62 // The acquire barrier is only really needed if we return true. It |
56 // prevents code conditioned on the result of unique() from running | 63 // prevents code conditioned on the result of unique() from running |
57 // until previous owners are all totally done calling unref(). | 64 // until previous owners are all totally done calling unref(). |
58 return true; | 65 return true; |
59 } | 66 } |
60 return false; | 67 return false; |
61 } | 68 } |
62 | 69 |
63 /** Increment the reference count. Must be balanced by a call to unref(). | 70 /** Increment the reference count. Must be balanced by a call to unref(). |
64 */ | 71 */ |
65 void ref() const { | 72 void ref() const { |
66 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK | 73 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK |
67 // Android employs some special subclasses that enable the fRefCnt to | 74 // Android employs some special subclasses that enable the fRefCnt to |
68 // go to zero, but not below, prior to reusing the object. This breaks | 75 // go to zero, but not below, prior to reusing the object. This breaks |
69 // the use of unique() on such objects and as such should be removed | 76 // the use of unique() on such objects and as such should be removed |
70 // once the Android code is fixed. | 77 // once the Android code is fixed. |
71 SkASSERT(fRefCnt >= 0); | 78 SkASSERT(getRefCnt() >= 0); |
72 #else | 79 #else |
73 SkASSERT(fRefCnt > 0); | 80 SkASSERT(getRefCnt() > 0); |
74 #endif | 81 #endif |
75 (void)sk_atomic_fetch_add(&fRefCnt, +1, sk_memory_order_relaxed); // No
barrier required. | 82 // No barrier required. |
| 83 (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed); |
76 } | 84 } |
77 | 85 |
78 /** Decrement the reference count. If the reference count is 1 before the | 86 /** Decrement the reference count. If the reference count is 1 before the |
79 decrement, then delete the object. Note that if this is the case, then | 87 decrement, then delete the object. Note that if this is the case, then |
80 the object needs to have been allocated via new, and not on the stack. | 88 the object needs to have been allocated via new, and not on the stack. |
81 */ | 89 */ |
82 void unref() const { | 90 void unref() const { |
83 SkASSERT(fRefCnt > 0); | 91 SkASSERT(getRefCnt() > 0); |
84 // A release here acts in place of all releases we "should" have been do
ing in ref(). | 92 // A release here acts in place of all releases we "should" have been do
ing in ref(). |
85 if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) { | 93 if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { |
86 // Like unique(), the acquire is only needed on success, to make sur
e | 94 // Like unique(), the acquire is only needed on success, to make sur
e |
87 // code in internal_dispose() doesn't happen before the decrement. | 95 // code in internal_dispose() doesn't happen before the decrement. |
88 this->internal_dispose(); | 96 this->internal_dispose(); |
89 } | 97 } |
90 } | 98 } |
91 | 99 |
92 #ifdef SK_DEBUG | |
93 void validate() const { | |
94 SkASSERT(fRefCnt > 0); | |
95 } | |
96 #endif | |
97 | |
98 protected: | 100 protected: |
99 /** | 101 /** |
100 * Allow subclasses to call this if they've overridden internal_dispose | 102 * Allow subclasses to call this if they've overridden internal_dispose |
101 * so they can reset fRefCnt before the destructor is called. Should only | 103 * so they can reset fRefCnt before the destructor is called. Should only |
102 * be called right before calling through to inherited internal_dispose() | 104 * be called right before calling through to inherited internal_dispose() |
103 * or before calling the destructor. | 105 * or before calling the destructor. |
104 */ | 106 */ |
105 void internal_dispose_restore_refcnt_to_1() const { | 107 void internal_dispose_restore_refcnt_to_1() const { |
106 #ifdef SK_DEBUG | 108 #ifdef SK_DEBUG |
107 SkASSERT(0 == fRefCnt); | 109 SkASSERT(0 == getRefCnt()); |
108 fRefCnt = 1; | 110 fRefCnt.store(1, std::memory_order_relaxed); |
109 #endif | 111 #endif |
110 } | 112 } |
111 | 113 |
112 private: | 114 private: |
113 /** | 115 /** |
114 * Called when the ref count goes to 0. | 116 * Called when the ref count goes to 0. |
115 */ | 117 */ |
116 virtual void internal_dispose() const { | 118 virtual void internal_dispose() const { |
117 this->internal_dispose_restore_refcnt_to_1(); | 119 this->internal_dispose_restore_refcnt_to_1(); |
118 delete this; | 120 delete this; |
119 } | 121 } |
120 | 122 |
121 // The following friends are those which override internal_dispose() | 123 // The following friends are those which override internal_dispose() |
122 // and conditionally call SkRefCnt::internal_dispose(). | 124 // and conditionally call SkRefCnt::internal_dispose(). |
123 friend class SkWeakRefCnt; | 125 friend class SkWeakRefCnt; |
124 | 126 |
125 mutable int32_t fRefCnt; | 127 mutable std::atomic<int32_t> fRefCnt; |
126 | 128 |
127 typedef SkNoncopyable INHERITED; | 129 typedef SkNoncopyable INHERITED; |
128 }; | 130 }; |
129 | 131 |
130 #ifdef SK_REF_CNT_MIXIN_INCLUDE | 132 #ifdef SK_REF_CNT_MIXIN_INCLUDE |
131 // It is the responsibility of the following include to define the type SkRefCnt
. | 133 // It is the responsibility of the following include to define the type SkRefCnt
. |
132 // This SkRefCnt should normally derive from SkRefCntBase. | 134 // This SkRefCnt should normally derive from SkRefCntBase. |
133 #include SK_REF_CNT_MIXIN_INCLUDE | 135 #include SK_REF_CNT_MIXIN_INCLUDE |
134 #else | 136 #else |
135 class SK_API SkRefCnt : public SkRefCntBase { }; | 137 class SK_API SkRefCnt : public SkRefCntBase { }; |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
208 SkAutoUnref(SkRefCnt* obj) : SkAutoTUnref<SkRefCnt>(obj) {} | 210 SkAutoUnref(SkRefCnt* obj) : SkAutoTUnref<SkRefCnt>(obj) {} |
209 }; | 211 }; |
210 #define SkAutoUnref(...) SK_REQUIRE_LOCAL_VAR(SkAutoUnref) | 212 #define SkAutoUnref(...) SK_REQUIRE_LOCAL_VAR(SkAutoUnref) |
211 | 213 |
212 // This is a variant of SkRefCnt that's Not Virtual, so weighs 4 bytes instead o
f 8 or 16. | 214 // This is a variant of SkRefCnt that's Not Virtual, so weighs 4 bytes instead o
f 8 or 16. |
213 // There's only benefit to using this if the deriving class does not otherwise n
eed a vtable. | 215 // There's only benefit to using this if the deriving class does not otherwise n
eed a vtable. |
214 template <typename Derived> | 216 template <typename Derived> |
215 class SkNVRefCnt : SkNoncopyable { | 217 class SkNVRefCnt : SkNoncopyable { |
216 public: | 218 public: |
217 SkNVRefCnt() : fRefCnt(1) {} | 219 SkNVRefCnt() : fRefCnt(1) {} |
218 ~SkNVRefCnt() { SkASSERTF(1 == fRefCnt, "NVRefCnt was %d", fRefCnt); } | 220 ~SkNVRefCnt() { SkASSERTF(1 == getRefCnt(), "NVRefCnt was %d", getRefCnt());
} |
219 | 221 |
220 // Implementation is pretty much the same as SkRefCntBase. All required barr
iers are the same: | 222 // Implementation is pretty much the same as SkRefCntBase. All required barr
iers are the same: |
221 // - unique() needs acquire when it returns true, and no barrier if it ret
urns false; | 223 // - unique() needs acquire when it returns true, and no barrier if it ret
urns false; |
222 // - ref() doesn't need any barrier; | 224 // - ref() doesn't need any barrier; |
223 // - unref() needs a release barrier, and an acquire if it's going to call
delete. | 225 // - unref() needs a release barrier, and an acquire if it's going to call
delete. |
224 | 226 |
225 bool unique() const { return 1 == sk_atomic_load(&fRefCnt, sk_memory_order_a
cquire); } | 227 bool unique() const { return 1 == fRefCnt.load(std::memory_order_acquire); } |
226 void ref() const { (void)sk_atomic_fetch_add(&fRefCnt, +1, sk_memory_orde
r_relaxed); } | 228 void ref() const { (void)fRefCnt.fetch_add(+1, std::memory_order_relaxed); } |
227 void unref() const { | 229 void unref() const { |
228 if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) { | 230 if (1 == fRefCnt.fetch_add(-1, std::memory_order_acq_rel)) { |
229 SkDEBUGCODE(fRefCnt = 1;) // restore the 1 for our destructor's ass
ert | 231 // restore the 1 for our destructor's assert |
| 232 SkDEBUGCODE(fRefCnt.store(1, std::memory_order_relaxed)); |
230 delete (const Derived*)this; | 233 delete (const Derived*)this; |
231 } | 234 } |
232 } | 235 } |
233 void deref() const { this->unref(); } | 236 void deref() const { this->unref(); } |
234 | 237 |
235 private: | 238 private: |
236 mutable int32_t fRefCnt; | 239 mutable std::atomic<int32_t> fRefCnt; |
| 240 int32_t getRefCnt() const { |
| 241 return fRefCnt.load(std::memory_order_relaxed); |
| 242 } |
237 }; | 243 }; |
238 | 244 |
239 ////////////////////////////////////////////////////////////////////////////////
/////////////////// | 245 ////////////////////////////////////////////////////////////////////////////////
/////////////////// |
240 | 246 |
241 /** | 247 /** |
242 * Shared pointer class to wrap classes that support a ref()/unref() interface. | 248 * Shared pointer class to wrap classes that support a ref()/unref() interface. |
243 * | 249 * |
244 * This can be used for classes inheriting from SkRefCnt, but it also works for
other | 250 * This can be used for classes inheriting from SkRefCnt, but it also works for
other |
245 * classes that match the interface, but have different internal choices: e.g.
the hosted class | 251 * classes that match the interface, but have different internal choices: e.g.
the hosted class |
246 * may have its ref/unref be thread-safe, but that is not assumed/imposed by sk
_sp. | 252 * may have its ref/unref be thread-safe, but that is not assumed/imposed by sk
_sp. |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
447 * | 453 * |
448 * This function may be helpful while we convert callers from ptr-based to sk_s
p-based parameters. | 454 * This function may be helpful while we convert callers from ptr-based to sk_s
p-based parameters. |
449 */ | 455 */ |
450 template <typename T> sk_sp<T> sk_ref_sp(T* obj) { | 456 template <typename T> sk_sp<T> sk_ref_sp(T* obj) { |
451 return sk_sp<T>(SkSafeRef(obj)); | 457 return sk_sp<T>(SkSafeRef(obj)); |
452 } | 458 } |
453 | 459 |
454 #endif | 460 #endif |
455 | 461 |
456 #endif | 462 #endif |
OLD | NEW |