150ffd9921e6dc82cae8ef143e8cecfd8bcf900fbmtklein/*
250ffd9921e6dc82cae8ef143e8cecfd8bcf900fbmtklein * Copyright 2015 Google Inc.
350ffd9921e6dc82cae8ef143e8cecfd8bcf900fbmtklein *
450ffd9921e6dc82cae8ef143e8cecfd8bcf900fbmtklein * Use of this source code is governed by a BSD-style license that can be
550ffd9921e6dc82cae8ef143e8cecfd8bcf900fbmtklein * found in the LICENSE file.
650ffd9921e6dc82cae8ef143e8cecfd8bcf900fbmtklein */
750ffd9921e6dc82cae8ef143e8cecfd8bcf900fbmtklein
8a64c48f4f929775f9c203aae809f440ac01d2c64mtklein#ifndef SkAtomics_DEFINED
9a64c48f4f929775f9c203aae809f440ac01d2c64mtklein#define SkAtomics_DEFINED
10a64c48f4f929775f9c203aae809f440ac01d2c64mtklein
11a64c48f4f929775f9c203aae809f440ac01d2c64mtklein// This file is not part of the public Skia API.
12a64c48f4f929775f9c203aae809f440ac01d2c64mtklein#include "SkTypes.h"
13a64c48f4f929775f9c203aae809f440ac01d2c64mtklein
14a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleinenum sk_memory_order {
15a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein    sk_memory_order_relaxed,
16a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein    sk_memory_order_consume,
17a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein    sk_memory_order_acquire,
18a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein    sk_memory_order_release,
19a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein    sk_memory_order_acq_rel,
20a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein    sk_memory_order_seq_cst,
21a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein};
22a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein
23a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleintemplate <typename T>
24a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleinT sk_atomic_load(const T*, sk_memory_order = sk_memory_order_seq_cst);
25a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein
26a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleintemplate <typename T>
27a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleinvoid sk_atomic_store(T*, T, sk_memory_order = sk_memory_order_seq_cst);
28a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein
29a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleintemplate <typename T>
30a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleinT sk_atomic_fetch_add(T*, T, sk_memory_order = sk_memory_order_seq_cst);
31a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein
32a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleintemplate <typename T>
33a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleinbool sk_atomic_compare_exchange(T*, T* expected, T desired,
34a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein                                sk_memory_order success = sk_memory_order_seq_cst,
35a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein                                sk_memory_order failure = sk_memory_order_seq_cst);
3686821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein
3750ffd9921e6dc82cae8ef143e8cecfd8bcf900fbmtkleintemplate <typename T>
3850ffd9921e6dc82cae8ef143e8cecfd8bcf900fbmtkleinT sk_atomic_exchange(T*, T, sk_memory_order = sk_memory_order_seq_cst);
3950ffd9921e6dc82cae8ef143e8cecfd8bcf900fbmtklein
4086821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein// A little wrapper class for small T (think, builtins: int, float, void*) to
4186821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein// ensure they're always used atomically.  This is our stand-in for std::atomic<T>.
4286821b56704ebc0a1a6d1e5d1e329369ac797c98mtkleintemplate <typename T>
4386821b56704ebc0a1a6d1e5d1e329369ac797c98mtkleinclass SkAtomic : SkNoncopyable {
4486821b56704ebc0a1a6d1e5d1e329369ac797c98mtkleinpublic:
4586821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein    SkAtomic() {}
4686821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein
4786821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein    // It is essential we return by value rather than by const&.  fVal may change at any time.
4886821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein    T load(sk_memory_order mo = sk_memory_order_seq_cst) const {
4986821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein        return sk_atomic_load(&fVal, mo);
5086821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein    }
5186821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein
5286821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein    void store(const T& val, sk_memory_order mo = sk_memory_order_seq_cst) {
5386821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein        sk_atomic_store(&fVal, val, mo);
5486821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein    }
5559c9203321cf4afb48597f39e4bdd4ae91da12a0mtklein
5659c9203321cf4afb48597f39e4bdd4ae91da12a0mtklein    bool compare_exchange(T* expected, const T& desired,
5759c9203321cf4afb48597f39e4bdd4ae91da12a0mtklein                          sk_memory_order success = sk_memory_order_seq_cst,
5859c9203321cf4afb48597f39e4bdd4ae91da12a0mtklein                          sk_memory_order failure = sk_memory_order_seq_cst) {
5959c9203321cf4afb48597f39e4bdd4ae91da12a0mtklein        return sk_atomic_compare_exchange(&fVal, expected, desired, success, failure);
6059c9203321cf4afb48597f39e4bdd4ae91da12a0mtklein    }
6186821b56704ebc0a1a6d1e5d1e329369ac797c98mtkleinprivate:
6286821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein    T fVal;
6386821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein};
6486821b56704ebc0a1a6d1e5d1e329369ac797c98mtklein
65a64c48f4f929775f9c203aae809f440ac01d2c64mtklein#if defined(_MSC_VER)
66a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein    #include "../ports/SkAtomics_std.h"
67a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein#elif !defined(SK_BUILD_FOR_IOS) && defined(__ATOMIC_RELAXED)
68a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein    #include "../ports/SkAtomics_atomic.h"
69a64c48f4f929775f9c203aae809f440ac01d2c64mtklein#else
70a64c48f4f929775f9c203aae809f440ac01d2c64mtklein    #include "../ports/SkAtomics_sync.h"
71a64c48f4f929775f9c203aae809f440ac01d2c64mtklein#endif
72a64c48f4f929775f9c203aae809f440ac01d2c64mtklein
73a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein// From here down we have shims for our old atomics API, to be weaned off of.
74a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein// We use the default sequentially-consistent memory order to make things simple
75a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein// and to match the practical reality of our old _sync and _win implementations.
76a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein
77a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleininline int32_t sk_atomic_inc(int32_t* ptr)            { return sk_atomic_fetch_add(ptr, +1); }
78a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleininline int32_t sk_atomic_dec(int32_t* ptr)            { return sk_atomic_fetch_add(ptr, -1); }
79a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleininline int32_t sk_atomic_add(int32_t* ptr, int32_t v) { return sk_atomic_fetch_add(ptr,  v); }
80a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein
81a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleininline int64_t sk_atomic_inc(int64_t* ptr) { return sk_atomic_fetch_add<int64_t>(ptr, +1); }
82a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein
83a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleininline bool sk_atomic_cas(int32_t* ptr, int32_t expected, int32_t desired) {
84a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein    return sk_atomic_compare_exchange(ptr, &expected, desired);
85a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein}
86a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein
87a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleininline void* sk_atomic_cas(void** ptr, void* expected, void* desired) {
88a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein    (void)sk_atomic_compare_exchange(ptr, &expected, desired);
89a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein    return expected;
90a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein}
91a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein
92a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleininline int32_t sk_atomic_conditional_inc(int32_t* ptr) {
93a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein    int32_t prev = sk_atomic_load(ptr);
94a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein    do {
95a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein        if (0 == prev) {
96a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein            break;
97a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein        }
98a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein    } while(!sk_atomic_compare_exchange(ptr, &prev, prev+1));
99a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein    return prev;
100a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein}
101a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein
102a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleintemplate <typename T>
103a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleinT sk_acquire_load(T* ptr) { return sk_atomic_load(ptr, sk_memory_order_acquire); }
104a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein
105a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleintemplate <typename T>
106a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleinvoid sk_release_store(T* ptr, T val) { sk_atomic_store(ptr, val, sk_memory_order_release); }
107a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein
108a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleininline void sk_membar_acquire__after_atomic_dec() {}
109a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtkleininline void sk_membar_acquire__after_atomic_conditional_inc() {}
110a669bc7a7ae7580c5cd92067aeb95d09e64ea720mtklein
111a64c48f4f929775f9c203aae809f440ac01d2c64mtklein#endif//SkAtomics_DEFINED
112