SkOnce: let f be any functor, update comments
BUG= R=bungeman@google.com Author: mtklein@google.com Review URL: https://codereview.chromium.org/104433005 git-svn-id: http://skia.googlecode.com/svn/trunk@12518 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
7787f2128d
commit
1b2c1b893a
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user