| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
| 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 SkOnce_DEFINED | 8 #ifndef SkOnce_DEFINED |
| 9 #define SkOnce_DEFINED | 9 #define SkOnce_DEFINED |
| 10 | 10 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 47 // ---------------------- Implementation details below here. -----------------
------------ | 47 // ---------------------- Implementation details below here. -----------------
------------ |
| 48 | 48 |
| 49 // This is POD and must be zero-initialized. | 49 // This is POD and must be zero-initialized. |
| 50 struct SkSpinlock { | 50 struct SkSpinlock { |
| 51 void acquire() { | 51 void acquire() { |
| 52 SkASSERT(shouldBeZero == 0); | 52 SkASSERT(shouldBeZero == 0); |
| 53 // No memory barrier needed, but sk_atomic_cas gives us at least release
anyway. | 53 // No memory barrier needed, but sk_atomic_cas gives us at least release
anyway. |
| 54 while (!sk_atomic_cas(&thisIsPrivate, 0, 1)) { | 54 while (!sk_atomic_cas(&thisIsPrivate, 0, 1)) { |
| 55 // spin | 55 // spin |
| 56 } | 56 } |
| 57 SK_ANNOTATE_RWLOCK_ACQUIRED(this, true); |
| 57 } | 58 } |
| 58 | 59 |
| 59 void release() { | 60 void release() { |
| 60 SkASSERT(shouldBeZero == 0); | 61 SkASSERT(shouldBeZero == 0); |
| 62 SK_ANNOTATE_RWLOCK_RELEASED(this, true); |
| 61 // This requires a release memory barrier before storing, which sk_atomi
c_cas guarantees. | 63 // This requires a release memory barrier before storing, which sk_atomi
c_cas guarantees. |
| 62 SkAssertResult(sk_atomic_cas(&thisIsPrivate, 1, 0)); | 64 SkAssertResult(sk_atomic_cas(&thisIsPrivate, 1, 0)); |
| 63 } | 65 } |
| 64 | 66 |
| 65 int32_t thisIsPrivate; | 67 int32_t thisIsPrivate; |
| 66 SkDEBUGCODE(int32_t shouldBeZero;) | 68 SkDEBUGCODE(int32_t shouldBeZero;) |
| 67 }; | 69 }; |
| 68 | 70 |
| 69 struct SkOnceFlag { | 71 struct SkOnceFlag { |
| 70 bool done; | 72 bool done; |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 138 // done before here---in particular, those done by calling f(arg)---are
observable | 140 // done before here---in particular, those done by calling f(arg)---are
observable |
| 139 // before the writes after the line, *done = true. | 141 // before the writes after the line, *done = true. |
| 140 // | 142 // |
| 141 // In version control terms this is like saying, "check in the work up | 143 // In version control terms this is like saying, "check in the work up |
| 142 // to and including f(arg), then check in *done=true as a subsequent cha
nge". | 144 // to and including f(arg), then check in *done=true as a subsequent cha
nge". |
| 143 // | 145 // |
| 144 // We'll use this in the fast path to make sure f(arg)'s effects are | 146 // We'll use this in the fast path to make sure f(arg)'s effects are |
| 145 // observable whenever we observe *done == true. | 147 // observable whenever we observe *done == true. |
| 146 release_barrier(); | 148 release_barrier(); |
| 147 *done = true; | 149 *done = true; |
| 150 SK_ANNOTATE_HAPPENS_BEFORE(done); |
| 148 } | 151 } |
| 149 } | 152 } |
| 150 | 153 |
| 151 // This is our fast path, called all the time. We do really want it to be inlin
ed. | 154 // This is our fast path, called all the time. We do really want it to be inlin
ed. |
| 152 template <typename Lock, typename Func, typename Arg> | 155 template <typename Lock, typename Func, typename Arg> |
| 153 inline void SkOnce(bool* done, Lock* lock, Func f, Arg arg, void(*atExit)()) { | 156 inline void SkOnce(bool* done, Lock* lock, Func f, Arg arg, void(*atExit)()) { |
| 154 if (!SK_ANNOTATE_UNPROTECTED_READ(*done)) { | 157 if (!SK_ANNOTATE_UNPROTECTED_READ(*done)) { |
| 155 sk_once_slow(done, lock, f, arg, atExit); | 158 sk_once_slow(done, lock, f, arg, atExit); |
| 156 } | 159 } |
| 157 // Also known as a load-load/load-store barrier, this acquire barrier makes | 160 // Also known as a load-load/load-store barrier, this acquire barrier makes |
| 158 // sure that anything we read from memory---in particular, memory written by | 161 // sure that anything we read from memory---in particular, memory written by |
| 159 // calling f(arg)---is at least as current as the value we read from once->d
one. | 162 // calling f(arg)---is at least as current as the value we read from once->d
one. |
| 160 // | 163 // |
| 161 // In version control terms, this is a lot like saying "sync up to the | 164 // In version control terms, this is a lot like saying "sync up to the |
| 162 // commit where we wrote once->done = true". | 165 // commit where we wrote once->done = true". |
| 163 // | 166 // |
| 164 // The release barrier in sk_once_slow guaranteed that once->done = true | 167 // The release barrier in sk_once_slow guaranteed that once->done = true |
| 165 // happens after f(arg), so by syncing to once->done = true here we're | 168 // happens after f(arg), so by syncing to once->done = true here we're |
| 166 // forcing ourselves to also wait until the effects of f(arg) are readble. | 169 // forcing ourselves to also wait until the effects of f(arg) are readble. |
| 167 acquire_barrier(); | 170 acquire_barrier(); |
| 171 SK_ANNOTATE_HAPPENS_AFTER(done); |
| 168 } | 172 } |
| 169 | 173 |
| 170 template <typename Func, typename Arg> | 174 template <typename Func, typename Arg> |
| 171 inline void SkOnce(SkOnceFlag* once, Func f, Arg arg, void(*atExit)()) { | 175 inline void SkOnce(SkOnceFlag* once, Func f, Arg arg, void(*atExit)()) { |
| 172 return SkOnce(&once->done, &once->lock, f, arg, atExit); | 176 return SkOnce(&once->done, &once->lock, f, arg, atExit); |
| 173 } | 177 } |
| 174 | 178 |
| 175 #undef SK_ANNOTATE_BENIGN_RACE | 179 #undef SK_ANNOTATE_BENIGN_RACE |
| 176 | 180 |
| 177 #endif // SkOnce_DEFINED | 181 #endif // SkOnce_DEFINED |
| OLD | NEW |