sanitizer_atomic_msvc.h revision 5d71de26cedae3dafc17449fe0182045c0bd20e8
1//===-- sanitizer_atomic_msvc.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// Not intended for direct inclusion. Include sanitizer_atomic.h. 12// 13//===----------------------------------------------------------------------===// 14 15#ifndef SANITIZER_ATOMIC_MSVC_H 16#define SANITIZER_ATOMIC_MSVC_H 17 18extern "C" void _ReadWriteBarrier(); 19#pragma intrinsic(_ReadWriteBarrier) 20extern "C" void _mm_mfence(); 21#pragma intrinsic(_mm_mfence) 22extern "C" void _mm_pause(); 23#pragma intrinsic(_mm_pause) 24extern "C" long _InterlockedExchangeAdd( // NOLINT 25 long volatile * Addend, long Value); // NOLINT 26#pragma intrinsic(_InterlockedExchangeAdd) 27extern "C" short _InterlockedCompareExchange16( // NOLINT 28 short volatile *Destination, // NOLINT 29 short Exchange, short Comparand); // NOLINT 30#pragma intrinsic(_InterlockedCompareExchange16) 31extern "C" 32long long _InterlockedCompareExchange64( // NOLINT 33 long long volatile *Destination, // NOLINT 34 long long Exchange, long long Comparand); // NOLINT 35#pragma intrinsic(_InterlockedCompareExchange64) 36extern "C" void *_InterlockedCompareExchangePointer( 37 void *volatile *Destination, 38 void *Exchange, void *Comparand); 39#pragma intrinsic(_InterlockedCompareExchangePointer) 40extern "C" 41long __cdecl _InterlockedCompareExchange( // NOLINT 42 long volatile *Destination, // NOLINT 43 long Exchange, long Comparand); // NOLINT 44#pragma intrinsic(_InterlockedCompareExchange) 45 46#ifdef _WIN64 47extern "C" long long _InterlockedExchangeAdd64( // NOLINT 48 long long volatile * Addend, long long Value); // NOLINT 49#pragma intrinsic(_InterlockedExchangeAdd64) 50#endif 51 52namespace __sanitizer { 53 54INLINE void atomic_signal_fence(memory_order) { 55 _ReadWriteBarrier(); 56} 57 58INLINE void atomic_thread_fence(memory_order) { 59 _mm_mfence(); 60} 61 62INLINE void proc_yield(int cnt) { 63 for (int i = 0; i < cnt; i++) 64 _mm_pause(); 65} 66 67template<typename T> 68INLINE typename T::Type atomic_load( 69 const volatile T *a, memory_order mo) { 70 DCHECK(mo & (memory_order_relaxed | memory_order_consume 71 | memory_order_acquire | memory_order_seq_cst)); 72 DCHECK(!((uptr)a % sizeof(*a))); 73 typename T::Type v; 74 // FIXME(dvyukov): 64-bit load is not atomic on 32-bits. 75 if (mo == memory_order_relaxed) { 76 v = a->val_dont_use; 77 } else { 78 atomic_signal_fence(memory_order_seq_cst); 79 v = a->val_dont_use; 80 atomic_signal_fence(memory_order_seq_cst); 81 } 82 return v; 83} 84 85template<typename T> 86INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) { 87 DCHECK(mo & (memory_order_relaxed | memory_order_release 88 | memory_order_seq_cst)); 89 DCHECK(!((uptr)a % sizeof(*a))); 90 // FIXME(dvyukov): 64-bit store is not atomic on 32-bits. 91 if (mo == memory_order_relaxed) { 92 a->val_dont_use = v; 93 } else { 94 atomic_signal_fence(memory_order_seq_cst); 95 a->val_dont_use = v; 96 atomic_signal_fence(memory_order_seq_cst); 97 } 98 if (mo == memory_order_seq_cst) 99 atomic_thread_fence(memory_order_seq_cst); 100} 101 102INLINE u32 atomic_fetch_add(volatile atomic_uint32_t *a, 103 u32 v, memory_order mo) { 104 (void)mo; 105 DCHECK(!((uptr)a % sizeof(*a))); 106 return (u32)_InterlockedExchangeAdd( 107 (volatile long*)&a->val_dont_use, (long)v); // NOLINT 108} 109 110INLINE uptr atomic_fetch_add(volatile atomic_uintptr_t *a, 111 uptr v, memory_order mo) { 112 (void)mo; 113 DCHECK(!((uptr)a % sizeof(*a))); 114#ifdef _WIN64 115 return (uptr)_InterlockedExchangeAdd64( 116 (volatile long long*)&a->val_dont_use, (long long)v); // NOLINT 117#else 118 return (uptr)_InterlockedExchangeAdd( 119 (volatile long*)&a->val_dont_use, (long)v); // NOLINT 120#endif 121} 122 123INLINE u32 atomic_fetch_sub(volatile atomic_uint32_t *a, 124 u32 v, memory_order mo) { 125 (void)mo; 126 DCHECK(!((uptr)a % sizeof(*a))); 127 return (u32)_InterlockedExchangeAdd( 128 (volatile long*)&a->val_dont_use, -(long)v); // NOLINT 129} 130 131INLINE uptr atomic_fetch_sub(volatile atomic_uintptr_t *a, 132 uptr v, memory_order mo) { 133 (void)mo; 134 DCHECK(!((uptr)a % sizeof(*a))); 135#ifdef _WIN64 136 return (uptr)_InterlockedExchangeAdd64( 137 (volatile long long*)&a->val_dont_use, -(long long)v); // NOLINT 138#else 139 return (uptr)_InterlockedExchangeAdd( 140 (volatile long*)&a->val_dont_use, -(long)v); // NOLINT 141#endif 142} 143 144INLINE u8 atomic_exchange(volatile atomic_uint8_t *a, 145 u8 v, memory_order mo) { 146 (void)mo; 147 DCHECK(!((uptr)a % sizeof(*a))); 148 __asm { 149 mov eax, a 150 mov cl, v 151 xchg [eax], cl // NOLINT 152 mov v, cl 153 } 154 return v; 155} 156 157INLINE u16 atomic_exchange(volatile atomic_uint16_t *a, 158 u16 v, memory_order mo) { 159 (void)mo; 160 DCHECK(!((uptr)a % sizeof(*a))); 161 __asm { 162 mov eax, a 163 mov cx, v 164 xchg [eax], cx // NOLINT 165 mov v, cx 166 } 167 return v; 168} 169 170INLINE bool atomic_compare_exchange_strong(volatile atomic_uint8_t *a, 171 u8 *cmp, 172 u8 xchgv, 173 memory_order mo) { 174 (void)mo; 175 DCHECK(!((uptr)a % sizeof(*a))); 176 u8 cmpv = *cmp; 177 u8 prev; 178 __asm { 179 mov al, cmpv 180 mov ecx, a 181 mov dl, xchgv 182 lock cmpxchg [ecx], dl 183 mov prev, al 184 } 185 if (prev == cmpv) 186 return true; 187 *cmp = prev; 188 return false; 189} 190 191INLINE bool atomic_compare_exchange_strong(volatile atomic_uintptr_t *a, 192 uptr *cmp, 193 uptr xchg, 194 memory_order mo) { 195 uptr cmpv = *cmp; 196 uptr prev = (uptr)_InterlockedCompareExchangePointer( 197 (void*volatile*)&a->val_dont_use, (void*)xchg, (void*)cmpv); 198 if (prev == cmpv) 199 return true; 200 *cmp = prev; 201 return false; 202} 203 204INLINE bool atomic_compare_exchange_strong(volatile atomic_uint16_t *a, 205 u16 *cmp, 206 u16 xchg, 207 memory_order mo) { 208 u16 cmpv = *cmp; 209 u16 prev = (u16)_InterlockedCompareExchange16( 210 (volatile short*)&a->val_dont_use, (short)xchg, (short)cmpv); 211 if (prev == cmpv) 212 return true; 213 *cmp = prev; 214 return false; 215} 216 217INLINE bool atomic_compare_exchange_strong(volatile atomic_uint32_t *a, 218 u32 *cmp, 219 u32 xchg, 220 memory_order mo) { 221 u32 cmpv = *cmp; 222 u32 prev = (u32)_InterlockedCompareExchange( 223 (volatile long*)&a->val_dont_use, (long)xchg, (long)cmpv); 224 if (prev == cmpv) 225 return true; 226 *cmp = prev; 227 return false; 228} 229 230INLINE bool atomic_compare_exchange_strong(volatile atomic_uint64_t *a, 231 u64 *cmp, 232 u64 xchg, 233 memory_order mo) { 234 u64 cmpv = *cmp; 235 u64 prev = (u64)_InterlockedCompareExchange64( 236 (volatile long long*)&a->val_dont_use, (long long)xchg, (long long)cmpv); 237 if (prev == cmpv) 238 return true; 239 *cmp = prev; 240 return false; 241} 242 243template<typename T> 244INLINE bool atomic_compare_exchange_weak(volatile T *a, 245 typename T::Type *cmp, 246 typename T::Type xchg, 247 memory_order mo) { 248 return atomic_compare_exchange_strong(a, cmp, xchg, mo); 249} 250 251} // namespace __sanitizer 252 253#endif // SANITIZER_ATOMIC_CLANG_H 254