diff options
author | mtklein <mtklein@google.com> | 2015-09-09 07:10:42 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-09-09 07:10:42 -0700 |
commit | 2ac6793efc9b33f6104f9c39810bee5714bdc208 (patch) | |
tree | 9d7e8e1e89d3fae55e7f6eabc9139fa28989d561 /include | |
parent | 62fb1ba1786863e545c89839b5706ad5151cec15 (diff) |
Revert of Port uses of SkLazyPtr to SkOncePtr. (patchset #7 id:110001 of https://codereview.chromium.org/1322933005/ )
Reason for revert:
Breaks Chrome roll.
obj/skia/ext/skia_chrome.skia_memory_dump_provider.o
does not have -I include/private on its include path, but transitively includes SkMessageBus.h.
Original issue's description:
> Port uses of SkLazyPtr to SkOncePtr.
>
> This gives SkOncePtr a non-trivial destructor that uses std::default_delete
> by default. This is overrideable, as seen in SkColorTable.
>
> SK_DECLARE_STATIC_ONCE_PTR still just leaves its pointers hanging at EOP.
>
> BUG=skia:
>
> No public API changes.
> TBR=reed@google.com
>
> Committed: https://skia.googlesource.com/skia/+/a1254acdb344174e761f5061c820559dab64a74c
TBR=herb@google.com,mtklein@chromium.org
NOPRESUBMIT=true
NOTREECHECKS=true
NOTRY=true
BUG=skia:
Review URL: https://codereview.chromium.org/1334523002
Diffstat (limited to 'include')
-rw-r--r-- | include/core/SkColorTable.h | 8 | ||||
-rw-r--r-- | include/core/SkLazyPtr.h | 188 | ||||
-rw-r--r-- | include/core/SkTypeface.h | 9 | ||||
-rw-r--r-- | include/private/SkOncePtr.h | 23 |
4 files changed, 209 insertions, 19 deletions
diff --git a/include/core/SkColorTable.h b/include/core/SkColorTable.h index ff2bf7cde2..c6ca1e961f 100644 --- a/include/core/SkColorTable.h +++ b/include/core/SkColorTable.h @@ -10,10 +10,10 @@ #ifndef SkColorTable_DEFINED #define SkColorTable_DEFINED -#include "../private/SkOncePtr.h" #include "SkColor.h" #include "SkFlattenable.h" #include "SkImageInfo.h" +#include "SkLazyPtr.h" /** \class SkColorTable @@ -55,16 +55,16 @@ public: static SkColorTable* Create(SkReadBuffer&); private: + static void Free16BitCache(uint16_t*); + enum AllocatedWithMalloc { kAllocatedWithMalloc }; // assumes ownership of colors (assumes it was allocated w/ malloc) SkColorTable(SkPMColor* colors, int count, AllocatedWithMalloc); - struct Free16BitCache { void operator()(uint16_t* cache) const { sk_free(cache); } }; - SkPMColor* fColors; - SkOncePtr<uint16_t, Free16BitCache> f16BitCache; + SkLazyPtr<uint16_t, Free16BitCache> f16BitCache; int fCount; void init(const SkPMColor* colors, int count); diff --git a/include/core/SkLazyPtr.h b/include/core/SkLazyPtr.h new file mode 100644 index 0000000000..b0cd2ff559 --- /dev/null +++ b/include/core/SkLazyPtr.h @@ -0,0 +1,188 @@ +/* + * Copyright 2014 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +#ifndef SkLazyPtr_DEFINED +#define SkLazyPtr_DEFINED + +/** Declare a lazily-chosen static pointer (or array of pointers) of type T. + * + * Example usage: + * + * Foo* GetSingletonFoo() { + * SK_DECLARE_STATIC_LAZY_PTR(Foo, singleton); // Created with new, destroyed with delete. + * return singleton.get(); + * } + * + * These macros take an optional T* (*Create)() and void (*Destroy)(T*) at the end. + * If not given, we'll use new and delete. + * These options are most useful when T doesn't have a public constructor or destructor. + * Create comes first, so you may use a custom Create with a default Destroy, but not vice versa. + * + * Foo* CustomCreate() { return ...; } + * void CustomDestroy(Foo* ptr) { ... } + * Foo* GetSingletonFooWithCustomCleanup() { + * SK_DECLARE_STATIC_LAZY_PTR(Foo, singleton, CustomCreate, CustomDestroy); + * return singleton.get(); + * } + * + * If you have a bunch of related static pointers of the same type, you can + * declare an array of lazy pointers together, and we'll pass the index to Create(). + * + * Foo* CreateFoo(int i) { return ...; } + * Foo* GetCachedFoo(Foo::Enum enumVal) { + * SK_DECLARE_STATIC_LAZY_PTR_ARRAY(Foo, Foo::kEnumCount, cachedFoos, CreateFoo); + * return cachedFoos[enumVal]; + * } + * + * + * You can think of SK_DECLARE_STATIC_LAZY_PTR as a cheaper specialization of + * SkOnce. There is no mutex or extra storage used past the pointer itself. + * + * We may call Create more than once, but all threads will see the same pointer + * returned from get(). Any extra calls to Create will be cleaned up. + * + * These macros must be used in a global scope, not in function scope or as a class member. + */ + +#define SK_DECLARE_STATIC_LAZY_PTR(T, name, ...) \ + namespace {} static Private::SkStaticLazyPtr<T, ##__VA_ARGS__> name + +#define SK_DECLARE_STATIC_LAZY_PTR_ARRAY(T, name, N, ...) \ + namespace {} static Private::SkStaticLazyPtrArray<T, N, ##__VA_ARGS__> name + +// namespace {} forces these macros to only be legal in global scopes. Chrome has thread-safety +// problems with them in function-local statics because it uses -fno-threadsafe-statics, and even +// in builds with threadsafe statics, those threadsafe statics are just unnecessary overhead. + +// Everything below here is private implementation details. Don't touch, don't even look. + +#include "SkAtomics.h" + +// See FIXME below. +class SkFontConfigInterfaceDirect; + +namespace Private { + +// Set *dst to ptr if *dst is NULL. Returns value of *dst, destroying ptr if not swapped in. +// Issues acquire memory barrier on failure, release on success. +template <typename P, void (*Destroy)(P)> +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; + } +} + +template <typename T> +T* sk_new() { + return new T; +} +template <typename T> +void sk_delete(T* ptr) { + delete ptr; +} + +// We're basing these implementations here on this article: +// http://preshing.com/20140709/the-purpose-of-memory_order_consume-in-cpp11/ +// +// Because the users of SkLazyPtr and SkLazyPtrArray will read the pointers +// _through_ our atomically set pointer, there is a data dependency between our +// atomic and the guarded data, and so we only need writer-releases / +// reader-consumes memory pairing rather than the more general write-releases / +// reader-acquires convention. +// +// 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 defined(THREAD_SANITIZER) + // 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> > +class SkStaticLazyPtr { +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 = consume_load(&fPtr); + return ptr ? ptr : try_cas<T*, Destroy>(&fPtr, Create()); + } + +private: + T* fPtr; +}; + +template <typename T> +T* sk_new_arg(int i) { + return new T(i); +} + +// This has no constructor and must be zero-initalized (the macro above does this). +template <typename T, int N, T* (*Create)(int) = sk_new_arg<T>, void (*Destroy)(T*) = sk_delete<T> > +class SkStaticLazyPtrArray { +public: + T* operator[](int i) { + 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 = consume_load(&fArray[i]); + return ptr ? ptr : try_cas<T*, Destroy>(&fArray[i], Create(i)); + } + +private: + T* fArray[N]; +}; + +} // namespace Private + +// This version is suitable for use as a class member. +// It's much the same as above except: +// - it has a constructor to zero itself; +// - it has a destructor to clean up; +// - get() calls SkNew(T) to create the pointer; +// - get(functor) calls functor to create the pointer. +template <typename T, void (*Destroy)(T*) = Private::sk_delete<T> > +class SkLazyPtr : SkNoncopyable { +public: + SkLazyPtr() : fPtr(NULL) {} + ~SkLazyPtr() { if (fPtr) { Destroy((T*)fPtr); } } + + T* get() const { + T* ptr = Private::consume_load(&fPtr); + return ptr ? ptr : Private::try_cas<T*, Destroy>(&fPtr, new T); + } + + template <typename Create> + T* get(const Create& create) const { + T* ptr = Private::consume_load(&fPtr); + return ptr ? ptr : Private::try_cas<T*, Destroy>(&fPtr, create()); + } + +private: + mutable T* fPtr; +}; + + +#endif//SkLazyPtr_DEFINED diff --git a/include/core/SkTypeface.h b/include/core/SkTypeface.h index 0b1ca6a4bd..c4242181fb 100644 --- a/include/core/SkTypeface.h +++ b/include/core/SkTypeface.h @@ -10,11 +10,11 @@ #ifndef SkTypeface_DEFINED #define SkTypeface_DEFINED -#include "../private/SkOncePtr.h" -#include "../private/SkWeakRefCnt.h" #include "SkFontStyle.h" +#include "SkLazyPtr.h" #include "SkRect.h" #include "SkString.h" +#include "../private/SkWeakRefCnt.h" class SkDescriptor; class SkFontData; @@ -398,7 +398,10 @@ private: static SkTypeface* CreateDefault(int style); // SkLazyPtr requires an int, not a Style. static void DeleteDefault(SkTypeface*); - SkOncePtr<SkRect> fLazyBounds; + struct BoundsComputer; +// friend struct BoundsComputer; + + SkLazyPtr<SkRect> fLazyBounds; SkFontID fUniqueID; SkFontStyle fStyle; bool fIsFixedPitch; diff --git a/include/private/SkOncePtr.h b/include/private/SkOncePtr.h index 40bea1a4c3..9af204bcb2 100644 --- a/include/private/SkOncePtr.h +++ b/include/private/SkOncePtr.h @@ -9,23 +9,22 @@ #define SkOncePtr_DEFINED #include "SkAtomics.h" -#include "SkUniquePtr.h" -template <typename T> class SkBaseOncePtr; +template <typename T> class SkStaticOnce; // Use this to create a global static pointer that's intialized exactly once when you call get(). -#define SK_DECLARE_STATIC_ONCE_PTR(type, name) namespace {} static SkBaseOncePtr<type> name +#define SK_DECLARE_STATIC_ONCE_PTR(type, name) namespace {} static SkStaticOnce<type> name // Use this for a local or member pointer that's initialized exactly once when you call get(). -template <typename T, typename Delete = skstd::default_delete<T>> +template <typename T> class SkOncePtr : SkNoncopyable { public: SkOncePtr() { sk_bzero(this, sizeof(*this)); } - ~SkOncePtr() { - if (T* ptr = (T*)*this) { - Delete()(ptr); - } - } + + // SkOncePtr does not have a destructor and does not clean up the pointer. But you may, e.g. + // delete (T*)fOncePtr; + // SkSafeUnref((T*)fOncePtr); + // etc. template <typename F> T* get(const F& f) const { @@ -37,11 +36,11 @@ public: } private: - SkBaseOncePtr<T> fOnce; + SkStaticOnce<T> fOnce; }; /* TODO(mtklein): in next CL -typedef SkBaseOncePtr<void> SkOnceFlag; +typedef SkStaticOnce<void> SkOnceFlag; #define SK_DECLARE_STATIC_ONCE(name) namespace {} static SkOnceFlag name template <typename F> @@ -53,7 +52,7 @@ inline void SkOnce(SkOnceFlag* once, const F& f) { // Implementation details below here! No peeking! template <typename T> -class SkBaseOncePtr { +class SkStaticOnce { public: template <typename F> T* get(const F& f) const { |