1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkSpinlock_DEFINED
9 #define SkSpinlock_DEFINED
10 
11 #include "include/core/SkTypes.h"
12 #include "include/private/SkThreadAnnotations.h"
13 #include <atomic>
14 
15 class SK_CAPABILITY("mutex") SkSpinlock {
16 public:
17     constexpr SkSpinlock() = default;
18 
acquire()19     void acquire() SK_ACQUIRE() {
20         // To act as a mutex, we need an acquire barrier when we acquire the lock.
21         if (fLocked.exchange(true, std::memory_order_acquire)) {
22             // Lock was contended.  Fall back to an out-of-line spin loop.
23             this->contendedAcquire();
24         }
25     }
26 
27     // Acquire the lock or fail (quickly). Lets the caller decide to do something other than wait.
tryAcquire()28     bool tryAcquire() SK_TRY_ACQUIRE(true) {
29         // To act as a mutex, we need an acquire barrier when we acquire the lock.
30         if (fLocked.exchange(true, std::memory_order_acquire)) {
31             // Lock was contended. Let the caller decide what to do.
32             return false;
33         }
34         return true;
35     }
36 
release()37     void release() SK_RELEASE_CAPABILITY() {
38         // To act as a mutex, we need a release barrier when we release the lock.
39         fLocked.store(false, std::memory_order_release);
40     }
41 
42 private:
43     SK_API void contendedAcquire();
44 
45     std::atomic<bool> fLocked{false};
46 };
47 
48 class SK_SCOPED_CAPABILITY SkAutoSpinlock {
49 public:
SkAutoSpinlock(SkSpinlock & mutex)50     SkAutoSpinlock(SkSpinlock& mutex) SK_ACQUIRE(mutex) : fSpinlock(mutex) { fSpinlock.acquire(); }
SK_RELEASE_CAPABILITY()51     ~SkAutoSpinlock() SK_RELEASE_CAPABILITY() { fSpinlock.release(); }
52 
53 private:
54     SkSpinlock& fSpinlock;
55 };
56 
57 #endif//SkSpinlock_DEFINED
58