summaryrefslogtreecommitdiffstats
path: root/libcxx/test/support/test_atomic.h
blob: 13a0b20250a027cb06bb1dccfc2258aa1b6cda55 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#ifndef SUPPORT_TEST_ATOMIC_H
#define SUPPORT_TEST_ATOMIC_H

// If the atomic memory order macros are defined then assume
// the compiler supports the required atomic builtins.
#if !defined(__ATOMIC_SEQ_CST)
#define TEST_HAS_NO_ATOMICS
#endif

template <class ValType>
class Atomic {
   ValType value;
   Atomic(Atomic const&);
   Atomic& operator=(Atomic const&);
   Atomic& operator=(Atomic const&) volatile;
private:
  enum {
#if !defined(TEST_HAS_NO_ATOMICS)
    AO_Relaxed = __ATOMIC_RELAXED,
    AO_Seq     = __ATOMIC_SEQ_CST
#else
    AO_Relaxed,
    AO_Seq
#endif
  };
  template <class Tp, class FromType>
  static inline void atomic_store_imp(Tp* dest, FromType from, int order = AO_Seq) {
#if !defined(TEST_HAS_NO_ATOMICS)
      __atomic_store_n(dest, from, order);
#else
    *dest = from;
#endif
  }

  template <class Tp>
  static inline Tp atomic_load_imp(Tp* from, int order = AO_Seq) {
#if !defined(TEST_HAS_NO_ATOMICS)
    return __atomic_load_n(from, order);
#else
    return *from;
#endif
  }

  template <class Tp, class AddType>
  static inline Tp atomic_add_imp(Tp* val, AddType add, int order = AO_Seq) {
#if !defined(TEST_HAS_NO_ATOMICS)
      return __atomic_add_fetch(val, add, order);
#else
    return *val += add;
#endif
  }

  template <class Tp>
  static inline Tp atomic_exchange_imp(Tp* val, Tp other, int order = AO_Seq) {
#if !defined(TEST_HAS_NO_ATOMICS)
      return __atomic_exchange_n(val, other, order);
#else
      Tp old = *val;
      *val = other;
      return old;
#endif
  }
public:
    Atomic() : value(0) {}
    Atomic(ValType x) : value(x) {}

    ValType operator=(ValType val) {
       atomic_store_imp(&value, val);
       return val;
    }

    ValType operator=(ValType val) volatile {
        atomic_store_imp(&value, val);
        return val;
    }

    ValType load() const volatile { return atomic_load_imp(&value); }
    void    store(ValType val) volatile { atomic_store_imp(&value, val); }

    ValType relaxedLoad() const volatile { return atomic_load_imp(&value, AO_Relaxed); }
    void    relaxedStore(ValType val) volatile { atomic_store_imp(&value, val, AO_Relaxed); }

    ValType exchange(ValType other) volatile { return atomic_exchange_imp(&value, other); }
    bool    testAndSet() volatile { return atomic_exchange_imp(&value, 1); }
    void    clear() volatile { atomic_store_imp(&value, 0); }

    operator ValType() const { return atomic_load_imp(&value); }
    operator ValType() const volatile { return atomic_load_imp(&value); }

    ValType operator+=(ValType val)  { return atomic_add_imp(&value, val); }
    ValType operator-=(ValType val)  { return atomic_add_imp(&value, -val); }
    ValType operator+=(ValType val) volatile { return atomic_add_imp(&value, val); }
    ValType operator-=(ValType val) volatile { return atomic_add_imp(&value, -val); }

    ValType operator++()  { return *this += 1; }
    ValType operator++(int) { return (*this += 1) - 1;  }
    ValType operator++() volatile { return *this += 1; }
    ValType operator++(int) volatile { return (*this += 1) - 1;  }

    ValType operator--() { return *this -= 1; }
    ValType operator--(int) { return (*this -= 1) + 1; }
    ValType operator--() volatile { return *this -= 1; }
    ValType operator--(int) volatile { return (*this -= 1) + 1; }
};

typedef Atomic<int> AtomicInt;
typedef Atomic<bool> AtomicBool;

#endif // SUPPORT_TEST_ATOMIC_H
OpenPOWER on IntegriCloud