diff options
-rw-r--r-- | src/core/SkOnce.h | 40 | ||||
-rw-r--r-- | src/core/SkScaledImageCache.cpp | 2 | ||||
-rw-r--r-- | tests/OnceTest.cpp | 14 |
3 files changed, 35 insertions, 21 deletions
diff --git a/src/core/SkOnce.h b/src/core/SkOnce.h index a469e22c86..89de112442 100644 --- a/src/core/SkOnce.h +++ b/src/core/SkOnce.h @@ -13,15 +13,15 @@ // is particularly useful for lazy singleton initialization. E.g. // // static void set_up_my_singleton(Singleton** singleton) { -// *singleton = new Singleton(...); +// *singleton = new Singleton(...); // } // ... // const Singleton& GetSingleton() { -// static Singleton* singleton = NULL; -// SK_DECLARE_STATIC_ONCE(once); -// SkOnce(&once, set_up_my_singleton, &singleton); -// SkASSERT(NULL != singleton); -// return *singleton; +// static Singleton* singleton = NULL; +// SK_DECLARE_STATIC_ONCE(once); +// SkOnce(&once, set_up_my_singleton, &singleton); +// SkASSERT(NULL != singleton); +// return *singleton; // } // // OnceTest.cpp also should serve as a few other simple examples. @@ -30,17 +30,17 @@ #include "SkTypes.h" #ifdef SK_USE_POSIX_THREADS -#define SK_DECLARE_STATIC_ONCE(name) \ - static SkOnceFlag name = { false, { PTHREAD_MUTEX_INITIALIZER } } +# define SK_ONCE_INIT { false, { PTHREAD_MUTEX_INITIALIZER } } #else -#define SK_DECLARE_STATIC_ONCE(name) \ - static SkOnceFlag name = { false, SkBaseMutex() } +# define SK_ONCE_INIT { false, SkBaseMutex() } #endif -struct SkOnceFlag; +#define SK_DECLARE_STATIC_ONCE(name) static SkOnceFlag name = SK_ONCE_INIT -template <typename Arg> -inline void SkOnce(SkOnceFlag* once, void (*f)(Arg), Arg arg); +struct SkOnceFlag; // If manually created, initialize with SkOnceFlag once = SK_ONCE_INIT + +template <typename Func, typename Arg> +inline void SkOnce(SkOnceFlag* once, Func f, Arg arg); // ---------------------- Implementation details below here. ----------------------------- @@ -96,19 +96,19 @@ inline static void acquire_barrier() { // This is the guts of the code, called when we suspect the one-time code hasn't been run yet. // This should be rarely called, so we separate it from SkOnce and don't mark it as inline. // (We don't mind if this is an actual function call, but odds are it'll be inlined anyway.) -template <typename Arg> -static void sk_once_slow(SkOnceFlag* once, void (*f)(Arg), Arg arg) { +template <typename Func, typename Arg> +static void sk_once_slow(SkOnceFlag* once, Func f, Arg arg) { const SkAutoMutexAcquire lock(once->mutex); if (!once->done) { f(arg); // Also known as a store-store/load-store barrier, this makes sure that the writes - // done before here---in particular, those done by calling once(arg)---are observable + // done before here---in particular, those done by calling f(arg)---are observable // before the writes after the line, *done = true. // // In version control terms this is like saying, "check in the work up - // to and including once(arg), then check in *done=true as a subsequent change". + // to and including f(arg), then check in *done=true as a subsequent change". // - // We'll use this in the fast path to make sure once(arg)'s effects are + // We'll use this in the fast path to make sure f(arg)'s effects are // observable whenever we observe *done == true. release_barrier(); once->done = true; @@ -131,8 +131,8 @@ void AnnotateBenignRace(const char* file, int line, const volatile void* mem, co #endif // This is our fast path, called all the time. We do really want it to be inlined. -template <typename Arg> -inline void SkOnce(SkOnceFlag* once, void (*f)(Arg), Arg arg) { +template <typename Func, typename Arg> +inline void SkOnce(SkOnceFlag* once, Func f, Arg arg) { ANNOTATE_BENIGN_RACE(&(once->done), "Don't worry TSAN, we're sure this is safe."); if (!once->done) { sk_once_slow(once, f, arg); diff --git a/src/core/SkScaledImageCache.cpp b/src/core/SkScaledImageCache.cpp index 55eadb849e..eba20c4f90 100644 --- a/src/core/SkScaledImageCache.cpp +++ b/src/core/SkScaledImageCache.cpp @@ -519,7 +519,7 @@ static void create_cache(SkScaledImageCache** cache) { static SkScaledImageCache* get_cache() { static SkScaledImageCache* gCache(NULL); SK_DECLARE_STATIC_ONCE(create_cache_once); - SkOnce<SkScaledImageCache**>(&create_cache_once, create_cache, &gCache); + SkOnce(&create_cache_once, create_cache, &gCache); SkASSERT(NULL != gCache); return gCache; } diff --git a/tests/OnceTest.cpp b/tests/OnceTest.cpp index 31c6a85a44..d3a0a0066a 100644 --- a/tests/OnceTest.cpp +++ b/tests/OnceTest.cpp @@ -28,6 +28,20 @@ DEF_TEST(SkOnce_Singlethreaded, r) { REPORTER_ASSERT(r, 5 == x); } +struct AddFour { void operator()(int* x) { *x += 4; } }; + +DEF_TEST(SkOnce_MiscFeatures, r) { + // Tests that we support functors and explicit SkOnceFlags. + int x = 0; + + SkOnceFlag once = SK_ONCE_INIT; + SkOnce(&once, AddFour(), &x); + SkOnce(&once, AddFour(), &x); + SkOnce(&once, AddFour(), &x); + + REPORTER_ASSERT(r, 4 == x); +} + static void add_six(int* x) { *x += 6; } |