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 |