OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2006 The Android Open Source Project | 3 * Copyright 2006 The Android Open Source Project |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 | 9 |
10 #ifndef SkRefCnt_DEFINED | 10 #ifndef SkRefCnt_DEFINED |
11 #define SkRefCnt_DEFINED | 11 #define SkRefCnt_DEFINED |
12 | 12 |
13 #include "SkDynamicAnnotations.h" | 13 #include "SkAtomics.h" |
14 #include "SkThread.h" | |
15 #include "SkInstCnt.h" | 14 #include "SkInstCnt.h" |
16 #include "SkTemplates.h" | 15 #include "SkTemplates.h" |
17 | 16 |
18 /** \class SkRefCntBase | 17 /** \class SkRefCntBase |
19 | 18 |
20 SkRefCntBase is the base class for objects that may be shared by multiple | 19 SkRefCntBase is the base class for objects that may be shared by multiple |
21 objects. When an existing owner wants to share a reference, it calls ref(). | 20 objects. When an existing owner wants to share a reference, it calls ref(). |
22 When an owner wants to release its reference, it calls unref(). When the | 21 When an owner wants to release its reference, it calls unref(). When the |
23 shared object's reference count goes to zero as the result of an unref() | 22 shared object's reference count goes to zero as the result of an unref() |
24 call, its (virtual) destructor is called. It is an error for the | 23 call, its (virtual) destructor is called. It is an error for the |
(...skipping 19 matching lines...) Expand all Loading... |
44 | 43 |
45 #ifdef SK_DEBUG | 44 #ifdef SK_DEBUG |
46 /** Return the reference count. Use only for debugging. */ | 45 /** Return the reference count. Use only for debugging. */ |
47 int32_t getRefCnt() const { return fRefCnt; } | 46 int32_t getRefCnt() const { return fRefCnt; } |
48 #endif | 47 #endif |
49 | 48 |
50 /** May return true if the caller is the only owner. | 49 /** May return true if the caller is the only owner. |
51 * Ensures that all previous owner's actions are complete. | 50 * Ensures that all previous owner's actions are complete. |
52 */ | 51 */ |
53 bool unique() const { | 52 bool unique() const { |
54 // We believe we're reading fRefCnt in a safe way here, so we stifle the
TSAN warning about | 53 if (1 == sk_atomic_load(&fRefCnt, sk_memory_order_acquire)) { |
55 // an unproctected read. Generally, don't read fRefCnt, and don't stifl
e this warning. | 54 // The acquire barrier is only really needed if we return true. It |
56 bool const unique = (1 == sk_acquire_load(&fRefCnt)); | 55 // prevents code conditioned on the result of unique() from running |
57 if (unique) { | 56 // until previous owners are all totally done calling unref(). |
58 // Acquire barrier (L/SL), if not provided by load of fRefCnt. | 57 return true; |
59 // Prevents user's 'unique' code from happening before decrements. | |
60 //TODO: issue the barrier only when unique is true | |
61 } | 58 } |
62 return unique; | 59 return false; |
63 } | 60 } |
64 | 61 |
65 /** Increment the reference count. Must be balanced by a call to unref(). | 62 /** Increment the reference count. Must be balanced by a call to unref(). |
66 */ | 63 */ |
67 void ref() const { | 64 void ref() const { |
68 SkASSERT(fRefCnt > 0); | 65 SkASSERT(fRefCnt > 0); |
69 sk_atomic_inc(&fRefCnt); // No barrier required. | 66 (void)sk_atomic_fetch_add(&fRefCnt, +1, sk_memory_order_relaxed); // No
barrier required. |
70 } | 67 } |
71 | 68 |
72 /** Decrement the reference count. If the reference count is 1 before the | 69 /** Decrement the reference count. If the reference count is 1 before the |
73 decrement, then delete the object. Note that if this is the case, then | 70 decrement, then delete the object. Note that if this is the case, then |
74 the object needs to have been allocated via new, and not on the stack. | 71 the object needs to have been allocated via new, and not on the stack. |
75 */ | 72 */ |
76 void unref() const { | 73 void unref() const { |
77 SkASSERT(fRefCnt > 0); | 74 SkASSERT(fRefCnt > 0); |
78 // Release barrier (SL/S), if not provided below. | 75 // A release here acts in place of all releases we "should" have been do
ing in ref(). |
79 if (sk_atomic_dec(&fRefCnt) == 1) { | 76 if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) { |
80 // Acquire barrier (L/SL), if not provided above. | 77 // Like unique(), the acquire is only needed on success, to make sur
e |
81 // Prevents code in dispose from happening before the decrement. | 78 // code in internal_dispose() doesn't happen before the decrement. |
82 sk_membar_acquire__after_atomic_dec(); | 79 this->internal_dispose(); |
83 internal_dispose(); | |
84 } | 80 } |
85 } | 81 } |
86 | 82 |
87 #ifdef SK_DEBUG | 83 #ifdef SK_DEBUG |
88 void validate() const { | 84 void validate() const { |
89 SkASSERT(fRefCnt > 0); | 85 SkASSERT(fRefCnt > 0); |
90 } | 86 } |
91 #endif | 87 #endif |
92 | 88 |
93 protected: | 89 protected: |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
255 class SkNVRefCnt : SkNoncopyable { | 251 class SkNVRefCnt : SkNoncopyable { |
256 public: | 252 public: |
257 SkNVRefCnt() : fRefCnt(1) {} | 253 SkNVRefCnt() : fRefCnt(1) {} |
258 ~SkNVRefCnt() { SkASSERTF(1 == fRefCnt, "NVRefCnt was %d", fRefCnt); } | 254 ~SkNVRefCnt() { SkASSERTF(1 == fRefCnt, "NVRefCnt was %d", fRefCnt); } |
259 | 255 |
260 // Implementation is pretty much the same as SkRefCntBase. All required barr
iers are the same: | 256 // Implementation is pretty much the same as SkRefCntBase. All required barr
iers are the same: |
261 // - unique() needs acquire when it returns true, and no barrier if it ret
urns false; | 257 // - unique() needs acquire when it returns true, and no barrier if it ret
urns false; |
262 // - ref() doesn't need any barrier; | 258 // - ref() doesn't need any barrier; |
263 // - unref() needs a release barrier, and an acquire if it's going to call
delete. | 259 // - unref() needs a release barrier, and an acquire if it's going to call
delete. |
264 | 260 |
265 bool unique() const { return 1 == sk_acquire_load(&fRefCnt); } | 261 bool unique() const { return 1 == sk_atomic_load(&fRefCnt, sk_memory_order_a
cquire); } |
266 void ref() const { sk_atomic_inc(&fRefCnt); } | 262 void ref() const { (void)sk_atomic_fetch_add(&fRefCnt, +1, sk_memory_orde
r_relaxed); } |
267 void unref() const { | 263 void unref() const { |
268 int32_t prevValue = sk_atomic_dec(&fRefCnt); | 264 if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) { |
269 SkASSERT(prevValue >= 1); | |
270 if (1 == prevValue) { | |
271 SkDEBUGCODE(fRefCnt = 1;) // restore the 1 for our destructor's as
sert | 265 SkDEBUGCODE(fRefCnt = 1;) // restore the 1 for our destructor's as
sert |
272 SkDELETE((const Derived*)this); | 266 SkDELETE((const Derived*)this); |
273 } | 267 } |
274 } | 268 } |
275 void deref() const { this->unref(); } // Chrome prefers to call deref(). | 269 void deref() const { this->unref(); } |
276 | 270 |
277 private: | 271 private: |
278 mutable int32_t fRefCnt; | 272 mutable int32_t fRefCnt; |
279 }; | 273 }; |
280 | 274 |
281 #endif | 275 #endif |
OLD | NEW |