SK_ONCE for SkData and SkPathRef

Adds SK_ONCE_FRIEND, to allow SK_DEF_ONCE code to be friends with a class.  This had to go in include/core to be visible to headers there.

BUG=
R=reed@google.com, bungeman@google.com

Author: mtklein@google.com

Review URL: https://codereview.chromium.org/26491003

git-svn-id: http://skia.googlecode.com/svn/trunk@11914 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkData.cpp b/src/core/SkData.cpp
index 8d6156c..56c1256 100644
--- a/src/core/SkData.cpp
+++ b/src/core/SkData.cpp
@@ -8,6 +8,7 @@
 #include "SkData.h"
 #include "SkFlattenableBuffers.h"
 #include "SkOSFile.h"
+#include "SkOnce.h"
 
 SK_DEFINE_INST_COUNT(SkData)
 
@@ -49,11 +50,14 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
+void SkData::NewEmptyImpl(SkData** empty) {
+    *empty = new SkData(NULL, 0, NULL, NULL);
+}
+
 SkData* SkData::NewEmpty() {
     static SkData* gEmptyRef;
-    if (NULL == gEmptyRef) {
-        gEmptyRef = new SkData(NULL, 0, NULL, NULL);
-    }
+    SK_DECLARE_STATIC_ONCE(once);
+    SkOnce(&once, SkData::NewEmptyImpl, &gEmptyRef);
     gEmptyRef->ref();
     return gEmptyRef;
 }
diff --git a/src/core/SkMatrix.cpp b/src/core/SkMatrix.cpp
index 41c0f88..5bcb35b 100644
--- a/src/core/SkMatrix.cpp
+++ b/src/core/SkMatrix.cpp
@@ -1894,14 +1894,15 @@
     return SkScalarSqrt(largerRoot);
 }
 
-DEF_SK_ONCE(reset_identity_matrix, SkMatrix* identity) {
+static void reset_identity_matrix(SkMatrix* identity) {
     identity->reset();
 }
 
 const SkMatrix& SkMatrix::I() {
     // If you can use C++11 now, you might consider replacing this with a constexpr constructor.
     static SkMatrix gIdentity;
-    SK_ONCE(reset_identity_matrix, &gIdentity);
+    SK_DECLARE_STATIC_ONCE(once);
+    SkOnce(&once, reset_identity_matrix, &gIdentity);
     return gIdentity;
 }
 
diff --git a/src/core/SkOnce.h b/src/core/SkOnce.h
index d5dd9d9..2c14942 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)
+struct SkOnceFlag;
 
-// 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)
-
+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 @@
 // 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 @@
         // 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 @@
 
 // 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
diff --git a/src/core/SkPathRef.cpp b/src/core/SkPathRef.cpp
index aeef227..f635c2a 100644
--- a/src/core/SkPathRef.cpp
+++ b/src/core/SkPathRef.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "SkBuffer.h"
+#include "SkOnce.h"
 #include "SkPath.h"
 #include "SkPathRef.h"
 
@@ -36,6 +37,18 @@
 }
 
 //////////////////////////////////////////////////////////////////////////////
+void SkPathRef::CreateEmptyImpl(SkPathRef** empty) {
+    *empty = SkNEW(SkPathRef);
+    (*empty)->computeBounds();  // Preemptively avoid a race to clear fBoundsIsDirty.
+}
+
+SkPathRef* SkPathRef::CreateEmpty() {
+    static SkPathRef* gEmptyPathRef;
+    SK_DECLARE_STATIC_ONCE(once);
+    SkOnce(&once, SkPathRef::CreateEmptyImpl, &gEmptyPathRef);
+    return SkRef(gEmptyPathRef);
+}
+
 void SkPathRef::CreateTransformedCopy(SkAutoTUnref<SkPathRef>* dst,
                                       const SkPathRef& src,
                                       const SkMatrix& matrix) {