1d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org/* 2d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org * Copyright 2014 Google Inc. 3d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org * 4d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org * Use of this source code is governed by a BSD-style license that can be 5d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org * found in the LICENSE file. 6d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org */ 7d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org 881496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org#ifndef SkLazyFnPtr_DEFINED 981496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org#define SkLazyFnPtr_DEFINED 1081496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org 1181496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org/** Declare a lazily-chosen static function pointer of type F. 1281496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org * 1381496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org * Example usage: 1481496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org * 1581496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org * typedef int (*FooImpl)(int, int); 1681496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org * 1781496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org * static FooImpl choose_foo() { return ... }; 1881496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org * 1981496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org * int Foo(int a, int b) { 20d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org * SK_DECLARE_STATIC_LAZY_FN_PTR(FooImpl, foo, choose_foo); 21d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org * return foo.get()(a, b); 2281496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org * } 2381496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org * 2481496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org * You can think of SK_DECLARE_STATIC_LAZY_FN_PTR as a cheaper specialization of SkOnce. 2581496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org * There is no mutex, and in the fast path, no memory barriers are issued. 2681496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org * 2781496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org * This must be used in a global or function scope, not as a class member. 2881496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org */ 29d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org#define SK_DECLARE_STATIC_LAZY_FN_PTR(F, name, Choose) static Private::SkLazyFnPtr<F, Choose> name 3081496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org 3181496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org 3281496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org// Everything below here is private implementation details. Don't touch, don't even look. 3381496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org 3481496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org#include "SkDynamicAnnotations.h" 3581496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org#include "SkThreadPriv.h" 3681496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org 3781496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.orgnamespace Private { 3881496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org 39d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org// This has no constructor and must be zero-initialized (the macro above does this). 40d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.orgtemplate <typename F, F (*Choose)()> 41d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.orgclass SkLazyFnPtr { 42d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.orgpublic: 43d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org F get() { 4481496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org // First, try reading to see if it's already set. 4581496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org F fn = (F)SK_ANNOTATE_UNPROTECTED_READ(fPtr); 4681496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org if (fn != NULL) { 4781496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org return fn; 4881496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org } 4981496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org 5081496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org // We think it's not already set. 51d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.org fn = Choose(); 5281496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org 5381496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org // No particular memory barriers needed; we're not guarding anything but the pointer itself. 5481496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org F prev = (F)sk_atomic_cas(&fPtr, NULL, (void*)fn); 5581496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org 5681496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org // If prev != NULL, someone snuck in and set fPtr concurrently. 5781496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org // If prev == NULL, we did write fn to fPtr. 5881496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org return prev != NULL ? prev : fn; 5981496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org } 6081496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org 61d3c6b3f1c89ad1336830957a1e9b235dd86910f2commit-bot@chromium.orgprivate: 6281496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org void* fPtr; 6381496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org}; 6481496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org 6581496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org} // namespace Private 6681496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org 6781496fb21637cc8d2a2b45a790e0f9d6d6f769c4commit-bot@chromium.org#endif//SkLazyFnPtr_DEFINED 68