cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_atomic.c (7427B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      4
      5  This software is provided 'as-is', without any express or implied
      6  warranty.  In no event will the authors be held liable for any damages
      7  arising from the use of this software.
      8
      9  Permission is granted to anyone to use this software for any purpose,
     10  including commercial applications, and to alter it and redistribute it
     11  freely, subject to the following restrictions:
     12
     13  1. The origin of this software must not be misrepresented; you must not
     14     claim that you wrote the original software. If you use this software
     15     in a product, an acknowledgment in the product documentation would be
     16     appreciated but is not required.
     17  2. Altered source versions must be plainly marked as such, and must not be
     18     misrepresented as being the original software.
     19  3. This notice may not be removed or altered from any source distribution.
     20*/
     21#include "../SDL_internal.h"
     22
     23#include "SDL_atomic.h"
     24
     25#if defined(_MSC_VER) && (_MSC_VER >= 1500)
     26#include <intrin.h>
     27#define HAVE_MSC_ATOMICS 1
     28#endif
     29
     30#if defined(__MACOSX__)  /* !!! FIXME: should we favor gcc atomics? */
     31#include <libkern/OSAtomic.h>
     32#endif
     33
     34#if !defined(HAVE_GCC_ATOMICS) && defined(__SOLARIS__)
     35#include <atomic.h>
     36#endif
     37
     38/*
     39  If any of the operations are not provided then we must emulate some
     40  of them. That means we need a nice implementation of spin locks
     41  that avoids the "one big lock" problem. We use a vector of spin
     42  locks and pick which one to use based on the address of the operand
     43  of the function.
     44
     45  To generate the index of the lock we first shift by 3 bits to get
     46  rid on the zero bits that result from 32 and 64 bit allignment of
     47  data. We then mask off all but 5 bits and use those 5 bits as an
     48  index into the table.
     49
     50  Picking the lock this way insures that accesses to the same data at
     51  the same time will go to the same lock. OTOH, accesses to different
     52  data have only a 1/32 chance of hitting the same lock. That should
     53  pretty much eliminate the chances of several atomic operations on
     54  different data from waiting on the same "big lock". If it isn't
     55  then the table of locks can be expanded to a new size so long as
     56  the new size is a power of two.
     57
     58  Contributed by Bob Pendleton, bob@pendleton.com
     59*/
     60
     61#if !defined(HAVE_MSC_ATOMICS) && !defined(HAVE_GCC_ATOMICS) && !defined(__MACOSX__) && !defined(__SOLARIS__)
     62#define EMULATE_CAS 1
     63#endif
     64
     65#if EMULATE_CAS
     66static SDL_SpinLock locks[32];
     67
     68static SDL_INLINE void
     69enterLock(void *a)
     70{
     71    uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
     72
     73    SDL_AtomicLock(&locks[index]);
     74}
     75
     76static SDL_INLINE void
     77leaveLock(void *a)
     78{
     79    uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
     80
     81    SDL_AtomicUnlock(&locks[index]);
     82}
     83#endif
     84
     85
     86SDL_bool
     87SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval)
     88{
     89#ifdef HAVE_MSC_ATOMICS
     90    return (_InterlockedCompareExchange((long*)&a->value, (long)newval, (long)oldval) == (long)oldval);
     91#elif defined(__MACOSX__)  /* !!! FIXME: should we favor gcc atomics? */
     92    return (SDL_bool) OSAtomicCompareAndSwap32Barrier(oldval, newval, &a->value);
     93#elif defined(HAVE_GCC_ATOMICS)
     94    return (SDL_bool) __sync_bool_compare_and_swap(&a->value, oldval, newval);
     95#elif defined(__SOLARIS__) && defined(_LP64)
     96    return (SDL_bool) ((int) atomic_cas_64((volatile uint64_t*)&a->value, (uint64_t)oldval, (uint64_t)newval) == oldval);
     97#elif defined(__SOLARIS__) && !defined(_LP64)
     98    return (SDL_bool) ((int) atomic_cas_32((volatile uint32_t*)&a->value, (uint32_t)oldval, (uint32_t)newval) == oldval);
     99#elif EMULATE_CAS
    100    SDL_bool retval = SDL_FALSE;
    101
    102    enterLock(a);
    103    if (a->value == oldval) {
    104        a->value = newval;
    105        retval = SDL_TRUE;
    106    }
    107    leaveLock(a);
    108
    109    return retval;
    110#else
    111    #error Please define your platform.
    112#endif
    113}
    114
    115SDL_bool
    116SDL_AtomicCASPtr(void **a, void *oldval, void *newval)
    117{
    118#if defined(HAVE_MSC_ATOMICS) && (_M_IX86)
    119    return (_InterlockedCompareExchange((long*)a, (long)newval, (long)oldval) == (long)oldval);
    120#elif defined(HAVE_MSC_ATOMICS) && (!_M_IX86)
    121    return (_InterlockedCompareExchangePointer(a, newval, oldval) == oldval);
    122#elif defined(__MACOSX__) && defined(__LP64__)   /* !!! FIXME: should we favor gcc atomics? */
    123    return (SDL_bool) OSAtomicCompareAndSwap64Barrier((int64_t)oldval, (int64_t)newval, (int64_t*) a);
    124#elif defined(__MACOSX__) && !defined(__LP64__)  /* !!! FIXME: should we favor gcc atomics? */
    125    return (SDL_bool) OSAtomicCompareAndSwap32Barrier((int32_t)oldval, (int32_t)newval, (int32_t*) a);
    126#elif defined(HAVE_GCC_ATOMICS)
    127    return __sync_bool_compare_and_swap(a, oldval, newval);
    128#elif defined(__SOLARIS__)
    129    return (SDL_bool) (atomic_cas_ptr(a, oldval, newval) == oldval);
    130#elif EMULATE_CAS
    131    SDL_bool retval = SDL_FALSE;
    132
    133    enterLock(a);
    134    if (*a == oldval) {
    135        *a = newval;
    136        retval = SDL_TRUE;
    137    }
    138    leaveLock(a);
    139
    140    return retval;
    141#else
    142    #error Please define your platform.
    143#endif
    144}
    145
    146int
    147SDL_AtomicSet(SDL_atomic_t *a, int v)
    148{
    149#ifdef HAVE_MSC_ATOMICS
    150    return _InterlockedExchange((long*)&a->value, v);
    151#elif defined(HAVE_GCC_ATOMICS)
    152    return __sync_lock_test_and_set(&a->value, v);
    153#elif defined(__SOLARIS__) && defined(_LP64)
    154    return (int) atomic_swap_64((volatile uint64_t*)&a->value, (uint64_t)v);
    155#elif defined(__SOLARIS__) && !defined(_LP64)
    156    return (int) atomic_swap_32((volatile uint32_t*)&a->value, (uint32_t)v);
    157#else
    158    int value;
    159    do {
    160        value = a->value;
    161    } while (!SDL_AtomicCAS(a, value, v));
    162    return value;
    163#endif
    164}
    165
    166void*
    167SDL_AtomicSetPtr(void **a, void *v)
    168{
    169#if defined(HAVE_MSC_ATOMICS) && (_M_IX86)
    170    return (void *) _InterlockedExchange((long *)a, (long) v);
    171#elif defined(HAVE_MSC_ATOMICS) && (!_M_IX86)
    172    return _InterlockedExchangePointer(a, v);
    173#elif defined(HAVE_GCC_ATOMICS)
    174    return __sync_lock_test_and_set(a, v);
    175#elif defined(__SOLARIS__)
    176    return atomic_swap_ptr(a, v);
    177#else
    178    void *value;
    179    do {
    180        value = *a;
    181    } while (!SDL_AtomicCASPtr(a, value, v));
    182    return value;
    183#endif
    184}
    185
    186int
    187SDL_AtomicAdd(SDL_atomic_t *a, int v)
    188{
    189#ifdef HAVE_MSC_ATOMICS
    190    return _InterlockedExchangeAdd((long*)&a->value, v);
    191#elif defined(HAVE_GCC_ATOMICS)
    192    return __sync_fetch_and_add(&a->value, v);
    193#elif defined(__SOLARIS__)
    194    int pv = a->value;
    195    membar_consumer();
    196#if defined(_LP64)
    197    atomic_add_64((volatile uint64_t*)&a->value, v);
    198#elif !defined(_LP64)
    199    atomic_add_32((volatile uint32_t*)&a->value, v);
    200#endif
    201    return pv;
    202#else
    203    int value;
    204    do {
    205        value = a->value;
    206    } while (!SDL_AtomicCAS(a, value, (value + v)));
    207    return value;
    208#endif
    209}
    210
    211int
    212SDL_AtomicGet(SDL_atomic_t *a)
    213{
    214    int value;
    215    do {
    216        value = a->value;
    217    } while (!SDL_AtomicCAS(a, value, value));
    218    return value;
    219}
    220
    221void *
    222SDL_AtomicGetPtr(void **a)
    223{
    224    void *value;
    225    do {
    226        value = *a;
    227    } while (!SDL_AtomicCASPtr(a, value, value));
    228    return value;
    229}
    230
    231#ifdef __thumb__
    232#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
    233__asm__(
    234"   .align 2\n"
    235"   .globl _SDL_MemoryBarrierRelease\n"
    236"   .globl _SDL_MemoryBarrierAcquire\n"
    237"_SDL_MemoryBarrierRelease:\n"
    238"_SDL_MemoryBarrierAcquire:\n"
    239"   mov r0, #0\n"
    240"   mcr p15, 0, r0, c7, c10, 5\n"
    241"   bx lr\n"
    242);
    243#endif
    244#endif
    245
    246/* vi: set ts=4 sw=4 expandtab: */