| Index: include/core/SkOnce.h
 | 
| diff --git a/include/core/SkOnce.h b/include/core/SkOnce.h
 | 
| index 59eaf598bca1b3a49257cbcf856b5b248c79063e..daeb819d428408d36ef4cb7b72407d2a12fc01e9 100644
 | 
| --- a/include/core/SkOnce.h
 | 
| +++ b/include/core/SkOnce.h
 | 
| @@ -40,8 +40,32 @@ struct SkOnceFlag;  // If manually created, initialize with SkOnceFlag once = SK
 | 
|  template <typename Func, typename Arg>
 | 
|  inline void SkOnce(SkOnceFlag* once, Func f, Arg arg, void(*atExit)() = NULL);
 | 
|  
 | 
| +// If you've already got a lock and a flag to use, this variant lets you avoid an extra SkOnceFlag.
 | 
| +template <typename Lock, typename Func, typename Arg>
 | 
| +inline void SkOnce(bool* done, Lock* lock, Func f, Arg arg, void(*atExit)() = NULL);
 | 
| +
 | 
|  //  ----------------------  Implementation details below here. -----------------------------
 | 
|  
 | 
| +// This is POD and must be zero-initialized.
 | 
| +struct SkSpinlock {
 | 
| +    void acquire() {
 | 
| +        SkASSERT(shouldBeZero == 0);
 | 
| +        // No memory barrier needed, but sk_atomic_cas gives us at least release anyway.
 | 
| +        while (!sk_atomic_cas(&thisIsPrivate, 0, 1)) {
 | 
| +            // spin
 | 
| +        }
 | 
| +    }
 | 
| +
 | 
| +    void release() {
 | 
| +        SkASSERT(shouldBeZero == 0);
 | 
| +        // This requires a release memory barrier before storing, which sk_atomic_cas guarantees.
 | 
| +        SkAssertResult(sk_atomic_cas(&thisIsPrivate, 1, 0));
 | 
| +    }
 | 
| +
 | 
| +    int32_t thisIsPrivate;
 | 
| +    SkDEBUGCODE(int32_t shouldBeZero;)
 | 
| +};
 | 
| +
 | 
|  struct SkOnceFlag {
 | 
|      bool done;
 | 
|      SkSpinlock lock;
 | 
| @@ -87,6 +111,16 @@ inline static void acquire_barrier() {
 | 
|      full_barrier_on_arm();
 | 
|  }
 | 
|  
 | 
| +// Works with SkSpinlock or SkMutex.
 | 
| +template <typename Lock>
 | 
| +class SkAutoLockAcquire {
 | 
| +public:
 | 
| +    explicit SkAutoLockAcquire(Lock* lock) : fLock(lock) { fLock->acquire(); }
 | 
| +    ~SkAutoLockAcquire() { fLock->release(); }
 | 
| +private:
 | 
| +    Lock* fLock;
 | 
| +};
 | 
| +
 | 
|  // We've pulled a pretty standard double-checked locking implementation apart
 | 
|  // into its main fast path and a slow path that's called when we suspect the
 | 
|  // one-time code hasn't run yet.
 | 
| @@ -94,10 +128,10 @@ 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 Func, typename Arg>
 | 
| -static void sk_once_slow(SkOnceFlag* once, Func f, Arg arg, void (*atExit)()) {
 | 
| -    const SkAutoSpinlock lock(&once->lock);
 | 
| -    if (!once->done) {
 | 
| +template <typename Lock, typename Func, typename Arg>
 | 
| +static void sk_once_slow(bool* done, Lock* lock, Func f, Arg arg, void (*atExit)()) {
 | 
| +    const SkAutoLockAcquire<Lock> locked(lock);
 | 
| +    if (!*done) {
 | 
|          f(arg);
 | 
|          if (atExit != NULL) {
 | 
|              atexit(atExit);
 | 
| @@ -112,15 +146,15 @@ static void sk_once_slow(SkOnceFlag* once, Func f, Arg arg, void (*atExit)()) {
 | 
|          // 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;
 | 
| +        *done = true;
 | 
|      }
 | 
|  }
 | 
|  
 | 
|  // This is our fast path, called all the time.  We do really want it to be inlined.
 | 
| -template <typename Func, typename Arg>
 | 
| -inline void SkOnce(SkOnceFlag* once, Func f, Arg arg, void(*atExit)()) {
 | 
| -    if (!SK_ANNOTATE_UNPROTECTED_READ(once->done)) {
 | 
| -        sk_once_slow(once, f, arg, atExit);
 | 
| +template <typename Lock, typename Func, typename Arg>
 | 
| +inline void SkOnce(bool* done, Lock* lock, Func f, Arg arg, void(*atExit)()) {
 | 
| +    if (!SK_ANNOTATE_UNPROTECTED_READ(*done)) {
 | 
| +        sk_once_slow(done, lock, f, arg, atExit);
 | 
|      }
 | 
|      // 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
 | 
| @@ -135,6 +169,11 @@ inline void SkOnce(SkOnceFlag* once, Func f, Arg arg, void(*atExit)()) {
 | 
|      acquire_barrier();
 | 
|  }
 | 
|  
 | 
| +template <typename Func, typename Arg>
 | 
| +inline void SkOnce(SkOnceFlag* once, Func f, Arg arg, void(*atExit)()) {
 | 
| +    return SkOnce(&once->done, &once->lock, f, arg, atExit);
 | 
| +}
 | 
| +
 | 
|  #undef SK_ANNOTATE_BENIGN_RACE
 | 
|  
 | 
|  #endif  // SkOnce_DEFINED
 | 
| 
 |