1 /*===-- atomic.c - Implement support functions for atomic operations.------=== 2 * 3 * Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 * See https://llvm.org/LICENSE.txt for license information. 5 * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 * 7 *===----------------------------------------------------------------------=== 8 * 9 * atomic.c defines a set of functions for performing atomic accesses on 10 * arbitrary-sized memory locations. This design uses locks that should 11 * be fast in the uncontended case, for two reasons: 12 * 13 * 1) This code must work with C programs that do not link to anything 14 * (including pthreads) and so it should not depend on any pthread 15 * functions. 16 * 2) Atomic operations, rather than explicit mutexes, are most commonly used 17 * on code where contended operations are rate. 18 * 19 * To avoid needing a per-object lock, this code allocates an array of 20 * locks and hashes the object pointers to find the one that it should use. 21 * For operations that must be atomic on two locations, the lower lock is 22 * always acquired first, to avoid deadlock. 23 * 24 *===----------------------------------------------------------------------=== 25 */ 26 27 #include <stdint.h> 28 #include <string.h> 29 30 #include "assembly.h" 31 32 // Clang objects if you redefine a builtin. This little hack allows us to 33 // define a function with the same name as an intrinsic. 34 #pragma redefine_extname __atomic_load_c SYMBOL_NAME(__atomic_load) 35 #pragma redefine_extname __atomic_store_c SYMBOL_NAME(__atomic_store) 36 #pragma redefine_extname __atomic_exchange_c SYMBOL_NAME(__atomic_exchange) 37 #pragma redefine_extname __atomic_compare_exchange_c SYMBOL_NAME(__atomic_compare_exchange) 38 39 /// Number of locks. This allocates one page on 32-bit platforms, two on 40 /// 64-bit. This can be specified externally if a different trade between 41 /// memory usage and contention probability is required for a given platform. 42 #ifndef SPINLOCK_COUNT 43 #define SPINLOCK_COUNT (1<<10) 44 #endif 45 static const long SPINLOCK_MASK = SPINLOCK_COUNT - 1; 46 47 //////////////////////////////////////////////////////////////////////////////// 48 // Platform-specific lock implementation. Falls back to spinlocks if none is 49 // defined. Each platform should define the Lock type, and corresponding 50 // lock() and unlock() functions. 51 //////////////////////////////////////////////////////////////////////////////// 52 #ifdef __FreeBSD__ 53 #include <errno.h> 54 #include <sys/types.h> 55 #include <machine/atomic.h> 56 #include <sys/umtx.h> 57 typedef struct _usem Lock; 58 __inline static void unlock(Lock *l) { 59 __c11_atomic_store((_Atomic(uint32_t)*)&l->_count, 1, __ATOMIC_RELEASE); 60 __c11_atomic_thread_fence(__ATOMIC_SEQ_CST); 61 if (l->_has_waiters) 62 _umtx_op(l, UMTX_OP_SEM_WAKE, 1, 0, 0); 63 } 64 __inline static void lock(Lock *l) { 65 uint32_t old = 1; 66 while (!__c11_atomic_compare_exchange_weak((_Atomic(uint32_t)*)&l->_count, &old, 67 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { 68 _umtx_op(l, UMTX_OP_SEM_WAIT, 0, 0, 0); 69 old = 1; 70 } 71 } 72 /// locks for atomic operations 73 static Lock locks[SPINLOCK_COUNT] = { [0 ... SPINLOCK_COUNT-1] = {0,1,0} }; 74 75 #elif defined(__APPLE__) 76 #include <libkern/OSAtomic.h> 77 typedef OSSpinLock Lock; 78 __inline static void unlock(Lock *l) { 79 OSSpinLockUnlock(l); 80 } 81 /// Locks a lock. In the current implementation, this is potentially 82 /// unbounded in the contended case. 83 __inline static void lock(Lock *l) { 84 OSSpinLockLock(l); 85 } 86 static Lock locks[SPINLOCK_COUNT]; // initialized to OS_SPINLOCK_INIT which is 0 87 88 #else 89 typedef _Atomic(uintptr_t) Lock; 90 /// Unlock a lock. This is a release operation. 91 __inline static void unlock(Lock *l) { 92 __c11_atomic_store(l, 0, __ATOMIC_RELEASE); 93 } 94 /// Locks a lock. In the current implementation, this is potentially 95 /// unbounded in the contended case. 96 __inline static void lock(Lock *l) { 97 uintptr_t old = 0; 98 while (!__c11_atomic_compare_exchange_weak(l, &old, 1, __ATOMIC_ACQUIRE, 99 __ATOMIC_RELAXED)) 100 old = 0; 101 } 102 /// locks for atomic operations 103 static Lock locks[SPINLOCK_COUNT]; 104 #endif 105 106 107 /// Returns a lock to use for a given pointer. 108 static __inline Lock *lock_for_pointer(void *ptr) { 109 intptr_t hash = (intptr_t)ptr; 110 // Disregard the lowest 4 bits. We want all values that may be part of the 111 // same memory operation to hash to the same value and therefore use the same 112 // lock. 113 hash >>= 4; 114 // Use the next bits as the basis for the hash 115 intptr_t low = hash & SPINLOCK_MASK; 116 // Now use the high(er) set of bits to perturb the hash, so that we don't 117 // get collisions from atomic fields in a single object 118 hash >>= 16; 119 hash ^= low; 120 // Return a pointer to the word to use 121 return locks + (hash & SPINLOCK_MASK); 122 } 123 124 /// Macros for determining whether a size is lock free. Clang can not yet 125 /// codegen __atomic_is_lock_free(16), so for now we assume 16-byte values are 126 /// not lock free. 127 #define IS_LOCK_FREE_1 __c11_atomic_is_lock_free(1) 128 #define IS_LOCK_FREE_2 __c11_atomic_is_lock_free(2) 129 #define IS_LOCK_FREE_4 __c11_atomic_is_lock_free(4) 130 #define IS_LOCK_FREE_8 __c11_atomic_is_lock_free(8) 131 #define IS_LOCK_FREE_16 0 132 133 /// Macro that calls the compiler-generated lock-free versions of functions 134 /// when they exist. 135 #define LOCK_FREE_CASES() \ 136 do {\ 137 switch (size) {\ 138 case 1:\ 139 if (IS_LOCK_FREE_1) {\ 140 LOCK_FREE_ACTION(uint8_t);\ 141 }\ 142 break; \ 143 case 2:\ 144 if (IS_LOCK_FREE_2) {\ 145 LOCK_FREE_ACTION(uint16_t);\ 146 }\ 147 break; \ 148 case 4:\ 149 if (IS_LOCK_FREE_4) {\ 150 LOCK_FREE_ACTION(uint32_t);\ 151 }\ 152 break; \ 153 case 8:\ 154 if (IS_LOCK_FREE_8) {\ 155 LOCK_FREE_ACTION(uint64_t);\ 156 }\ 157 break; \ 158 case 16:\ 159 if (IS_LOCK_FREE_16) {\ 160 /* FIXME: __uint128_t isn't available on 32 bit platforms. 161 LOCK_FREE_ACTION(__uint128_t);*/\ 162 }\ 163 break; \ 164 }\ 165 } while (0) 166 167 168 /// An atomic load operation. This is atomic with respect to the source 169 /// pointer only. 170 void __atomic_load_c(int size, void *src, void *dest, int model) { 171 #define LOCK_FREE_ACTION(type) \ 172 *((type*)dest) = __c11_atomic_load((_Atomic(type)*)src, model);\ 173 return; 174 LOCK_FREE_CASES(); 175 #undef LOCK_FREE_ACTION 176 Lock *l = lock_for_pointer(src); 177 lock(l); 178 memcpy(dest, src, size); 179 unlock(l); 180 } 181 182 /// An atomic store operation. This is atomic with respect to the destination 183 /// pointer only. 184 void __atomic_store_c(int size, void *dest, void *src, int model) { 185 #define LOCK_FREE_ACTION(type) \ 186 __c11_atomic_store((_Atomic(type)*)dest, *(type*)src, model);\ 187 return; 188 LOCK_FREE_CASES(); 189 #undef LOCK_FREE_ACTION 190 Lock *l = lock_for_pointer(dest); 191 lock(l); 192 memcpy(dest, src, size); 193 unlock(l); 194 } 195 196 /// Atomic compare and exchange operation. If the value at *ptr is identical 197 /// to the value at *expected, then this copies value at *desired to *ptr. If 198 /// they are not, then this stores the current value from *ptr in *expected. 199 /// 200 /// This function returns 1 if the exchange takes place or 0 if it fails. 201 int __atomic_compare_exchange_c(int size, void *ptr, void *expected, 202 void *desired, int success, int failure) { 203 #define LOCK_FREE_ACTION(type) \ 204 return __c11_atomic_compare_exchange_strong((_Atomic(type)*)ptr, (type*)expected,\ 205 *(type*)desired, success, failure) 206 LOCK_FREE_CASES(); 207 #undef LOCK_FREE_ACTION 208 Lock *l = lock_for_pointer(ptr); 209 lock(l); 210 if (memcmp(ptr, expected, size) == 0) { 211 memcpy(ptr, desired, size); 212 unlock(l); 213 return 1; 214 } 215 memcpy(expected, ptr, size); 216 unlock(l); 217 return 0; 218 } 219 220 /// Performs an atomic exchange operation between two pointers. This is atomic 221 /// with respect to the target address. 222 void __atomic_exchange_c(int size, void *ptr, void *val, void *old, int model) { 223 #define LOCK_FREE_ACTION(type) \ 224 *(type*)old = __c11_atomic_exchange((_Atomic(type)*)ptr, *(type*)val,\ 225 model);\ 226 return; 227 LOCK_FREE_CASES(); 228 #undef LOCK_FREE_ACTION 229 Lock *l = lock_for_pointer(ptr); 230 lock(l); 231 memcpy(old, ptr, size); 232 memcpy(ptr, val, size); 233 unlock(l); 234 } 235 236 //////////////////////////////////////////////////////////////////////////////// 237 // Where the size is known at compile time, the compiler may emit calls to 238 // specialised versions of the above functions. 239 //////////////////////////////////////////////////////////////////////////////// 240 #ifdef __SIZEOF_INT128__ 241 #define OPTIMISED_CASES\ 242 OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t)\ 243 OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t)\ 244 OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t)\ 245 OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t)\ 246 OPTIMISED_CASE(16, IS_LOCK_FREE_16, __uint128_t) 247 #else 248 #define OPTIMISED_CASES\ 249 OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t)\ 250 OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t)\ 251 OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t)\ 252 OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t) 253 #endif 254 255 #define OPTIMISED_CASE(n, lockfree, type)\ 256 type __atomic_load_##n(type *src, int model) {\ 257 if (lockfree)\ 258 return __c11_atomic_load((_Atomic(type)*)src, model);\ 259 Lock *l = lock_for_pointer(src);\ 260 lock(l);\ 261 type val = *src;\ 262 unlock(l);\ 263 return val;\ 264 } 265 OPTIMISED_CASES 266 #undef OPTIMISED_CASE 267 268 #define OPTIMISED_CASE(n, lockfree, type)\ 269 void __atomic_store_##n(type *dest, type val, int model) {\ 270 if (lockfree) {\ 271 __c11_atomic_store((_Atomic(type)*)dest, val, model);\ 272 return;\ 273 }\ 274 Lock *l = lock_for_pointer(dest);\ 275 lock(l);\ 276 *dest = val;\ 277 unlock(l);\ 278 return;\ 279 } 280 OPTIMISED_CASES 281 #undef OPTIMISED_CASE 282 283 #define OPTIMISED_CASE(n, lockfree, type)\ 284 type __atomic_exchange_##n(type *dest, type val, int model) {\ 285 if (lockfree)\ 286 return __c11_atomic_exchange((_Atomic(type)*)dest, val, model);\ 287 Lock *l = lock_for_pointer(dest);\ 288 lock(l);\ 289 type tmp = *dest;\ 290 *dest = val;\ 291 unlock(l);\ 292 return tmp;\ 293 } 294 OPTIMISED_CASES 295 #undef OPTIMISED_CASE 296 297 #define OPTIMISED_CASE(n, lockfree, type)\ 298 int __atomic_compare_exchange_##n(type *ptr, type *expected, type desired,\ 299 int success, int failure) {\ 300 if (lockfree)\ 301 return __c11_atomic_compare_exchange_strong((_Atomic(type)*)ptr, expected, desired,\ 302 success, failure);\ 303 Lock *l = lock_for_pointer(ptr);\ 304 lock(l);\ 305 if (*ptr == *expected) {\ 306 *ptr = desired;\ 307 unlock(l);\ 308 return 1;\ 309 }\ 310 *expected = *ptr;\ 311 unlock(l);\ 312 return 0;\ 313 } 314 OPTIMISED_CASES 315 #undef OPTIMISED_CASE 316 317 //////////////////////////////////////////////////////////////////////////////// 318 // Atomic read-modify-write operations for integers of various sizes. 319 //////////////////////////////////////////////////////////////////////////////// 320 #define ATOMIC_RMW(n, lockfree, type, opname, op) \ 321 type __atomic_fetch_##opname##_##n(type *ptr, type val, int model) {\ 322 if (lockfree) \ 323 return __c11_atomic_fetch_##opname((_Atomic(type)*)ptr, val, model);\ 324 Lock *l = lock_for_pointer(ptr);\ 325 lock(l);\ 326 type tmp = *ptr;\ 327 *ptr = tmp op val;\ 328 unlock(l);\ 329 return tmp;\ 330 } 331 332 #define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, add, +) 333 OPTIMISED_CASES 334 #undef OPTIMISED_CASE 335 #define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, sub, -) 336 OPTIMISED_CASES 337 #undef OPTIMISED_CASE 338 #define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, and, &) 339 OPTIMISED_CASES 340 #undef OPTIMISED_CASE 341 #define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, or, |) 342 OPTIMISED_CASES 343 #undef OPTIMISED_CASE 344 #define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, xor, ^) 345 OPTIMISED_CASES 346 #undef OPTIMISED_CASE 347