• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 SkAtomics_DEFINED
9 #define SkAtomics_DEFINED
10 
11 // This file is not part of the public Skia API.
12 #include "SkTypes.h"
13 #include <atomic>
14 
15 // ~~~~~~~~ APIs ~~~~~~~~~
16 
17 enum sk_memory_order {
18     sk_memory_order_relaxed,
19     sk_memory_order_consume,
20     sk_memory_order_acquire,
21     sk_memory_order_release,
22     sk_memory_order_acq_rel,
23     sk_memory_order_seq_cst,
24 };
25 
26 template <typename T>
27 T sk_atomic_load(const T*, sk_memory_order = sk_memory_order_seq_cst);
28 
29 template <typename T>
30 void sk_atomic_store(T*, T, sk_memory_order = sk_memory_order_seq_cst);
31 
32 template <typename T>
33 T sk_atomic_fetch_add(T*, T, sk_memory_order = sk_memory_order_seq_cst);
34 
35 template <typename T>
36 T sk_atomic_fetch_sub(T*, T, sk_memory_order = sk_memory_order_seq_cst);
37 
38 template <typename T>
39 bool sk_atomic_compare_exchange(T*, T* expected, T desired,
40                                 sk_memory_order success = sk_memory_order_seq_cst,
41                                 sk_memory_order failure = sk_memory_order_seq_cst);
42 
43 template <typename T>
44 T sk_atomic_exchange(T*, T, sk_memory_order = sk_memory_order_seq_cst);
45 
46 // A little wrapper class for small T (think, builtins: int, float, void*) to
47 // ensure they're always used atomically.  This is our stand-in for std::atomic<T>.
48 // !!! Please _really_ know what you're doing if you change default_memory_order. !!!
49 template <typename T, sk_memory_order default_memory_order = sk_memory_order_seq_cst>
50 class SkAtomic : SkNoncopyable {
51 public:
SkAtomic()52     SkAtomic() {}
SkAtomic(const T & val)53     explicit SkAtomic(const T& val) : fVal(val) {}
54 
55     // It is essential we return by value rather than by const&.  fVal may change at any time.
56     T load(sk_memory_order mo = default_memory_order) const {
57         return sk_atomic_load(&fVal, mo);
58     }
59 
60     void store(const T& val, sk_memory_order mo = default_memory_order) {
61         sk_atomic_store(&fVal, val, mo);
62     }
63 
64     // Alias for .load(default_memory_order).
T()65     operator T() const {
66         return this->load();
67     }
68 
69     // Alias for .store(v, default_memory_order).
70     T operator=(const T& v) {
71         this->store(v);
72         return v;
73     }
74 
75     T fetch_add(const T& val, sk_memory_order mo = default_memory_order) {
76         return sk_atomic_fetch_add(&fVal, val, mo);
77     }
78 
79     T fetch_sub(const T& val, sk_memory_order mo = default_memory_order) {
80         return sk_atomic_fetch_sub(&fVal, val, mo);
81     }
82 
83     bool compare_exchange(T* expected, const T& desired,
84                           sk_memory_order success = default_memory_order,
85                           sk_memory_order failure = default_memory_order) {
86         return sk_atomic_compare_exchange(&fVal, expected, desired, success, failure);
87     }
88 private:
89     T fVal;
90 };
91 
92 // ~~~~~~~~ Implementations ~~~~~~~~~
93 
94 template <typename T>
sk_atomic_load(const T * ptr,sk_memory_order mo)95 T sk_atomic_load(const T* ptr, sk_memory_order mo) {
96     SkASSERT(mo == sk_memory_order_relaxed ||
97              mo == sk_memory_order_seq_cst ||
98              mo == sk_memory_order_acquire ||
99              mo == sk_memory_order_consume);
100     const std::atomic<T>* ap = reinterpret_cast<const std::atomic<T>*>(ptr);
101     return std::atomic_load_explicit(ap, (std::memory_order)mo);
102 }
103 
104 template <typename T>
sk_atomic_store(T * ptr,T val,sk_memory_order mo)105 void sk_atomic_store(T* ptr, T val, sk_memory_order mo) {
106     SkASSERT(mo == sk_memory_order_relaxed ||
107              mo == sk_memory_order_seq_cst ||
108              mo == sk_memory_order_release);
109     std::atomic<T>* ap = reinterpret_cast<std::atomic<T>*>(ptr);
110     return std::atomic_store_explicit(ap, val, (std::memory_order)mo);
111 }
112 
113 template <typename T>
sk_atomic_fetch_add(T * ptr,T val,sk_memory_order mo)114 T sk_atomic_fetch_add(T* ptr, T val, sk_memory_order mo) {
115     // All values of mo are valid.
116     std::atomic<T>* ap = reinterpret_cast<std::atomic<T>*>(ptr);
117     return std::atomic_fetch_add_explicit(ap, val, (std::memory_order)mo);
118 }
119 
120 template <typename T>
sk_atomic_fetch_sub(T * ptr,T val,sk_memory_order mo)121 T sk_atomic_fetch_sub(T* ptr, T val, sk_memory_order mo) {
122     // All values of mo are valid.
123     std::atomic<T>* ap = reinterpret_cast<std::atomic<T>*>(ptr);
124     return std::atomic_fetch_sub_explicit(ap, val, (std::memory_order)mo);
125 }
126 
127 template <typename T>
sk_atomic_compare_exchange(T * ptr,T * expected,T desired,sk_memory_order success,sk_memory_order failure)128 bool sk_atomic_compare_exchange(T* ptr, T* expected, T desired,
129                                 sk_memory_order success,
130                                 sk_memory_order failure) {
131     // All values of success are valid.
132     SkASSERT(failure == sk_memory_order_relaxed ||
133              failure == sk_memory_order_seq_cst ||
134              failure == sk_memory_order_acquire ||
135              failure == sk_memory_order_consume);
136     SkASSERT(failure <= success);
137     std::atomic<T>* ap = reinterpret_cast<std::atomic<T>*>(ptr);
138     return std::atomic_compare_exchange_strong_explicit(ap, expected, desired,
139                                                         (std::memory_order)success,
140                                                         (std::memory_order)failure);
141 }
142 
143 template <typename T>
sk_atomic_exchange(T * ptr,T val,sk_memory_order mo)144 T sk_atomic_exchange(T* ptr, T val, sk_memory_order mo) {
145     // All values of mo are valid.
146     std::atomic<T>* ap = reinterpret_cast<std::atomic<T>*>(ptr);
147     return std::atomic_exchange_explicit(ap, val, (std::memory_order)mo);
148 }
149 
150 // ~~~~~~~~ Legacy APIs ~~~~~~~~~
151 
152 // From here down we have shims for our old atomics API, to be weaned off of.
153 // We use the default sequentially-consistent memory order to make things simple
154 // and to match the practical reality of our old _sync and _win implementations.
155 
sk_atomic_inc(int32_t * ptr)156 inline int32_t sk_atomic_inc(int32_t* ptr) { return sk_atomic_fetch_add(ptr, +1); }
sk_atomic_dec(int32_t * ptr)157 inline int32_t sk_atomic_dec(int32_t* ptr) { return sk_atomic_fetch_add(ptr, -1); }
158 
159 #endif//SkAtomics_DEFINED
160