1 //===-- sanitizer_atomic_clang_other.h --------------------------*- C++ -*-===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // This file is a part of ThreadSanitizer/AddressSanitizer runtime.
9 // Not intended for direct inclusion. Include sanitizer_atomic.h.
11 //===----------------------------------------------------------------------===//
13 #ifndef SANITIZER_ATOMIC_CLANG_OTHER_H
14 #define SANITIZER_ATOMIC_CLANG_OTHER_H
16 namespace __sanitizer
{
18 // MIPS32 does not support atomic > 4 bytes. To address this lack of
19 // functionality, the sanitizer library provides helper methods which use an
20 // internal spin lock mechanism to emulate atomic oprations when the size is
22 #if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32
23 static void __spin_lock(volatile int *lock
) {
24 while (__sync_lock_test_and_set(lock
, 1))
29 static void __spin_unlock(volatile int *lock
) { __sync_lock_release(lock
); }
32 // Make sure the lock is on its own cache line to prevent false sharing.
33 // Put it inside a struct that is aligned and padded to the typical MIPS
34 // cacheline which is 32 bytes.
37 char pad
[32 - sizeof(int)];
38 } __attribute__((aligned(32))) lock
= {0};
41 T
__mips_sync_fetch_and_add(volatile T
*ptr
, T val
) {
44 __spin_lock(&lock
.lock
);
49 __spin_unlock(&lock
.lock
);
55 T
__mips_sync_val_compare_and_swap(volatile T
*ptr
, T oldval
, T newval
) {
57 __spin_lock(&lock
.lock
);
60 if (ret
== oldval
) *ptr
= newval
;
62 __spin_unlock(&lock
.lock
);
68 INLINE
void proc_yield(int cnt
) {
69 __asm__
__volatile__("" ::: "memory");
73 INLINE 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
)));
80 if (sizeof(*a
) < 8 || sizeof(void*) == 8) {
81 // Assume that aligned loads are atomic.
82 if (mo
== memory_order_relaxed
) {
84 } else if (mo
== memory_order_consume
) {
85 // Assume that processor respects data dependencies
86 // (and that compiler won't break them).
87 __asm__
__volatile__("" ::: "memory");
89 __asm__
__volatile__("" ::: "memory");
90 } else if (mo
== memory_order_acquire
) {
91 __asm__
__volatile__("" ::: "memory");
95 // E.g. on POWER we need a hw fence even before the store.
101 // 64-bit load on 32-bit platform.
102 // Gross, but simple and reliable.
103 // Assume that it is not in read-only memory.
104 #if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32
105 typename
T::Type
volatile *val_ptr
=
106 const_cast<typename
T::Type
volatile *>(&a
->val_dont_use
);
107 v
= __mips_sync_fetch_and_add
<u64
>(
108 reinterpret_cast<u64
volatile *>(val_ptr
), 0);
110 v
= __sync_fetch_and_add(
111 const_cast<typename
T::Type
volatile *>(&a
->val_dont_use
), 0);
118 INLINE
void atomic_store(volatile T
*a
, typename
T::Type v
, memory_order mo
) {
119 DCHECK(mo
& (memory_order_relaxed
| memory_order_release
120 | memory_order_seq_cst
));
121 DCHECK(!((uptr
)a
% sizeof(*a
)));
123 if (sizeof(*a
) < 8 || sizeof(void*) == 8) {
124 // Assume that aligned loads are atomic.
125 if (mo
== memory_order_relaxed
) {
127 } else if (mo
== memory_order_release
) {
128 __sync_synchronize();
130 __asm__
__volatile__("" ::: "memory");
132 __sync_synchronize();
134 __sync_synchronize();
137 // 64-bit store on 32-bit platform.
138 // Gross, but simple and reliable.
139 typename
T::Type cmp
= a
->val_dont_use
;
140 typename
T::Type cur
;
142 #if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32
143 typename
T::Type
volatile *val_ptr
=
144 const_cast<typename
T::Type
volatile *>(&a
->val_dont_use
);
145 cur
= __mips_sync_val_compare_and_swap
<u64
>(
146 reinterpret_cast<u64
volatile *>(val_ptr
), (u64
)cmp
, (u64
)v
);
148 cur
= __sync_val_compare_and_swap(&a
->val_dont_use
, cmp
, v
);
157 } // namespace __sanitizer
159 #endif // #ifndef SANITIZER_ATOMIC_CLANG_OTHER_H