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_relaxed)) { |
55 // an unproctected read. Generally, don't read fRefCnt, and don't stifl e this warning. | 54 // Prevents code conditioned on the result of unique() from running |
56 bool const unique = (1 == sk_acquire_load(&fRefCnt)); | 55 // until previous owners are all totally done calling unref(). |
57 if (unique) { | 56 sk_memory_barrier(sk_memory_order_acquire); |
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 // An acquire makes sure code in internal_dispose() doen't happen before the decrement. |
bungeman-skia
2015/02/03 17:14:47
nit: doen't?
I liked the way it was clear before
mtklein
2015/02/03 17:27:57
Done.
| |
80 // Acquire barrier (L/SL), if not provided above. | 77 if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) { |
81 // Prevents code in dispose from happening before the decrement. | 78 this->internal_dispose(); |
82 sk_membar_acquire__after_atomic_dec(); | |
83 internal_dispose(); | |
84 } | 79 } |
85 } | 80 } |
86 | 81 |
87 #ifdef SK_DEBUG | 82 #ifdef SK_DEBUG |
88 void validate() const { | 83 void validate() const { |
89 SkASSERT(fRefCnt > 0); | 84 SkASSERT(fRefCnt > 0); |
90 } | 85 } |
91 #endif | 86 #endif |
92 | 87 |
93 protected: | 88 protected: |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
255 class SkNVRefCnt : SkNoncopyable { | 250 class SkNVRefCnt : SkNoncopyable { |
256 public: | 251 public: |
257 SkNVRefCnt() : fRefCnt(1) {} | 252 SkNVRefCnt() : fRefCnt(1) {} |
258 ~SkNVRefCnt() { SkASSERTF(1 == fRefCnt, "NVRefCnt was %d", fRefCnt); } | 253 ~SkNVRefCnt() { SkASSERTF(1 == fRefCnt, "NVRefCnt was %d", fRefCnt); } |
259 | 254 |
260 // Implementation is pretty much the same as SkRefCntBase. All required barr iers are the same: | 255 // 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; | 256 // - unique() needs acquire when it returns true, and no barrier if it ret urns false; |
262 // - ref() doesn't need any barrier; | 257 // - ref() doesn't need any barrier; |
263 // - unref() needs a release barrier, and an acquire if it's going to call delete. | 258 // - unref() needs a release barrier, and an acquire if it's going to call delete. |
264 | 259 |
265 bool unique() const { return 1 == sk_acquire_load(&fRefCnt); } | 260 bool unique() const { |
266 void ref() const { sk_atomic_inc(&fRefCnt); } | 261 if (1 == sk_atomic_load(&fRefCnt, sk_memory_order_relaxed)) { |
267 void unref() const { | 262 sk_memory_barrier(sk_memory_order_acquire); |
268 int32_t prevValue = sk_atomic_dec(&fRefCnt); | 263 return true; |
269 SkASSERT(prevValue >= 1); | 264 } |
270 if (1 == prevValue) { | 265 return false; |
266 } | |
267 void ref() const { (void)sk_atomic_fetch_add(&fRefCnt, +1, sk_memory_order _relaxed); } | |
268 void unref() const { | |
269 if (1 == sk_atomic_fetch_add(&fRefCnt, -1, sk_memory_order_acq_rel)) { | |
271 SkDEBUGCODE(fRefCnt = 1;) // restore the 1 for our destructor's as sert | 270 SkDEBUGCODE(fRefCnt = 1;) // restore the 1 for our destructor's as sert |
272 SkDELETE((const Derived*)this); | 271 SkDELETE((const Derived*)this); |
273 } | 272 } |
274 } | 273 } |
275 void deref() const { this->unref(); } // Chrome prefers to call deref(). | 274 void deref() const { this->unref(); } // Chrome prefers to call deref(). |
bungeman-skia
2015/02/03 17:14:47
I know it has nothing to do with this CL, but I st
mtklein
2015/02/03 17:27:57
Done.
| |
276 | 275 |
277 private: | 276 private: |
278 mutable int32_t fRefCnt; | 277 mutable int32_t fRefCnt; |
279 }; | 278 }; |
280 | 279 |
281 #endif | 280 #endif |
OLD | NEW |