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