aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkLazyFnPtr.h
diff options
context:
space:
mode:
authorGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-05-28 19:40:21 +0000
committerGravatar commit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>2014-05-28 19:40:21 +0000
commit3fdc7d6dd13b510de09cf29ffd3fe36adf89d541 (patch)
tree86f759d14cce06337d375fda6493d0bb9259c8ee /src/core/SkLazyFnPtr.h
parent29ac34ee526578fb0a01cd2d0c23c23e6a823d82 (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.h58
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