OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 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 SkLazyPtr_DEFINED | 8 #ifndef SkLazyPtr_DEFINED |
9 #define SkLazyPtr_DEFINED | 9 #define SkLazyPtr_DEFINED |
10 | 10 |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
81 return prev; | 81 return prev; |
82 } else { | 82 } else { |
83 // We need a release barrier before returning ptr, which sk_atomic_cas p
rovided. | 83 // We need a release barrier before returning ptr, which sk_atomic_cas p
rovided. |
84 return ptr; | 84 return ptr; |
85 } | 85 } |
86 } | 86 } |
87 | 87 |
88 template <typename T> T* sk_new() { return SkNEW(T); } | 88 template <typename T> T* sk_new() { return SkNEW(T); } |
89 template <typename T> void sk_delete(T* ptr) { SkDELETE(ptr); } | 89 template <typename T> void sk_delete(T* ptr) { SkDELETE(ptr); } |
90 | 90 |
| 91 // We're basing these implementations here on this article: |
| 92 // http://preshing.com/20140709/the-purpose-of-memory_order_consume-in-cpp11/ |
| 93 // |
| 94 // Because the users of SkLazyPtr and SkLazyPtrArray will read the pointers |
| 95 // _through_ our atomically set pointer, there is a data dependency between our |
| 96 // atomic and the guarded data, and so we only need writer-releases / |
| 97 // reader-consumes memory pairing rather than the more general write-releases / |
| 98 // reader-acquires convention. |
| 99 // |
| 100 // This is nice, because a sk_consume_load is free on all our platforms: x86, |
| 101 // ARM, MIPS. In contrast, sk_acquire_load issues a memory barrier on non-x86. |
| 102 |
91 // This has no constructor and must be zero-initalized (the macro above does thi
s). | 103 // This has no constructor and must be zero-initalized (the macro above does thi
s). |
92 template <typename T, T* (*Create)() = sk_new<T>, void (*Destroy)(T*) = sk_delet
e<T> > | 104 template <typename T, T* (*Create)() = sk_new<T>, void (*Destroy)(T*) = sk_delet
e<T> > |
93 class SkLazyPtr { | 105 class SkLazyPtr { |
94 public: | 106 public: |
95 T* get() { | 107 T* get() { |
96 // If fPtr has already been filled, we need an acquire barrier when load
ing it. | 108 // If fPtr has already been filled, we need a consume barrier when loadi
ng it. |
97 // If not, we need a release barrier when setting it. try_cas will do t
hat. | 109 // If not, we need a release barrier when setting it. try_cas will do t
hat. |
98 T* ptr = (T*)sk_acquire_load(&fPtr); | 110 T* ptr = (T*)sk_consume_load(&fPtr); |
99 return ptr ? ptr : try_cas<T*, Destroy>(&fPtr, Create()); | 111 return ptr ? ptr : try_cas<T*, Destroy>(&fPtr, Create()); |
100 } | 112 } |
101 | 113 |
102 #ifdef SK_DEVELOPER | 114 #ifdef SK_DEVELOPER |
103 // FIXME: We know we leak refs on some classes. For now, let them leak. | 115 // FIXME: We know we leak refs on some classes. For now, let them leak. |
104 void cleanup(SkFontConfigInterfaceDirect*) {} | 116 void cleanup(SkFontConfigInterfaceDirect*) {} |
105 template <typename U> void cleanup(U* ptr) { Destroy(ptr); } | 117 template <typename U> void cleanup(U* ptr) { Destroy(ptr); } |
106 | 118 |
107 ~SkLazyPtr() { | 119 ~SkLazyPtr() { |
108 this->cleanup((T*)fPtr); | 120 this->cleanup((T*)fPtr); |
109 fPtr = NULL; | 121 fPtr = NULL; |
110 } | 122 } |
111 #endif | 123 #endif |
112 | 124 |
113 private: | 125 private: |
114 void* fPtr; | 126 void* fPtr; |
115 }; | 127 }; |
116 | 128 |
117 template <typename T> T* sk_new_arg(int i) { return SkNEW_ARGS(T, (i)); } | 129 template <typename T> T* sk_new_arg(int i) { return SkNEW_ARGS(T, (i)); } |
118 | 130 |
119 // This has no constructor and must be zero-initalized (the macro above does thi
s). | 131 // This has no constructor and must be zero-initalized (the macro above does thi
s). |
120 template <typename T, int N, T* (*Create)(int) = sk_new_arg<T>, void (*Destroy)(
T*) = sk_delete<T> > | 132 template <typename T, int N, T* (*Create)(int) = sk_new_arg<T>, void (*Destroy)(
T*) = sk_delete<T> > |
121 class SkLazyPtrArray { | 133 class SkLazyPtrArray { |
122 public: | 134 public: |
123 T* operator[](int i) { | 135 T* operator[](int i) { |
124 SkASSERT(i >= 0 && i < N); | 136 SkASSERT(i >= 0 && i < N); |
125 // If fPtr has already been filled, we need an acquire barrier when load
ing it. | 137 // If fPtr has already been filled, we need an consume barrier when load
ing it. |
126 // If not, we need a release barrier when setting it. try_cas will do t
hat. | 138 // If not, we need a release barrier when setting it. try_cas will do t
hat. |
127 T* ptr = (T*)sk_acquire_load(&fArray[i]); | 139 T* ptr = (T*)sk_consume_load(&fArray[i]); |
128 return ptr ? ptr : try_cas<T*, Destroy>(&fArray[i], Create(i)); | 140 return ptr ? ptr : try_cas<T*, Destroy>(&fArray[i], Create(i)); |
129 } | 141 } |
130 | 142 |
131 #ifdef SK_DEVELOPER | 143 #ifdef SK_DEVELOPER |
132 ~SkLazyPtrArray() { | 144 ~SkLazyPtrArray() { |
133 for (int i = 0; i < N; i++) { | 145 for (int i = 0; i < N; i++) { |
134 Destroy((T*)fArray[i]); | 146 Destroy((T*)fArray[i]); |
135 fArray[i] = NULL; | 147 fArray[i] = NULL; |
136 } | 148 } |
137 } | 149 } |
138 #endif | 150 #endif |
139 | 151 |
140 private: | 152 private: |
141 void* fArray[N]; | 153 void* fArray[N]; |
142 }; | 154 }; |
143 | 155 |
144 } // namespace Private | 156 } // namespace Private |
145 | 157 |
146 #endif//SkLazyPtr_DEFINED | 158 #endif//SkLazyPtr_DEFINED |
OLD | NEW |