Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(46)

Side by Side Diff: include/core/SkLazyPtr.h

Issue 908943002: Port SkLazyPtr to new SkAtomics.h (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: includes Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « include/core/SkAtomics.h ('k') | include/core/SkPixelRef.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
53 53
54 #define SK_DECLARE_STATIC_LAZY_PTR_ARRAY(T, name, N, ...) \ 54 #define SK_DECLARE_STATIC_LAZY_PTR_ARRAY(T, name, N, ...) \
55 namespace {} static Private::SkStaticLazyPtrArray<T, N, ##__VA_ARGS__> name 55 namespace {} static Private::SkStaticLazyPtrArray<T, N, ##__VA_ARGS__> name
56 56
57 // namespace {} forces these macros to only be legal in global scopes. Chrome h as thread-safety 57 // namespace {} forces these macros to only be legal in global scopes. Chrome h as thread-safety
58 // problems with them in function-local statics because it uses -fno-threadsafe- statics, and even 58 // problems with them in function-local statics because it uses -fno-threadsafe- statics, and even
59 // in builds with threadsafe statics, those threadsafe statics are just unnecess ary overhead. 59 // in builds with threadsafe statics, those threadsafe statics are just unnecess ary overhead.
60 60
61 // Everything below here is private implementation details. Don't touch, don't even look. 61 // Everything below here is private implementation details. Don't touch, don't even look.
62 62
63 #include "SkDynamicAnnotations.h" 63 #include "SkAtomics.h"
64 #include "SkThread.h"
65 #include "SkThreadPriv.h"
66 64
67 // See FIXME below. 65 // See FIXME below.
68 class SkFontConfigInterfaceDirect; 66 class SkFontConfigInterfaceDirect;
69 67
70 namespace Private { 68 namespace Private {
71 69
72 // Set *dst to ptr if *dst is NULL. Returns value of *dst, destroying ptr if no t swapped in. 70 // Set *dst to ptr if *dst is NULL. Returns value of *dst, destroying ptr if no t swapped in.
73 // Issues the same memory barriers as sk_atomic_cas: acquire on failure, release on success. 71 // Issues acquire memory barrier on failure, release on success.
74 template <typename P, void (*Destroy)(P)> 72 template <typename P, void (*Destroy)(P)>
75 static P try_cas(void** dst, P ptr) { 73 static P try_cas(P* dst, P ptr) {
76 P prev = (P)sk_atomic_cas(dst, NULL, ptr); 74 P prev = NULL;
77 75 if (sk_atomic_compare_exchange(dst, &prev, ptr,
78 if (prev) { 76 sk_memory_order_release/*on success*/,
79 // We need an acquire barrier before returning prev, which sk_atomic_cas provided. 77 sk_memory_order_acquire/*on failure*/)) {
78 // We need a release barrier before returning ptr. The compare_exchange provides it.
79 SkASSERT(!prev);
80 return ptr;
81 } else {
80 Destroy(ptr); 82 Destroy(ptr);
83 // We need an acquire barrier before returning prev. The compare_exchan ge provided it.
84 SkASSERT(prev);
81 return prev; 85 return prev;
82 } else {
83 // We need a release barrier before returning ptr, which sk_atomic_cas p rovided.
84 return ptr;
85 } 86 }
86 } 87 }
87 88
88 template <typename T> T* sk_new() { return SkNEW(T); } 89 template <typename T> T* sk_new() { return SkNEW(T); }
89 template <typename T> void sk_delete(T* ptr) { SkDELETE(ptr); } 90 template <typename T> void sk_delete(T* ptr) { SkDELETE(ptr); }
90 91
91 // We're basing these implementations here on this article: 92 // We're basing these implementations here on this article:
92 // http://preshing.com/20140709/the-purpose-of-memory_order_consume-in-cpp11/ 93 // http://preshing.com/20140709/the-purpose-of-memory_order_consume-in-cpp11/
93 // 94 //
94 // Because the users of SkLazyPtr and SkLazyPtrArray will read the pointers 95 // 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 // _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 // 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-consumes memory pairing rather than the more general write-releases /
98 // reader-acquires convention. 99 // reader-acquires convention.
99 // 100 //
100 // This is nice, because a sk_consume_load is free on all our platforms: x86, 101 // This is nice, because a 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 // ARM, MIPS. In contrast, an acquire load issues a memory barrier on non-x86.
103
104 template <typename T>
105 T consume_load(T* ptr) {
106 #if DYNAMIC_ANNOTATIONS_ENABLED
107 // TSAN gets anxious if we don't tell it what we're actually doing, a consum e load.
108 return sk_atomic_load(ptr, sk_memory_order_consume);
109 #else
110 // All current compilers blindly upgrade consume memory order to acquire mem ory order.
111 // For our purposes, though, no memory barrier is required, so we lie and us e relaxed.
112 return sk_atomic_load(ptr, sk_memory_order_relaxed);
113 #endif
114 }
102 115
103 // This has no constructor and must be zero-initalized (the macro above does thi s). 116 // This has no constructor and must be zero-initalized (the macro above does thi s).
104 template <typename T, T* (*Create)() = sk_new<T>, void (*Destroy)(T*) = sk_delet e<T> > 117 template <typename T, T* (*Create)() = sk_new<T>, void (*Destroy)(T*) = sk_delet e<T> >
105 class SkStaticLazyPtr { 118 class SkStaticLazyPtr {
106 public: 119 public:
107 T* get() { 120 T* get() {
108 // If fPtr has already been filled, we need a consume barrier when loadi ng it. 121 // If fPtr has already been filled, we need a consume barrier when loadi ng it.
109 // If not, we need a release barrier when setting it. try_cas will do t hat. 122 // If not, we need a release barrier when setting it. try_cas will do t hat.
110 T* ptr = (T*)sk_consume_load(&fPtr); 123 T* ptr = consume_load(&fPtr);
111 return ptr ? ptr : try_cas<T*, Destroy>(&fPtr, Create()); 124 return ptr ? ptr : try_cas<T*, Destroy>(&fPtr, Create());
112 } 125 }
113 126
114 private: 127 private:
115 void* fPtr; 128 T* fPtr;
116 }; 129 };
117 130
118 template <typename T> T* sk_new_arg(int i) { return SkNEW_ARGS(T, (i)); } 131 template <typename T> T* sk_new_arg(int i) { return SkNEW_ARGS(T, (i)); }
119 132
120 // This has no constructor and must be zero-initalized (the macro above does thi s). 133 // This has no constructor and must be zero-initalized (the macro above does thi s).
121 template <typename T, int N, T* (*Create)(int) = sk_new_arg<T>, void (*Destroy)( T*) = sk_delete<T> > 134 template <typename T, int N, T* (*Create)(int) = sk_new_arg<T>, void (*Destroy)( T*) = sk_delete<T> >
122 class SkStaticLazyPtrArray { 135 class SkStaticLazyPtrArray {
123 public: 136 public:
124 T* operator[](int i) { 137 T* operator[](int i) {
125 SkASSERT(i >= 0 && i < N); 138 SkASSERT(i >= 0 && i < N);
126 // If fPtr has already been filled, we need an consume barrier when load ing it. 139 // If fPtr has already been filled, we need an consume barrier when load ing it.
127 // If not, we need a release barrier when setting it. try_cas will do t hat. 140 // If not, we need a release barrier when setting it. try_cas will do t hat.
128 T* ptr = (T*)sk_consume_load(&fArray[i]); 141 T* ptr = consume_load(&fArray[i]);
129 return ptr ? ptr : try_cas<T*, Destroy>(&fArray[i], Create(i)); 142 return ptr ? ptr : try_cas<T*, Destroy>(&fArray[i], Create(i));
130 } 143 }
131 144
132 private: 145 private:
133 void* fArray[N]; 146 T* fArray[N];
134 }; 147 };
135 148
136 } // namespace Private 149 } // namespace Private
137 150
138 // This version is suitable for use as a class member. 151 // This version is suitable for use as a class member.
139 // It's much the same as above except: 152 // It's much the same as above except:
140 // - it has a constructor to zero itself; 153 // - it has a constructor to zero itself;
141 // - it has a destructor to clean up; 154 // - it has a destructor to clean up;
142 // - get() calls SkNew(T) to create the pointer; 155 // - get() calls SkNew(T) to create the pointer;
143 // - get(functor) calls functor to create the pointer. 156 // - get(functor) calls functor to create the pointer.
144 template <typename T, void (*Destroy)(T*) = Private::sk_delete<T> > 157 template <typename T, void (*Destroy)(T*) = Private::sk_delete<T> >
145 class SkLazyPtr : SkNoncopyable { 158 class SkLazyPtr : SkNoncopyable {
146 public: 159 public:
147 SkLazyPtr() : fPtr(NULL) {} 160 SkLazyPtr() : fPtr(NULL) {}
148 ~SkLazyPtr() { if (fPtr) { Destroy((T*)fPtr); } } 161 ~SkLazyPtr() { if (fPtr) { Destroy((T*)fPtr); } }
149 162
150 T* get() const { 163 T* get() const {
151 T* ptr = (T*)sk_consume_load(&fPtr); 164 T* ptr = Private::consume_load(&fPtr);
152 return ptr ? ptr : Private::try_cas<T*, Destroy>(&fPtr, SkNEW(T)); 165 return ptr ? ptr : Private::try_cas<T*, Destroy>(&fPtr, SkNEW(T));
153 } 166 }
154 167
155 template <typename Create> 168 template <typename Create>
156 T* get(const Create& create) const { 169 T* get(const Create& create) const {
157 T* ptr = (T*)sk_consume_load(&fPtr); 170 T* ptr = Private::consume_load(&fPtr);
158 return ptr ? ptr : Private::try_cas<T*, Destroy>(&fPtr, create()); 171 return ptr ? ptr : Private::try_cas<T*, Destroy>(&fPtr, create());
159 } 172 }
160 173
161 private: 174 private:
162 mutable void* fPtr; 175 mutable T* fPtr;
163 }; 176 };
164 177
165 178
166 #endif//SkLazyPtr_DEFINED 179 #endif//SkLazyPtr_DEFINED
OLDNEW
« no previous file with comments | « include/core/SkAtomics.h ('k') | include/core/SkPixelRef.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698