atomic.c revision 2aff73868669a46a84ea617801beea47dda0b581
12aff73868669a46a84ea617801beea47dda0b581David Chisnall/*===-- atomic.c - Implement support functions for atomic operations.------===
22aff73868669a46a84ea617801beea47dda0b581David Chisnall *
32aff73868669a46a84ea617801beea47dda0b581David Chisnall *                     The LLVM Compiler Infrastructure
42aff73868669a46a84ea617801beea47dda0b581David Chisnall *
52aff73868669a46a84ea617801beea47dda0b581David Chisnall * This file is dual licensed under the MIT and the University of Illinois Open
62aff73868669a46a84ea617801beea47dda0b581David Chisnall * Source Licenses. See LICENSE.TXT for details.
72aff73868669a46a84ea617801beea47dda0b581David Chisnall *
82aff73868669a46a84ea617801beea47dda0b581David Chisnall *===----------------------------------------------------------------------===
92aff73868669a46a84ea617801beea47dda0b581David Chisnall *
102aff73868669a46a84ea617801beea47dda0b581David Chisnall *  atomic.c defines a set of functions for performing atomic accesses on
112aff73868669a46a84ea617801beea47dda0b581David Chisnall *  arbitrary-sized memory locations.  This design uses locks that should
122aff73868669a46a84ea617801beea47dda0b581David Chisnall *  be fast in the uncontended case, for two reasons:
132aff73868669a46a84ea617801beea47dda0b581David Chisnall *
142aff73868669a46a84ea617801beea47dda0b581David Chisnall *  1) This code must work with C programs that do not link to anything
152aff73868669a46a84ea617801beea47dda0b581David Chisnall *     (including pthreads) and so it should not depend on any pthread
162aff73868669a46a84ea617801beea47dda0b581David Chisnall *     functions.
172aff73868669a46a84ea617801beea47dda0b581David Chisnall *  2) Atomic operations, rather than explicit mutexes, are most commonly used
182aff73868669a46a84ea617801beea47dda0b581David Chisnall *     on code where contended operations are rate.
192aff73868669a46a84ea617801beea47dda0b581David Chisnall *
202aff73868669a46a84ea617801beea47dda0b581David Chisnall *  To avoid needing a per-object lock, this code allocates an array of
212aff73868669a46a84ea617801beea47dda0b581David Chisnall *  locks and hashes the object pointers to find the one that it should use.
222aff73868669a46a84ea617801beea47dda0b581David Chisnall *  For operations that must be atomic on two locations, the lower lock is
232aff73868669a46a84ea617801beea47dda0b581David Chisnall *  always acquired first, to avoid deadlock.
242aff73868669a46a84ea617801beea47dda0b581David Chisnall *
252aff73868669a46a84ea617801beea47dda0b581David Chisnall *===----------------------------------------------------------------------===
262aff73868669a46a84ea617801beea47dda0b581David Chisnall */
272aff73868669a46a84ea617801beea47dda0b581David Chisnall
282aff73868669a46a84ea617801beea47dda0b581David Chisnall#include <stdint.h>
292aff73868669a46a84ea617801beea47dda0b581David Chisnall#include <string.h>
302aff73868669a46a84ea617801beea47dda0b581David Chisnall
312aff73868669a46a84ea617801beea47dda0b581David Chisnall// Clang objects if you redefine a builtin.  This little hack allows us to
322aff73868669a46a84ea617801beea47dda0b581David Chisnall// define a function with the same name as an intrinsic.
332aff73868669a46a84ea617801beea47dda0b581David Chisnall#pragma redefine_extname __atomic_load_n __atomic_load
342aff73868669a46a84ea617801beea47dda0b581David Chisnall#pragma redefine_extname __atomic_store_n __atomic_store
352aff73868669a46a84ea617801beea47dda0b581David Chisnall#pragma redefine_extname __atomic_exchange_n __atomic_exchange
362aff73868669a46a84ea617801beea47dda0b581David Chisnall#pragma redefine_extname __atomic_compare_exchange_n __atomic_compare_exchange
372aff73868669a46a84ea617801beea47dda0b581David Chisnall
382aff73868669a46a84ea617801beea47dda0b581David Chisnall/// Number of locks.  This allocates one page on 32-bit platforms, two on
392aff73868669a46a84ea617801beea47dda0b581David Chisnall/// 64-bit.  This can be specified externally if a different trade between
402aff73868669a46a84ea617801beea47dda0b581David Chisnall/// memory usage and contention probability is required for a given platform.
412aff73868669a46a84ea617801beea47dda0b581David Chisnall#ifndef SPINLOCK_COUNT
422aff73868669a46a84ea617801beea47dda0b581David Chisnall#define SPINLOCK_COUNT (1<<10)
432aff73868669a46a84ea617801beea47dda0b581David Chisnall#endif
442aff73868669a46a84ea617801beea47dda0b581David Chisnallstatic const long SPINLOCK_MASK = SPINLOCK_COUNT - 1;
452aff73868669a46a84ea617801beea47dda0b581David Chisnall
462aff73868669a46a84ea617801beea47dda0b581David Chisnall////////////////////////////////////////////////////////////////////////////////
472aff73868669a46a84ea617801beea47dda0b581David Chisnall// Platform-specific lock implementation.  Falls back to spinlocks if none is
482aff73868669a46a84ea617801beea47dda0b581David Chisnall// defined.  Each platform should define the Lock type, and corresponding
492aff73868669a46a84ea617801beea47dda0b581David Chisnall// lock() and unlock() functions.
502aff73868669a46a84ea617801beea47dda0b581David Chisnall////////////////////////////////////////////////////////////////////////////////
512aff73868669a46a84ea617801beea47dda0b581David Chisnall#ifdef __FreeBSD__
522aff73868669a46a84ea617801beea47dda0b581David Chisnall#include <errno.h>
532aff73868669a46a84ea617801beea47dda0b581David Chisnall#include <sys/types.h>
542aff73868669a46a84ea617801beea47dda0b581David Chisnall#include <machine/atomic.h>
552aff73868669a46a84ea617801beea47dda0b581David Chisnall#include <sys/umtx.h>
562aff73868669a46a84ea617801beea47dda0b581David Chisnalltypedef struct _usem Lock;
572aff73868669a46a84ea617801beea47dda0b581David Chisnallinline static void unlock(Lock *l) {
582aff73868669a46a84ea617801beea47dda0b581David Chisnall  __atomic_store((_Atomic(uint32_t)*)&l->_count, 1, __ATOMIC_RELEASE);
592aff73868669a46a84ea617801beea47dda0b581David Chisnall  __atomic_thread_fence(__ATOMIC_SEQ_CST);
602aff73868669a46a84ea617801beea47dda0b581David Chisnall  if (l->_has_waiters)
612aff73868669a46a84ea617801beea47dda0b581David Chisnall      _umtx_op(l, UMTX_OP_SEM_WAKE, 1, 0, 0);
622aff73868669a46a84ea617801beea47dda0b581David Chisnall}
632aff73868669a46a84ea617801beea47dda0b581David Chisnallinline static void lock(Lock *l) {
642aff73868669a46a84ea617801beea47dda0b581David Chisnall  uint32_t old = 1;
652aff73868669a46a84ea617801beea47dda0b581David Chisnall  while (!__atomic_compare_exchange_weak((_Atomic(uint32_t)*)&l->_count, &old,
662aff73868669a46a84ea617801beea47dda0b581David Chisnall        0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) {
672aff73868669a46a84ea617801beea47dda0b581David Chisnall    _umtx_op(l, UMTX_OP_SEM_WAIT, 0, 0, 0);
682aff73868669a46a84ea617801beea47dda0b581David Chisnall    old = 1;
692aff73868669a46a84ea617801beea47dda0b581David Chisnall  }
702aff73868669a46a84ea617801beea47dda0b581David Chisnall}
712aff73868669a46a84ea617801beea47dda0b581David Chisnall/// locks for atomic operations
722aff73868669a46a84ea617801beea47dda0b581David Chisnallstatic Lock locks[SPINLOCK_COUNT] = { [0 ...  SPINLOCK_COUNT-1] = {0,1,0} };
732aff73868669a46a84ea617801beea47dda0b581David Chisnall#else
742aff73868669a46a84ea617801beea47dda0b581David Chisnalltypedef _Atomic(uintptr_t) Lock;
752aff73868669a46a84ea617801beea47dda0b581David Chisnall/// Unlock a lock.  This is a release operation.
762aff73868669a46a84ea617801beea47dda0b581David Chisnallinline static void unlock(Lock *l) {
772aff73868669a46a84ea617801beea47dda0b581David Chisnall  __atomic_store(l, 0, __ATOMIC_RELEASE);
782aff73868669a46a84ea617801beea47dda0b581David Chisnall}
792aff73868669a46a84ea617801beea47dda0b581David Chisnall/// Locks a lock.  In the current implementation, this is potentially
802aff73868669a46a84ea617801beea47dda0b581David Chisnall/// unbounded in the contended case.
812aff73868669a46a84ea617801beea47dda0b581David Chisnallinline static void lock(Lock *l) {
822aff73868669a46a84ea617801beea47dda0b581David Chisnall  uintptr_t old = 0;
832aff73868669a46a84ea617801beea47dda0b581David Chisnall  while (!__atomic_compare_exchange_weak(l, &old, 1, __ATOMIC_ACQUIRE,
842aff73868669a46a84ea617801beea47dda0b581David Chisnall        __ATOMIC_RELAXED))
852aff73868669a46a84ea617801beea47dda0b581David Chisnall    old = 0;
862aff73868669a46a84ea617801beea47dda0b581David Chisnall}
872aff73868669a46a84ea617801beea47dda0b581David Chisnall/// locks for atomic operations
882aff73868669a46a84ea617801beea47dda0b581David Chisnallstatic Lock locks[SPINLOCK_COUNT];
892aff73868669a46a84ea617801beea47dda0b581David Chisnall#endif
902aff73868669a46a84ea617801beea47dda0b581David Chisnall
912aff73868669a46a84ea617801beea47dda0b581David Chisnall
922aff73868669a46a84ea617801beea47dda0b581David Chisnall/// Returns a lock to use for a given pointer.
932aff73868669a46a84ea617801beea47dda0b581David Chisnallstatic inline Lock *lock_for_pointer(void *ptr) {
942aff73868669a46a84ea617801beea47dda0b581David Chisnall  intptr_t hash = (intptr_t)ptr;
952aff73868669a46a84ea617801beea47dda0b581David Chisnall  // Disregard the lowest 4 bits.  We want all values that may be part of the
962aff73868669a46a84ea617801beea47dda0b581David Chisnall  // same memory operation to hash to the same value and therefore use the same
972aff73868669a46a84ea617801beea47dda0b581David Chisnall  // lock.
982aff73868669a46a84ea617801beea47dda0b581David Chisnall  hash >>= 4;
992aff73868669a46a84ea617801beea47dda0b581David Chisnall  // Use the next bits as the basis for the hash
1002aff73868669a46a84ea617801beea47dda0b581David Chisnall  intptr_t low = hash & SPINLOCK_MASK;
1012aff73868669a46a84ea617801beea47dda0b581David Chisnall  // Now use the high(er) set of bits to perturb the hash, so that we don't
1022aff73868669a46a84ea617801beea47dda0b581David Chisnall  // get collisions from atomic fields in a single object
1032aff73868669a46a84ea617801beea47dda0b581David Chisnall  hash >>= 16;
1042aff73868669a46a84ea617801beea47dda0b581David Chisnall  hash ^= low;
1052aff73868669a46a84ea617801beea47dda0b581David Chisnall  // Return a pointer to the word to use
1062aff73868669a46a84ea617801beea47dda0b581David Chisnall  return locks + (hash & SPINLOCK_MASK);
1072aff73868669a46a84ea617801beea47dda0b581David Chisnall}
1082aff73868669a46a84ea617801beea47dda0b581David Chisnall
1092aff73868669a46a84ea617801beea47dda0b581David Chisnall/// Macros for determining whether a size is lock free.  Clang can not yet
1102aff73868669a46a84ea617801beea47dda0b581David Chisnall/// codegen __atomic_is_lock_free(16), so for now we assume 16-byte values are
1112aff73868669a46a84ea617801beea47dda0b581David Chisnall/// not lock free.
1122aff73868669a46a84ea617801beea47dda0b581David Chisnall#define IS_LOCK_FREE_1 __atomic_is_lock_free(1)
1132aff73868669a46a84ea617801beea47dda0b581David Chisnall#define IS_LOCK_FREE_2 __atomic_is_lock_free(2)
1142aff73868669a46a84ea617801beea47dda0b581David Chisnall#define IS_LOCK_FREE_4 __atomic_is_lock_free(4)
1152aff73868669a46a84ea617801beea47dda0b581David Chisnall#define IS_LOCK_FREE_8 __atomic_is_lock_free(8)
1162aff73868669a46a84ea617801beea47dda0b581David Chisnall#define IS_LOCK_FREE_16 0
1172aff73868669a46a84ea617801beea47dda0b581David Chisnall
1182aff73868669a46a84ea617801beea47dda0b581David Chisnall/// Macro that calls the compiler-generated lock-free versions of functions
1192aff73868669a46a84ea617801beea47dda0b581David Chisnall/// when they exist.
1202aff73868669a46a84ea617801beea47dda0b581David Chisnall#define LOCK_FREE_CASES() \
1212aff73868669a46a84ea617801beea47dda0b581David Chisnall  do {\
1222aff73868669a46a84ea617801beea47dda0b581David Chisnall  switch (size) {\
1232aff73868669a46a84ea617801beea47dda0b581David Chisnall    case 2:\
1242aff73868669a46a84ea617801beea47dda0b581David Chisnall      if (IS_LOCK_FREE_2) {\
1252aff73868669a46a84ea617801beea47dda0b581David Chisnall        LOCK_FREE_ACTION(uint16_t);\
1262aff73868669a46a84ea617801beea47dda0b581David Chisnall      }\
1272aff73868669a46a84ea617801beea47dda0b581David Chisnall    case 4:\
1282aff73868669a46a84ea617801beea47dda0b581David Chisnall      if (IS_LOCK_FREE_4) {\
1292aff73868669a46a84ea617801beea47dda0b581David Chisnall        LOCK_FREE_ACTION(uint32_t);\
1302aff73868669a46a84ea617801beea47dda0b581David Chisnall      }\
1312aff73868669a46a84ea617801beea47dda0b581David Chisnall    case 8:\
1322aff73868669a46a84ea617801beea47dda0b581David Chisnall      if (IS_LOCK_FREE_8) {\
1332aff73868669a46a84ea617801beea47dda0b581David Chisnall        LOCK_FREE_ACTION(uint64_t);\
1342aff73868669a46a84ea617801beea47dda0b581David Chisnall      }\
1352aff73868669a46a84ea617801beea47dda0b581David Chisnall    case 16:\
1362aff73868669a46a84ea617801beea47dda0b581David Chisnall      if (IS_LOCK_FREE_16) {\
1372aff73868669a46a84ea617801beea47dda0b581David Chisnall        LOCK_FREE_ACTION(__uint128_t);\
1382aff73868669a46a84ea617801beea47dda0b581David Chisnall      }\
1392aff73868669a46a84ea617801beea47dda0b581David Chisnall  }\
1402aff73868669a46a84ea617801beea47dda0b581David Chisnall  } while (0)
1412aff73868669a46a84ea617801beea47dda0b581David Chisnall
1422aff73868669a46a84ea617801beea47dda0b581David Chisnall
1432aff73868669a46a84ea617801beea47dda0b581David Chisnall/// An atomic load operation.  This is atomic with respect to the source
1442aff73868669a46a84ea617801beea47dda0b581David Chisnall/// pointer only.
1452aff73868669a46a84ea617801beea47dda0b581David Chisnallvoid __atomic_load_n(int size, void *src, void *dest, int model) {
1462aff73868669a46a84ea617801beea47dda0b581David Chisnall#define LOCK_FREE_ACTION(type) \
1472aff73868669a46a84ea617801beea47dda0b581David Chisnall    *((type*)dest) = __atomic_load((_Atomic(type)*)src, model);\
1482aff73868669a46a84ea617801beea47dda0b581David Chisnall    return;
1492aff73868669a46a84ea617801beea47dda0b581David Chisnall  LOCK_FREE_CASES();
1502aff73868669a46a84ea617801beea47dda0b581David Chisnall#undef LOCK_FREE_ACTION
1512aff73868669a46a84ea617801beea47dda0b581David Chisnall  Lock *l = lock_for_pointer(src);
1522aff73868669a46a84ea617801beea47dda0b581David Chisnall  lock(l);
1532aff73868669a46a84ea617801beea47dda0b581David Chisnall  memcpy(dest, src, size);
1542aff73868669a46a84ea617801beea47dda0b581David Chisnall  unlock(l);
1552aff73868669a46a84ea617801beea47dda0b581David Chisnall}
1562aff73868669a46a84ea617801beea47dda0b581David Chisnall
1572aff73868669a46a84ea617801beea47dda0b581David Chisnall/// An atomic store operation.  This is atomic with respect to the destination
1582aff73868669a46a84ea617801beea47dda0b581David Chisnall/// pointer only.
1592aff73868669a46a84ea617801beea47dda0b581David Chisnallvoid __atomic_store_n(int size, void *dest, void *src, int model) {
1602aff73868669a46a84ea617801beea47dda0b581David Chisnall#define LOCK_FREE_ACTION(type) \
1612aff73868669a46a84ea617801beea47dda0b581David Chisnall    __atomic_store((_Atomic(type)*)dest, *(type*)dest, model);\
1622aff73868669a46a84ea617801beea47dda0b581David Chisnall    return;
1632aff73868669a46a84ea617801beea47dda0b581David Chisnall  LOCK_FREE_CASES();
1642aff73868669a46a84ea617801beea47dda0b581David Chisnall#undef LOCK_FREE_ACTION
1652aff73868669a46a84ea617801beea47dda0b581David Chisnall  Lock *l = lock_for_pointer(dest);
1662aff73868669a46a84ea617801beea47dda0b581David Chisnall  lock(l);
1672aff73868669a46a84ea617801beea47dda0b581David Chisnall  memcpy(dest, src, size);
1682aff73868669a46a84ea617801beea47dda0b581David Chisnall  unlock(l);
1692aff73868669a46a84ea617801beea47dda0b581David Chisnall}
1702aff73868669a46a84ea617801beea47dda0b581David Chisnall
1712aff73868669a46a84ea617801beea47dda0b581David Chisnall/// Atomic compare and exchange operation.  If the value at *ptr is identical
1722aff73868669a46a84ea617801beea47dda0b581David Chisnall/// to the value at *expected, then this copies value at *desired to *ptr.  If
1732aff73868669a46a84ea617801beea47dda0b581David Chisnall/// they  are not, then this stores the current value from *ptr in *expected.
1742aff73868669a46a84ea617801beea47dda0b581David Chisnall///
1752aff73868669a46a84ea617801beea47dda0b581David Chisnall/// This function returns 1 if the exchange takes place or 0 if it fails.
1762aff73868669a46a84ea617801beea47dda0b581David Chisnallint __atomic_compare_exchange_n(int size, void *ptr, void *expected,
1772aff73868669a46a84ea617801beea47dda0b581David Chisnall    void *desired, int success, int failure) {
1782aff73868669a46a84ea617801beea47dda0b581David Chisnall#define LOCK_FREE_ACTION(type) \
1792aff73868669a46a84ea617801beea47dda0b581David Chisnall  return __atomic_compare_exchange_strong((_Atomic(type)*)ptr, (type*)expected,\
1802aff73868669a46a84ea617801beea47dda0b581David Chisnall      *(type*)desired, success, failure)
1812aff73868669a46a84ea617801beea47dda0b581David Chisnall  LOCK_FREE_CASES();
1822aff73868669a46a84ea617801beea47dda0b581David Chisnall#undef LOCK_FREE_ACTION
1832aff73868669a46a84ea617801beea47dda0b581David Chisnall  Lock *l = lock_for_pointer(ptr);
1842aff73868669a46a84ea617801beea47dda0b581David Chisnall  lock(l);
1852aff73868669a46a84ea617801beea47dda0b581David Chisnall  if (memcmp(ptr, expected, size) == 0) {
1862aff73868669a46a84ea617801beea47dda0b581David Chisnall    memcpy(ptr, desired, size);
1872aff73868669a46a84ea617801beea47dda0b581David Chisnall    unlock(l);
1882aff73868669a46a84ea617801beea47dda0b581David Chisnall    return 1;
1892aff73868669a46a84ea617801beea47dda0b581David Chisnall  }
1902aff73868669a46a84ea617801beea47dda0b581David Chisnall  memcpy(expected, ptr, size);
1912aff73868669a46a84ea617801beea47dda0b581David Chisnall  unlock(l);
1922aff73868669a46a84ea617801beea47dda0b581David Chisnall  return 0;
1932aff73868669a46a84ea617801beea47dda0b581David Chisnall}
1942aff73868669a46a84ea617801beea47dda0b581David Chisnall
1952aff73868669a46a84ea617801beea47dda0b581David Chisnall/// Performs an atomic exchange operation between two pointers.  This is atomic
1962aff73868669a46a84ea617801beea47dda0b581David Chisnall/// with respect to the target address.
1972aff73868669a46a84ea617801beea47dda0b581David Chisnallvoid __atomic_exchange_n(int size, void *ptr, void *val, void *old, int model) {
1982aff73868669a46a84ea617801beea47dda0b581David Chisnall#define LOCK_FREE_ACTION(type) \
1992aff73868669a46a84ea617801beea47dda0b581David Chisnall    *(type*)old = __atomic_exchange((_Atomic(type)*)ptr, *(type*)val,\
2002aff73868669a46a84ea617801beea47dda0b581David Chisnall        model);\
2012aff73868669a46a84ea617801beea47dda0b581David Chisnall    return;
2022aff73868669a46a84ea617801beea47dda0b581David Chisnall  LOCK_FREE_CASES();
2032aff73868669a46a84ea617801beea47dda0b581David Chisnall#undef LOCK_FREE_ACTION
2042aff73868669a46a84ea617801beea47dda0b581David Chisnall  Lock *l = lock_for_pointer(ptr);
2052aff73868669a46a84ea617801beea47dda0b581David Chisnall  lock(l);
2062aff73868669a46a84ea617801beea47dda0b581David Chisnall  memcpy(old, ptr, size);
2072aff73868669a46a84ea617801beea47dda0b581David Chisnall  memcpy(ptr, val, size);
2082aff73868669a46a84ea617801beea47dda0b581David Chisnall  unlock(l);
2092aff73868669a46a84ea617801beea47dda0b581David Chisnall}
2102aff73868669a46a84ea617801beea47dda0b581David Chisnall
2112aff73868669a46a84ea617801beea47dda0b581David Chisnall////////////////////////////////////////////////////////////////////////////////
2122aff73868669a46a84ea617801beea47dda0b581David Chisnall// Where the size is known at compile time, the compiler may emit calls to
2132aff73868669a46a84ea617801beea47dda0b581David Chisnall// specialised versions of the above functions.
2142aff73868669a46a84ea617801beea47dda0b581David Chisnall////////////////////////////////////////////////////////////////////////////////
2152aff73868669a46a84ea617801beea47dda0b581David Chisnall#define OPTIMISED_CASES\
2162aff73868669a46a84ea617801beea47dda0b581David Chisnall  OPTIMISED_CASE(1, IS_LOCK_FREE_1, uint8_t)\
2172aff73868669a46a84ea617801beea47dda0b581David Chisnall  OPTIMISED_CASE(2, IS_LOCK_FREE_2, uint16_t)\
2182aff73868669a46a84ea617801beea47dda0b581David Chisnall  OPTIMISED_CASE(4, IS_LOCK_FREE_4, uint32_t)\
2192aff73868669a46a84ea617801beea47dda0b581David Chisnall  OPTIMISED_CASE(8, IS_LOCK_FREE_8, uint64_t)\
2202aff73868669a46a84ea617801beea47dda0b581David Chisnall  OPTIMISED_CASE(16, IS_LOCK_FREE_16, __uint128_t)\
2212aff73868669a46a84ea617801beea47dda0b581David Chisnall
2222aff73868669a46a84ea617801beea47dda0b581David Chisnall#define OPTIMISED_CASE(n, lockfree, type)\
2232aff73868669a46a84ea617801beea47dda0b581David Chisnalltype __atomic_load_##n(type *src, int model) {\
2242aff73868669a46a84ea617801beea47dda0b581David Chisnall  if (lockfree)\
2252aff73868669a46a84ea617801beea47dda0b581David Chisnall    return __atomic_load((_Atomic(type)*)src, model);\
2262aff73868669a46a84ea617801beea47dda0b581David Chisnall  Lock *l = lock_for_pointer(src);\
2272aff73868669a46a84ea617801beea47dda0b581David Chisnall  lock(l);\
2282aff73868669a46a84ea617801beea47dda0b581David Chisnall  type val = *src;\
2292aff73868669a46a84ea617801beea47dda0b581David Chisnall  unlock(l);\
2302aff73868669a46a84ea617801beea47dda0b581David Chisnall  return val;\
2312aff73868669a46a84ea617801beea47dda0b581David Chisnall}
2322aff73868669a46a84ea617801beea47dda0b581David ChisnallOPTIMISED_CASES
2332aff73868669a46a84ea617801beea47dda0b581David Chisnall#undef OPTIMISED_CASE
2342aff73868669a46a84ea617801beea47dda0b581David Chisnall
2352aff73868669a46a84ea617801beea47dda0b581David Chisnall#define OPTIMISED_CASE(n, lockfree, type)\
2362aff73868669a46a84ea617801beea47dda0b581David Chisnallvoid  __atomic_store_##n(type *dest, type val, int model) {\
2372aff73868669a46a84ea617801beea47dda0b581David Chisnall  if (lockfree) {\
2382aff73868669a46a84ea617801beea47dda0b581David Chisnall    __atomic_store((_Atomic(type)*)dest, val, model);\
2392aff73868669a46a84ea617801beea47dda0b581David Chisnall    return;\
2402aff73868669a46a84ea617801beea47dda0b581David Chisnall  }\
2412aff73868669a46a84ea617801beea47dda0b581David Chisnall  Lock *l = lock_for_pointer(dest);\
2422aff73868669a46a84ea617801beea47dda0b581David Chisnall  lock(l);\
2432aff73868669a46a84ea617801beea47dda0b581David Chisnall  *dest = val;\
2442aff73868669a46a84ea617801beea47dda0b581David Chisnall  unlock(l);\
2452aff73868669a46a84ea617801beea47dda0b581David Chisnall  return;\
2462aff73868669a46a84ea617801beea47dda0b581David Chisnall}
2472aff73868669a46a84ea617801beea47dda0b581David ChisnallOPTIMISED_CASES
2482aff73868669a46a84ea617801beea47dda0b581David Chisnall#undef OPTIMISED_CASE
2492aff73868669a46a84ea617801beea47dda0b581David Chisnall
2502aff73868669a46a84ea617801beea47dda0b581David Chisnall#define OPTIMISED_CASE(n, lockfree, type)\
2512aff73868669a46a84ea617801beea47dda0b581David Chisnalltype __atomic_exchange_##n(type *dest, type val, int model) {\
2522aff73868669a46a84ea617801beea47dda0b581David Chisnall  if (lockfree)\
2532aff73868669a46a84ea617801beea47dda0b581David Chisnall    return __atomic_exchange((_Atomic(type)*)dest, val, model);\
2542aff73868669a46a84ea617801beea47dda0b581David Chisnall  Lock *l = lock_for_pointer(dest);\
2552aff73868669a46a84ea617801beea47dda0b581David Chisnall  lock(l);\
2562aff73868669a46a84ea617801beea47dda0b581David Chisnall  type tmp = *dest;\
2572aff73868669a46a84ea617801beea47dda0b581David Chisnall  *dest = val;\
2582aff73868669a46a84ea617801beea47dda0b581David Chisnall  unlock(l);\
2592aff73868669a46a84ea617801beea47dda0b581David Chisnall  return tmp;\
2602aff73868669a46a84ea617801beea47dda0b581David Chisnall}
2612aff73868669a46a84ea617801beea47dda0b581David ChisnallOPTIMISED_CASES
2622aff73868669a46a84ea617801beea47dda0b581David Chisnall#undef OPTIMISED_CASE
2632aff73868669a46a84ea617801beea47dda0b581David Chisnall
2642aff73868669a46a84ea617801beea47dda0b581David Chisnall#define OPTIMISED_CASE(n, lockfree, type)\
2652aff73868669a46a84ea617801beea47dda0b581David Chisnallint __atomic_compare_exchange_##n(type *ptr, type *expected, type desired,\
2662aff73868669a46a84ea617801beea47dda0b581David Chisnall    int success, int failure) {\
2672aff73868669a46a84ea617801beea47dda0b581David Chisnall  if (lockfree)\
2682aff73868669a46a84ea617801beea47dda0b581David Chisnall    return __atomic_compare_exchange_strong((_Atomic(type)*)ptr, expected, desired,\
2692aff73868669a46a84ea617801beea47dda0b581David Chisnall        success, failure);\
2702aff73868669a46a84ea617801beea47dda0b581David Chisnall  Lock *l = lock_for_pointer(ptr);\
2712aff73868669a46a84ea617801beea47dda0b581David Chisnall  lock(l);\
2722aff73868669a46a84ea617801beea47dda0b581David Chisnall  if (*ptr == *expected) {\
2732aff73868669a46a84ea617801beea47dda0b581David Chisnall    *ptr = desired;\
2742aff73868669a46a84ea617801beea47dda0b581David Chisnall    unlock(l);\
2752aff73868669a46a84ea617801beea47dda0b581David Chisnall    return 1;\
2762aff73868669a46a84ea617801beea47dda0b581David Chisnall  }\
2772aff73868669a46a84ea617801beea47dda0b581David Chisnall  *expected = *ptr;\
2782aff73868669a46a84ea617801beea47dda0b581David Chisnall  unlock(l);\
2792aff73868669a46a84ea617801beea47dda0b581David Chisnall  return 0;\
2802aff73868669a46a84ea617801beea47dda0b581David Chisnall}
2812aff73868669a46a84ea617801beea47dda0b581David ChisnallOPTIMISED_CASES
2822aff73868669a46a84ea617801beea47dda0b581David Chisnall#undef OPTIMISED_CASE
2832aff73868669a46a84ea617801beea47dda0b581David Chisnall
2842aff73868669a46a84ea617801beea47dda0b581David Chisnall////////////////////////////////////////////////////////////////////////////////
2852aff73868669a46a84ea617801beea47dda0b581David Chisnall// Atomic read-modify-write operations for integers of various sizes.
2862aff73868669a46a84ea617801beea47dda0b581David Chisnall////////////////////////////////////////////////////////////////////////////////
2872aff73868669a46a84ea617801beea47dda0b581David Chisnall#define ATOMIC_RMW(n, lockfree, type, opname, op) \
2882aff73868669a46a84ea617801beea47dda0b581David Chisnalltype __atomic_fetch_##opname##_##n(type *ptr, type val, int model) {\
2892aff73868669a46a84ea617801beea47dda0b581David Chisnall  if (lockfree) \
2902aff73868669a46a84ea617801beea47dda0b581David Chisnall    return __atomic_fetch_##opname((_Atomic(type)*)ptr, val, model);\
2912aff73868669a46a84ea617801beea47dda0b581David Chisnall  Lock *l = lock_for_pointer(ptr);\
2922aff73868669a46a84ea617801beea47dda0b581David Chisnall  lock(l);\
2932aff73868669a46a84ea617801beea47dda0b581David Chisnall  type tmp = *ptr;\
2942aff73868669a46a84ea617801beea47dda0b581David Chisnall  *ptr = tmp op val;\
2952aff73868669a46a84ea617801beea47dda0b581David Chisnall  unlock(l);\
2962aff73868669a46a84ea617801beea47dda0b581David Chisnall  return tmp;\
2972aff73868669a46a84ea617801beea47dda0b581David Chisnall}
2982aff73868669a46a84ea617801beea47dda0b581David Chisnall
2992aff73868669a46a84ea617801beea47dda0b581David Chisnall#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, add, +)
3002aff73868669a46a84ea617801beea47dda0b581David ChisnallOPTIMISED_CASES
3012aff73868669a46a84ea617801beea47dda0b581David Chisnall#undef OPTIMISED_CASE
3022aff73868669a46a84ea617801beea47dda0b581David Chisnall#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, sub, -)
3032aff73868669a46a84ea617801beea47dda0b581David ChisnallOPTIMISED_CASES
3042aff73868669a46a84ea617801beea47dda0b581David Chisnall#undef OPTIMISED_CASE
3052aff73868669a46a84ea617801beea47dda0b581David Chisnall#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, and, &)
3062aff73868669a46a84ea617801beea47dda0b581David ChisnallOPTIMISED_CASES
3072aff73868669a46a84ea617801beea47dda0b581David Chisnall#undef OPTIMISED_CASE
3082aff73868669a46a84ea617801beea47dda0b581David Chisnall#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, or, |)
3092aff73868669a46a84ea617801beea47dda0b581David ChisnallOPTIMISED_CASES
3102aff73868669a46a84ea617801beea47dda0b581David Chisnall#undef OPTIMISED_CASE
3112aff73868669a46a84ea617801beea47dda0b581David Chisnall#define OPTIMISED_CASE(n, lockfree, type) ATOMIC_RMW(n, lockfree, type, xor, ^)
3122aff73868669a46a84ea617801beea47dda0b581David ChisnallOPTIMISED_CASES
3132aff73868669a46a84ea617801beea47dda0b581David Chisnall#undef OPTIMISED_CASE
314