Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(636)

Unified Diff: src/core/SkOnce.h

Issue 26491003: SK_ONCE for SkData (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: dropped assert Created 7 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/core/SkMatrix.cpp ('k') | src/core/SkPathRef.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/core/SkOnce.h
diff --git a/src/core/SkOnce.h b/src/core/SkOnce.h
index d5dd9d925ba0f413b3922a7ba99a44720d0f7341..2c14942077fff78fc1ba9dffafd087dc09488c91 100644
--- a/src/core/SkOnce.h
+++ b/src/core/SkOnce.h
@@ -8,54 +8,46 @@
#ifndef SkOnce_DEFINED
#define SkOnce_DEFINED
-// SkOnce.h defines two macros, DEF_SK_ONCE and SK_ONCE.
-// You can use these macros together to create a threadsafe block of code that
-// runs at most once, no matter how many times you call it. This is
-// particularly useful for lazy singleton initialization. E.g.
+// SkOnce.h defines SK_DECLARE_STATIC_ONCE and SkOnce(), which you can use
+// together to create a threadsafe way to call a function just once. This
+// is particularly useful for lazy singleton initialization. E.g.
//
-// DEF_SK_ONCE(set_up_my_singleton, SingletonType* singleton) {
-// // Code in this block will run at most once.
+// static void set_up_my_singleton(Singleton** singleton) {
// *singleton = new Singleton(...);
// }
// ...
-// const Singleton& getSingleton() {
+// const Singleton& GetSingleton() {
// static Singleton* singleton = NULL;
-// // Always call SK_ONCE. It's very cheap to call after the first time.
-// SK_ONCE(set_up_my_singleton, singleton);
+// SK_DECLARE_STATIC_ONCE(once);
+// SkOnce(&once, set_up_my_singleton, &singleton);
// SkASSERT(NULL != singleton);
// return *singleton;
// }
//
-// OnceTest.cpp also should serve as another simple example.
+// OnceTest.cpp also should serve as a few other simple examples.
#include "SkThread.h"
#include "SkTypes.h"
+#ifdef SK_USE_POSIX_THREADS
+#define SK_DECLARE_STATIC_ONCE(name) \
+ static SkOnceFlag name = { false, { PTHREAD_MUTEX_INITIALIZER } }
+#else
+#define SK_DECLARE_STATIC_ONCE(name) \
+ static SkOnceFlag name = { false, SkBaseMutex() }
+#endif
-// Pass a unique name (at least in this scope) for name, and a type and name
-// for arg (as if writing a function declaration).
-// E.g.
-// DEF_SK_ONCE(my_onetime_setup, int* foo) {
-// *foo += 5;
-// }
-#define DEF_SK_ONCE(name, arg) \
- static bool sk_once_##name##_done = false; \
- SK_DECLARE_STATIC_MUTEX(sk_once_##name##_mutex); \
- static void sk_once_##name##_function(arg)
-
-// Call this anywhere you need to guarantee that the corresponding DEF_SK_ONCE
-// block of code has run. name should match the DEF_SK_ONCE, and here you pass
-// the actual value of the argument.
-// E.g
-// int foo = 0;
-// SK_ONCE(my_onetime_setup, &foo);
-// SkASSERT(5 == foo);
-#define SK_ONCE(name, arg) \
- sk_once(&sk_once_##name##_done, &sk_once_##name##_mutex, sk_once_##name##_function, arg)
+struct SkOnceFlag;
+template <typename Arg>
+inline void SkOnce(SkOnceFlag* once, void (*f)(Arg), Arg arg);
// ---------------------- Implementation details below here. -----------------------------
+struct SkOnceFlag {
+ bool done;
+ SkBaseMutex mutex;
+};
// TODO(bungeman, mtklein): move all these *barrier* functions to SkThread when refactoring lands.
@@ -98,13 +90,13 @@ inline static void acquire_barrier() {
// one-time code hasn't run yet.
// 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 sk_once and don't mark it as inline.
+// 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(bool* done, SkBaseMutex* mutex, void (*once)(Arg), Arg arg) {
- const SkAutoMutexAcquire lock(*mutex);
- if (!*done) {
- once(arg);
+static void sk_once_slow(SkOnceFlag* once, void (*f)(Arg), 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
// before the writes after the line, *done = true.
@@ -115,7 +107,7 @@ static void sk_once_slow(bool* done, SkBaseMutex* mutex, void (*once)(Arg), Arg
// We'll use this in the fast path to make sure once(arg)'s effects are
// observable whenever we observe *done == true.
release_barrier();
- *done = true;
+ once->done = true;
}
}
@@ -136,25 +128,24 @@ void AnnotateBenignRace(const char* file, int line, const volatile void* mem, co
// This is our fast path, called all the time. We do really want it to be inlined.
template <typename Arg>
-inline static void sk_once(bool* done, SkBaseMutex* mutex, void (*once)(Arg), Arg arg) {
- ANNOTATE_BENIGN_RACE(done, "Don't worry TSAN, we're sure this is safe.");
- if (!*done) {
- sk_once_slow(done, mutex, once, arg);
+inline void SkOnce(SkOnceFlag* once, void (*f)(Arg), 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);
}
// Also known as a load-load/load-store barrier, this acquire barrier makes
// sure that anything we read from memory---in particular, memory written by
- // calling once(arg)---is at least as current as the value we read from done.
+ // calling f(arg)---is at least as current as the value we read from once->done.
//
// In version control terms, this is a lot like saying "sync up to the
- // commit where we wrote *done = true".
+ // commit where we wrote once->done = true".
//
- // The release barrier in sk_once_slow guaranteed that *done = true
- // happens after once(arg), so by syncing to *done = true here we're
- // forcing ourselves to also wait until the effects of once(arg) are readble.
+ // The release barrier in sk_once_slow guaranteed that once->done = true
+ // happens after f(arg), so by syncing to once->done = true here we're
+ // forcing ourselves to also wait until the effects of f(arg) are readble.
acquire_barrier();
}
#undef ANNOTATE_BENIGN_RACE
-
#endif // SkOnce_DEFINED
« no previous file with comments | « src/core/SkMatrix.cpp ('k') | src/core/SkPathRef.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698