blob: 56272e25e68c70261c12f335647f07d2ec1f961a [file] [log] [blame]
mtklein50ffd992015-03-30 08:13:33 -07001/*
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
mtkleina64c48f2015-01-21 13:13:31 -08008#ifndef SkAtomics_DEFINED
9#define SkAtomics_DEFINED
10
11// This file is not part of the public Skia API.
12#include "SkTypes.h"
mtklein23267db2015-11-12 11:07:53 -080013#include <atomic>
14
15// ~~~~~~~~ APIs ~~~~~~~~~
mtkleina64c48f2015-01-21 13:13:31 -080016
mtkleina669bc72015-02-02 12:22:07 -080017enum 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
26template <typename T>
27T sk_atomic_load(const T*, sk_memory_order = sk_memory_order_seq_cst);
28
29template <typename T>
30void sk_atomic_store(T*, T, sk_memory_order = sk_memory_order_seq_cst);
31
32template <typename T>
33T sk_atomic_fetch_add(T*, T, sk_memory_order = sk_memory_order_seq_cst);
34
35template <typename T>
herb3667d5b2015-09-16 07:46:17 -070036T sk_atomic_fetch_sub(T*, T, sk_memory_order = sk_memory_order_seq_cst);
37
38template <typename T>
mtkleina669bc72015-02-02 12:22:07 -080039bool 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);
mtklein86821b52015-02-24 14:38:12 -080042
mtklein50ffd992015-03-30 08:13:33 -070043template <typename T>
44T sk_atomic_exchange(T*, T, sk_memory_order = sk_memory_order_seq_cst);
45
mtklein86821b52015-02-24 14:38:12 -080046// 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>.
mtkleinbf905202015-10-07 12:46:43 -070048// !!! Please _really_ know what you're doing if you change default_memory_order. !!!
49template <typename T, sk_memory_order default_memory_order = sk_memory_order_seq_cst>
mtklein86821b52015-02-24 14:38:12 -080050class SkAtomic : SkNoncopyable {
51public:
52 SkAtomic() {}
mtklein942e99b2015-06-17 07:53:22 -070053 explicit SkAtomic(const T& val) : fVal(val) {}
mtklein86821b52015-02-24 14:38:12 -080054
55 // It is essential we return by value rather than by const&. fVal may change at any time.
mtkleinbf905202015-10-07 12:46:43 -070056 T load(sk_memory_order mo = default_memory_order) const {
mtklein86821b52015-02-24 14:38:12 -080057 return sk_atomic_load(&fVal, mo);
58 }
59
mtkleinbf905202015-10-07 12:46:43 -070060 void store(const T& val, sk_memory_order mo = default_memory_order) {
mtklein86821b52015-02-24 14:38:12 -080061 sk_atomic_store(&fVal, val, mo);
62 }
mtklein59c92032015-02-25 12:51:55 -080063
mtkleinbf905202015-10-07 12:46:43 -070064 // Alias for .load(default_memory_order).
herb08692672015-09-28 08:59:18 -070065 operator T() const {
66 return this->load();
67 }
68
mtkleinbf905202015-10-07 12:46:43 -070069 // Alias for .store(v, default_memory_order).
herb08692672015-09-28 08:59:18 -070070 T operator=(const T& v) {
71 this->store(v);
72 return v;
73 }
74
mtkleinbf905202015-10-07 12:46:43 -070075 T fetch_add(const T& val, sk_memory_order mo = default_memory_order) {
mtklein942e99b2015-06-17 07:53:22 -070076 return sk_atomic_fetch_add(&fVal, val, mo);
77 }
78
mtkleinbf905202015-10-07 12:46:43 -070079 T fetch_sub(const T& val, sk_memory_order mo = default_memory_order) {
herb3667d5b2015-09-16 07:46:17 -070080 return sk_atomic_fetch_sub(&fVal, val, mo);
81 }
82
mtklein59c92032015-02-25 12:51:55 -080083 bool compare_exchange(T* expected, const T& desired,
mtkleinbf905202015-10-07 12:46:43 -070084 sk_memory_order success = default_memory_order,
85 sk_memory_order failure = default_memory_order) {
mtklein59c92032015-02-25 12:51:55 -080086 return sk_atomic_compare_exchange(&fVal, expected, desired, success, failure);
87 }
mtklein86821b52015-02-24 14:38:12 -080088private:
89 T fVal;
90};
91
mtklein23267db2015-11-12 11:07:53 -080092// ~~~~~~~~ Implementations ~~~~~~~~~
93
94template <typename T>
95T 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
104template <typename T>
105void 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
113template <typename T>
114T 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
120template <typename T>
121T 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
127template <typename T>
128bool 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
143template <typename T>
144T 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 ~~~~~~~~~
mtkleina64c48f2015-01-21 13:13:31 -0800151
mtkleina669bc72015-02-02 12:22:07 -0800152// 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
mtklein570c8682016-07-27 08:40:45 -0700156inline int32_t sk_atomic_inc(int32_t* ptr) { return sk_atomic_fetch_add(ptr, +1); }
157inline int32_t sk_atomic_dec(int32_t* ptr) { return sk_atomic_fetch_add(ptr, -1); }
mtkleina669bc72015-02-02 12:22:07 -0800158
mtkleina64c48f2015-01-21 13:13:31 -0800159#endif//SkAtomics_DEFINED