src/atomic/SDL_atomic.c
author Ryan C. Gordon
Mon, 01 Jan 2018 19:16:51 -0500
changeset 11803 454f6dc9cb85
parent 11318 06fd8421e8f6
child 11811 5d94cb6b24d3
permissions -rw-r--r--
windows: Remove references to GetVersionExA (thanks, Andrew Pilley!).

"GetVersionExA is deprecated in windows 8.1 and above's SDK, causing a warning
when building against the win10 SDK. Attached patch cleans up the usage for a
warning-free build.

GetVersionExA was being used to test to see if SDL was running on win9x or
winnt. A quick chat with Ryan on twitter suggested that SDL doesn't
officially support win9x anymore, so the call to this can be outright removed.

As an aside, replacing the call to GetVersionExA with VerifyVersionInfoA (the
recommended path) would have been pointless, as VerifyVersionInfoA only
supports VER_PLATFORM_WIN32_NT and doesn't officially support any other value
for dwPlatformId currently. (And it's probable that win9x SDKs didn't have
VerifyVersionInfo* in them anyway.)"

Fixes Bugzilla #4019.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2017 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 /* The __atomic_load_n() intrinsic showed up in different times for different compilers. */
    39 #if defined(HAVE_GCC_ATOMICS)
    40 # if defined(__clang__)
    41 #   if __has_builtin(__atomic_load_n)
    42       /* !!! FIXME: this advertises as available in the NDK but uses an external symbol we don't have.
    43          It might be in a later NDK or we might need an extra library? --ryan. */
    44 #     if !defined(__ANDROID__)
    45 #       define HAVE_ATOMIC_LOAD_N 1
    46 #     endif
    47 #   endif
    48 # elif defined(__GNUC__)
    49 #   if (__GNUC__ >= 5)
    50 #     define HAVE_ATOMIC_LOAD_N 1
    51 #   endif
    52 # endif
    53 #endif
    54 
    55 #if defined(__WATCOMC__) && defined(__386__)
    56 #define HAVE_WATCOM_ATOMICS
    57 extern _inline int _SDL_xchg_watcom(volatile int *a, int v);
    58 #pragma aux _SDL_xchg_watcom = \
    59   "xchg [ecx], eax" \
    60   parm [ecx] [eax] \
    61   value [eax] \
    62   modify exact [eax];
    63 
    64 extern _inline unsigned char _SDL_cmpxchg_watcom(volatile int *a, int newval, int oldval);
    65 #pragma aux _SDL_cmpxchg_watcom = \
    66   "lock cmpxchg [edx], ecx" \
    67   "setz al" \
    68   parm [edx] [ecx] [eax] \
    69   value [al] \
    70   modify exact [eax];
    71 
    72 extern _inline int _SDL_xadd_watcom(volatile int *a, int v);
    73 #pragma aux _SDL_xadd_watcom = \
    74   "lock xadd [ecx], eax" \
    75   parm [ecx] [eax] \
    76   value [eax] \
    77   modify exact [eax];
    78 #endif /* __WATCOMC__ && __386__ */
    79 
    80 /*
    81   If any of the operations are not provided then we must emulate some
    82   of them. That means we need a nice implementation of spin locks
    83   that avoids the "one big lock" problem. We use a vector of spin
    84   locks and pick which one to use based on the address of the operand
    85   of the function.
    86 
    87   To generate the index of the lock we first shift by 3 bits to get
    88   rid on the zero bits that result from 32 and 64 bit allignment of
    89   data. We then mask off all but 5 bits and use those 5 bits as an
    90   index into the table.
    91 
    92   Picking the lock this way insures that accesses to the same data at
    93   the same time will go to the same lock. OTOH, accesses to different
    94   data have only a 1/32 chance of hitting the same lock. That should
    95   pretty much eliminate the chances of several atomic operations on
    96   different data from waiting on the same "big lock". If it isn't
    97   then the table of locks can be expanded to a new size so long as
    98   the new size is a power of two.
    99 
   100   Contributed by Bob Pendleton, bob@pendleton.com
   101 */
   102 
   103 #if !defined(HAVE_MSC_ATOMICS) && !defined(HAVE_GCC_ATOMICS) && !defined(__MACOSX__) && !defined(__SOLARIS__) && !defined(HAVE_WATCOM_ATOMICS)
   104 #define EMULATE_CAS 1
   105 #endif
   106 
   107 #if EMULATE_CAS
   108 static SDL_SpinLock locks[32];
   109 
   110 static SDL_INLINE void
   111 enterLock(void *a)
   112 {
   113     uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
   114 
   115     SDL_AtomicLock(&locks[index]);
   116 }
   117 
   118 static SDL_INLINE void
   119 leaveLock(void *a)
   120 {
   121     uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
   122 
   123     SDL_AtomicUnlock(&locks[index]);
   124 }
   125 #endif
   126 
   127 
   128 SDL_bool
   129 SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval)
   130 {
   131 #ifdef HAVE_MSC_ATOMICS
   132     return (_InterlockedCompareExchange((long*)&a->value, (long)newval, (long)oldval) == (long)oldval);
   133 #elif defined(HAVE_WATCOM_ATOMICS)
   134     return (SDL_bool) _SDL_cmpxchg_watcom(&a->value, newval, oldval);
   135 #elif defined(HAVE_GCC_ATOMICS)
   136     return (SDL_bool) __sync_bool_compare_and_swap(&a->value, oldval, newval);
   137 #elif defined(__MACOSX__)  /* this is deprecated in 10.12 sdk; favor gcc atomics. */
   138     return (SDL_bool) OSAtomicCompareAndSwap32Barrier(oldval, newval, &a->value);
   139 #elif defined(__SOLARIS__) && defined(_LP64)
   140     return (SDL_bool) ((int) atomic_cas_64((volatile uint64_t*)&a->value, (uint64_t)oldval, (uint64_t)newval) == oldval);
   141 #elif defined(__SOLARIS__) && !defined(_LP64)
   142     return (SDL_bool) ((int) atomic_cas_32((volatile uint32_t*)&a->value, (uint32_t)oldval, (uint32_t)newval) == oldval);
   143 #elif EMULATE_CAS
   144     SDL_bool retval = SDL_FALSE;
   145 
   146     enterLock(a);
   147     if (a->value == oldval) {
   148         a->value = newval;
   149         retval = SDL_TRUE;
   150     }
   151     leaveLock(a);
   152 
   153     return retval;
   154 #else
   155     #error Please define your platform.
   156 #endif
   157 }
   158 
   159 SDL_bool
   160 SDL_AtomicCASPtr(void **a, void *oldval, void *newval)
   161 {
   162 #if defined(HAVE_MSC_ATOMICS) && (_M_IX86)
   163     return (_InterlockedCompareExchange((long*)a, (long)newval, (long)oldval) == (long)oldval);
   164 #elif defined(HAVE_MSC_ATOMICS) && (!_M_IX86)
   165     return (_InterlockedCompareExchangePointer(a, newval, oldval) == oldval);
   166 #elif defined(HAVE_WATCOM_ATOMICS)
   167     return (SDL_bool) _SDL_cmpxchg_watcom((int *)a, (long)newval, (long)oldval);
   168 #elif defined(HAVE_GCC_ATOMICS)
   169     return __sync_bool_compare_and_swap(a, oldval, newval);
   170 #elif defined(__MACOSX__) && defined(__LP64__)  /* this is deprecated in 10.12 sdk; favor gcc atomics. */
   171     return (SDL_bool) OSAtomicCompareAndSwap64Barrier((int64_t)oldval, (int64_t)newval, (int64_t*) a);
   172 #elif defined(__MACOSX__) && !defined(__LP64__)  /* this is deprecated in 10.12 sdk; favor gcc atomics. */
   173     return (SDL_bool) OSAtomicCompareAndSwap32Barrier((int32_t)oldval, (int32_t)newval, (int32_t*) a);
   174 #elif defined(__SOLARIS__)
   175     return (SDL_bool) (atomic_cas_ptr(a, oldval, newval) == oldval);
   176 #elif EMULATE_CAS
   177     SDL_bool retval = SDL_FALSE;
   178 
   179     enterLock(a);
   180     if (*a == oldval) {
   181         *a = newval;
   182         retval = SDL_TRUE;
   183     }
   184     leaveLock(a);
   185 
   186     return retval;
   187 #else
   188     #error Please define your platform.
   189 #endif
   190 }
   191 
   192 int
   193 SDL_AtomicSet(SDL_atomic_t *a, int v)
   194 {
   195 #ifdef HAVE_MSC_ATOMICS
   196     return _InterlockedExchange((long*)&a->value, v);
   197 #elif defined(HAVE_WATCOM_ATOMICS)
   198     return _SDL_xchg_watcom(&a->value, v);
   199 #elif defined(HAVE_GCC_ATOMICS)
   200     return __sync_lock_test_and_set(&a->value, v);
   201 #elif defined(__SOLARIS__) && defined(_LP64)
   202     return (int) atomic_swap_64((volatile uint64_t*)&a->value, (uint64_t)v);
   203 #elif defined(__SOLARIS__) && !defined(_LP64)
   204     return (int) atomic_swap_32((volatile uint32_t*)&a->value, (uint32_t)v);
   205 #else
   206     int value;
   207     do {
   208         value = a->value;
   209     } while (!SDL_AtomicCAS(a, value, v));
   210     return value;
   211 #endif
   212 }
   213 
   214 void*
   215 SDL_AtomicSetPtr(void **a, void *v)
   216 {
   217 #if defined(HAVE_MSC_ATOMICS) && (_M_IX86)
   218     return (void *) _InterlockedExchange((long *)a, (long) v);
   219 #elif defined(HAVE_MSC_ATOMICS) && (!_M_IX86)
   220     return _InterlockedExchangePointer(a, v);
   221 #elif defined(HAVE_WATCOM_ATOMICS)
   222     return (void *) _SDL_xchg_watcom((int *)a, (long)v);
   223 #elif defined(HAVE_GCC_ATOMICS)
   224     return __sync_lock_test_and_set(a, v);
   225 #elif defined(__SOLARIS__)
   226     return atomic_swap_ptr(a, v);
   227 #else
   228     void *value;
   229     do {
   230         value = *a;
   231     } while (!SDL_AtomicCASPtr(a, value, v));
   232     return value;
   233 #endif
   234 }
   235 
   236 int
   237 SDL_AtomicAdd(SDL_atomic_t *a, int v)
   238 {
   239 #ifdef HAVE_MSC_ATOMICS
   240     return _InterlockedExchangeAdd((long*)&a->value, v);
   241 #elif defined(HAVE_WATCOM_ATOMICS)
   242     return _SDL_xadd_watcom(&a->value, v);
   243 #elif defined(HAVE_GCC_ATOMICS)
   244     return __sync_fetch_and_add(&a->value, v);
   245 #elif defined(__SOLARIS__)
   246     int pv = a->value;
   247     membar_consumer();
   248 #if defined(_LP64)
   249     atomic_add_64((volatile uint64_t*)&a->value, v);
   250 #elif !defined(_LP64)
   251     atomic_add_32((volatile uint32_t*)&a->value, v);
   252 #endif
   253     return pv;
   254 #else
   255     int value;
   256     do {
   257         value = a->value;
   258     } while (!SDL_AtomicCAS(a, value, (value + v)));
   259     return value;
   260 #endif
   261 }
   262 
   263 int
   264 SDL_AtomicGet(SDL_atomic_t *a)
   265 {
   266 #ifdef HAVE_ATOMIC_LOAD_N
   267     return __atomic_load_n(&a->value, __ATOMIC_SEQ_CST);
   268 #else
   269     int value;
   270     do {
   271         value = a->value;
   272     } while (!SDL_AtomicCAS(a, value, value));
   273     return value;
   274 #endif
   275 }
   276 
   277 void *
   278 SDL_AtomicGetPtr(void **a)
   279 {
   280 #ifdef HAVE_ATOMIC_LOAD_N
   281     return __atomic_load_n(a, __ATOMIC_SEQ_CST);
   282 #else
   283     void *value;
   284     do {
   285         value = *a;
   286     } while (!SDL_AtomicCASPtr(a, value, value));
   287     return value;
   288 #endif
   289 }
   290 
   291 void
   292 SDL_MemoryBarrierReleaseFunction(void)
   293 {
   294     SDL_MemoryBarrierRelease();
   295 }
   296 
   297 void
   298 SDL_MemoryBarrierAcquireFunction(void)
   299 {
   300     SDL_MemoryBarrierAcquire();
   301 }
   302 
   303 /* vi: set ts=4 sw=4 expandtab: */