diff options
author | 2014-05-28 19:40:21 +0000 | |
---|---|---|
committer | 2014-05-28 19:40:21 +0000 | |
commit | 3fdc7d6dd13b510de09cf29ffd3fe36adf89d541 (patch) | |
tree | 86f759d14cce06337d375fda6493d0bb9259c8ee /src/core/SkLazyFnPtr.h | |
parent | 29ac34ee526578fb0a01cd2d0c23c23e6a823d82 (diff) |
Spin off just SkLazyFnPtr from 305513002.
The memory barrier in SkOnce is a perf regression for sk_mem{set,cpy} in
SkUtils on ARM. We can do a lot better for function pointers.
BUG=skia:
R=bungeman@google.com, mtklein@google.com
Author: mtklein@chromium.org
Review URL: https://codereview.chromium.org/305753002
git-svn-id: http://skia.googlecode.com/svn/trunk@14929 2bbb7eff-a529-9590-31e7-b0007b416f81
Diffstat (limited to 'src/core/SkLazyFnPtr.h')
-rw-r--r-- | src/core/SkLazyFnPtr.h | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/src/core/SkLazyFnPtr.h b/src/core/SkLazyFnPtr.h new file mode 100644 index 0000000000..cb7832d4c5 --- /dev/null +++ b/src/core/SkLazyFnPtr.h @@ -0,0 +1,58 @@ +#ifndef SkLazyFnPtr_DEFINED +#define SkLazyFnPtr_DEFINED + +/** Declare a lazily-chosen static function pointer of type F. + * + * Example usage: + * + * typedef int (*FooImpl)(int, int); + * + * static FooImpl choose_foo() { return ... }; + * + * int Foo(int a, int b) { + * SK_DECLARE_STATIC_LAZY_FN_PTR(FooImpl, choice); + * return choice.get(choose_foo)(a, b); + * } + * + * You can think of SK_DECLARE_STATIC_LAZY_FN_PTR as a cheaper specialization of SkOnce. + * There is no mutex, and in the fast path, no memory barriers are issued. + * + * This must be used in a global or function scope, not as a class member. + */ +#define SK_DECLARE_STATIC_LAZY_FN_PTR(F, name) static Private::SkLazyFnPtr<F> name = { NULL } + + +// Everything below here is private implementation details. Don't touch, don't even look. + +#include "SkDynamicAnnotations.h" +#include "SkThread.h" + +namespace Private { + +// This has no constructor and is link-time initialized, so its members must be public. +template <typename F> +struct SkLazyFnPtr { + F get(F (*choose)()) { + // First, try reading to see if it's already set. + F fn = (F)SK_ANNOTATE_UNPROTECTED_READ(fPtr); + if (fn != NULL) { + return fn; + } + + // We think it's not already set. + fn = choose(); + + // No particular memory barriers needed; we're not guarding anything but the pointer itself. + F prev = (F)sk_atomic_cas(&fPtr, NULL, (void*)fn); + + // If prev != NULL, someone snuck in and set fPtr concurrently. + // If prev == NULL, we did write fn to fPtr. + return prev != NULL ? prev : fn; + } + + void* fPtr; +}; + +} // namespace Private + +#endif//SkLazyFnPtr_DEFINED |