sanitizer_atomic.h revision a3eca8192505f4796194dd24eb051019f402de99
1//===-- sanitizer_atomic.h --------------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of ThreadSanitizer/AddressSanitizer runtime.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef SANITIZER_ATOMIC_H
15#define SANITIZER_ATOMIC_H
16
17#include "sanitizer_internal_defs.h"
18
19namespace __sanitizer {
20
21enum memory_order {
22  memory_order_relaxed = 1 << 0,
23  memory_order_consume = 1 << 1,
24  memory_order_acquire = 1 << 2,
25  memory_order_release = 1 << 3,
26  memory_order_acq_rel = 1 << 4,
27  memory_order_seq_cst = 1 << 5,
28};
29
30struct atomic_uint8_t {
31  typedef u8 Type;
32  volatile Type val_dont_use;
33};
34
35struct atomic_uint16_t {
36  typedef u16 Type;
37  volatile Type val_dont_use;
38};
39
40struct atomic_uint32_t {
41  typedef u32 Type;
42  volatile Type val_dont_use;
43};
44
45struct atomic_uint64_t {
46  typedef u64 Type;
47  volatile Type val_dont_use;
48};
49
50struct atomic_uintptr_t {
51  typedef uptr Type;
52  volatile Type val_dont_use;
53};
54
55INLINE void atomic_signal_fence(memory_order) {
56  __asm__ __volatile__("" ::: "memory");
57}
58
59INLINE void atomic_thread_fence(memory_order) {
60  __sync_synchronize();
61}
62
63INLINE void proc_yield(int cnt) {
64  __asm__ __volatile__("" ::: "memory");
65#if defined(__i386__) || defined(__x86_64__)
66  for (int i = 0; i < cnt; i++)
67    __asm__ __volatile__("pause");
68#endif
69  __asm__ __volatile__("" ::: "memory");
70}
71
72template<typename T>
73INLINE typename T::Type atomic_load(
74    const volatile T *a, memory_order mo) {
75  DCHECK(mo & (memory_order_relaxed | memory_order_consume
76      | memory_order_acquire | memory_order_seq_cst));
77  DCHECK(!((uptr)a % sizeof(*a)));
78  typename T::Type v;
79  if (mo == memory_order_relaxed) {
80    v = a->val_dont_use;
81  } else {
82    atomic_signal_fence(memory_order_seq_cst);
83    v = a->val_dont_use;
84    atomic_signal_fence(memory_order_seq_cst);
85  }
86  return v;
87}
88
89template<typename T>
90INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
91  DCHECK(mo & (memory_order_relaxed | memory_order_release
92      | memory_order_seq_cst));
93  DCHECK(!((uptr)a % sizeof(*a)));
94  if (mo == memory_order_relaxed) {
95    a->val_dont_use = v;
96  } else {
97    atomic_signal_fence(memory_order_seq_cst);
98    a->val_dont_use = v;
99    atomic_signal_fence(memory_order_seq_cst);
100  }
101  if (mo == memory_order_seq_cst)
102    atomic_thread_fence(memory_order_seq_cst);
103}
104
105template<typename T>
106INLINE typename T::Type atomic_fetch_add(volatile T *a,
107    typename T::Type v, memory_order mo) {
108  (void)mo;
109  DCHECK(!((uptr)a % sizeof(*a)));
110  return __sync_fetch_and_add(&a->val_dont_use, v);
111}
112
113template<typename T>
114INLINE typename T::Type atomic_fetch_sub(volatile T *a,
115    typename T::Type v, memory_order mo) {
116  (void)mo;
117  DCHECK(!((uptr)a % sizeof(*a)));
118  return __sync_fetch_and_add(&a->val_dont_use, -v);
119}
120
121template<typename T>
122INLINE typename T::Type atomic_exchange(volatile T *a,
123    typename T::Type v, memory_order mo) {
124  DCHECK(!((uptr)a % sizeof(*a)));
125  if (mo & (memory_order_release | memory_order_acq_rel | memory_order_seq_cst))
126    __sync_synchronize();
127  v = __sync_lock_test_and_set(&a->val_dont_use, v);
128  if (mo == memory_order_seq_cst)
129    __sync_synchronize();
130  return v;
131}
132
133template<typename T>
134INLINE bool atomic_compare_exchange_strong(volatile T *a,
135                                           typename T::Type *cmp,
136                                           typename T::Type xchg,
137                                           memory_order mo) {
138  typedef typename T::Type Type;
139  Type cmpv = *cmp;
140  Type prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg);
141  if (prev == cmpv)
142    return true;
143  *cmp = prev;
144  return false;
145}
146
147template<typename T>
148INLINE bool atomic_compare_exchange_weak(volatile T *a,
149                                           typename T::Type *cmp,
150                                           typename T::Type xchg,
151                                           memory_order mo) {
152  return atomic_compare_exchange_strong(a, cmp, xchg, mo);
153}
154
155}  // namespace __sanitizer
156
157#endif  // SANITIZER_ATOMIC_H
158