| 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 |