| Index: include/core/SkLazyPtr.h
|
| diff --git a/include/core/SkLazyPtr.h b/include/core/SkLazyPtr.h
|
| index 896dfbf88d762570545a9e5a7715aeeb795313e9..fb2e43e874681c1e993992ae891bae40561930a4 100644
|
| --- a/include/core/SkLazyPtr.h
|
| +++ b/include/core/SkLazyPtr.h
|
| @@ -60,9 +60,7 @@
|
|
|
| // Everything below here is private implementation details. Don't touch, don't even look.
|
|
|
| -#include "SkDynamicAnnotations.h"
|
| -#include "SkThread.h"
|
| -#include "SkThreadPriv.h"
|
| +#include "SkAtomics.h"
|
|
|
| // See FIXME below.
|
| class SkFontConfigInterfaceDirect;
|
| @@ -70,18 +68,21 @@ class SkFontConfigInterfaceDirect;
|
| namespace Private {
|
|
|
| // Set *dst to ptr if *dst is NULL. Returns value of *dst, destroying ptr if not swapped in.
|
| -// Issues the same memory barriers as sk_atomic_cas: acquire on failure, release on success.
|
| +// Issues acquire memory barrier on failure, release on success.
|
| template <typename P, void (*Destroy)(P)>
|
| -static P try_cas(void** dst, P ptr) {
|
| - P prev = (P)sk_atomic_cas(dst, NULL, ptr);
|
| -
|
| - if (prev) {
|
| - // We need an acquire barrier before returning prev, which sk_atomic_cas provided.
|
| +static P try_cas(P* dst, P ptr) {
|
| + P prev = NULL;
|
| + if (sk_atomic_compare_exchange(dst, &prev, ptr,
|
| + sk_memory_order_release/*on success*/,
|
| + sk_memory_order_acquire/*on failure*/)) {
|
| + // We need a release barrier before returning ptr. The compare_exchange provides it.
|
| + SkASSERT(!prev);
|
| + return ptr;
|
| + } else {
|
| Destroy(ptr);
|
| + // We need an acquire barrier before returning prev. The compare_exchange provided it.
|
| + SkASSERT(prev);
|
| return prev;
|
| - } else {
|
| - // We need a release barrier before returning ptr, which sk_atomic_cas provided.
|
| - return ptr;
|
| }
|
| }
|
|
|
| @@ -97,8 +98,20 @@ template <typename T> void sk_delete(T* ptr) { SkDELETE(ptr); }
|
| // reader-consumes memory pairing rather than the more general write-releases /
|
| // reader-acquires convention.
|
| //
|
| -// This is nice, because a sk_consume_load is free on all our platforms: x86,
|
| -// ARM, MIPS. In contrast, sk_acquire_load issues a memory barrier on non-x86.
|
| +// This is nice, because a consume load is free on all our platforms: x86,
|
| +// ARM, MIPS. In contrast, an acquire load issues a memory barrier on non-x86.
|
| +
|
| +template <typename T>
|
| +T consume_load(T* ptr) {
|
| +#if DYNAMIC_ANNOTATIONS_ENABLED
|
| + // TSAN gets anxious if we don't tell it what we're actually doing, a consume load.
|
| + return sk_atomic_load(ptr, sk_memory_order_consume);
|
| +#else
|
| + // All current compilers blindly upgrade consume memory order to acquire memory order.
|
| + // For our purposes, though, no memory barrier is required, so we lie and use relaxed.
|
| + return sk_atomic_load(ptr, sk_memory_order_relaxed);
|
| +#endif
|
| +}
|
|
|
| // This has no constructor and must be zero-initalized (the macro above does this).
|
| template <typename T, T* (*Create)() = sk_new<T>, void (*Destroy)(T*) = sk_delete<T> >
|
| @@ -107,12 +120,12 @@ public:
|
| T* get() {
|
| // If fPtr has already been filled, we need a consume barrier when loading it.
|
| // If not, we need a release barrier when setting it. try_cas will do that.
|
| - T* ptr = (T*)sk_consume_load(&fPtr);
|
| + T* ptr = consume_load(&fPtr);
|
| return ptr ? ptr : try_cas<T*, Destroy>(&fPtr, Create());
|
| }
|
|
|
| private:
|
| - void* fPtr;
|
| + T* fPtr;
|
| };
|
|
|
| template <typename T> T* sk_new_arg(int i) { return SkNEW_ARGS(T, (i)); }
|
| @@ -125,12 +138,12 @@ public:
|
| SkASSERT(i >= 0 && i < N);
|
| // If fPtr has already been filled, we need an consume barrier when loading it.
|
| // If not, we need a release barrier when setting it. try_cas will do that.
|
| - T* ptr = (T*)sk_consume_load(&fArray[i]);
|
| + T* ptr = consume_load(&fArray[i]);
|
| return ptr ? ptr : try_cas<T*, Destroy>(&fArray[i], Create(i));
|
| }
|
|
|
| private:
|
| - void* fArray[N];
|
| + T* fArray[N];
|
| };
|
|
|
| } // namespace Private
|
| @@ -148,18 +161,18 @@ public:
|
| ~SkLazyPtr() { if (fPtr) { Destroy((T*)fPtr); } }
|
|
|
| T* get() const {
|
| - T* ptr = (T*)sk_consume_load(&fPtr);
|
| + T* ptr = Private::consume_load(&fPtr);
|
| return ptr ? ptr : Private::try_cas<T*, Destroy>(&fPtr, SkNEW(T));
|
| }
|
|
|
| template <typename Create>
|
| T* get(const Create& create) const {
|
| - T* ptr = (T*)sk_consume_load(&fPtr);
|
| + T* ptr = Private::consume_load(&fPtr);
|
| return ptr ? ptr : Private::try_cas<T*, Destroy>(&fPtr, create());
|
| }
|
|
|
| private:
|
| - mutable void* fPtr;
|
| + mutable T* fPtr;
|
| };
|
|
|
|
|
|
|