Home | History | Annotate | Line # | Download | only in builtins
      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