src/atomic/SDL_spinlock.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.
slouken@8582
     1
/*
slouken@8582
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
slouken@8582
     4
slouken@8582
     5
  This software is provided 'as-is', without any express or implied
slouken@8582
     6
  warranty.  In no event will the authors be held liable for any damages
slouken@8582
     7
  arising from the use of this software.
slouken@8582
     8
slouken@8582
     9
  Permission is granted to anyone to use this software for any purpose,
slouken@8582
    10
  including commercial applications, and to alter it and redistribute it
slouken@8582
    11
  freely, subject to the following restrictions:
slouken@8582
    12
slouken@8582
    13
  1. The origin of this software must not be misrepresented; you must not
slouken@8582
    14
     claim that you wrote the original software. If you use this software
slouken@8582
    15
     in a product, an acknowledgment in the product documentation would be
slouken@8582
    16
     appreciated but is not required.
slouken@8582
    17
  2. Altered source versions must be plainly marked as such, and must not be
slouken@8582
    18
     misrepresented as being the original software.
slouken@8582
    19
  3. This notice may not be removed or altered from any source distribution.
slouken@8582
    20
*/
icculus@8093
    21
#include "../SDL_internal.h"
slouken@8582
    22
slouken@8582
    23
#if defined(__WIN32__) || defined(__WINRT__)
slouken@8582
    24
#include "../core/windows/SDL_windows.h"
slouken@8582
    25
#endif
slouken@8582
    26
slouken@8582
    27
#include "SDL_atomic.h"
slouken@8582
    28
#include "SDL_mutex.h"
slouken@8582
    29
#include "SDL_timer.h"
slouken@8582
    30
binarycrusader@8979
    31
#if !defined(HAVE_GCC_ATOMICS) && defined(__SOLARIS__)
binarycrusader@8979
    32
#include <atomic.h>
binarycrusader@8979
    33
#endif
slouken@8582
    34
sezeroz@11318
    35
#if defined(__WATCOMC__) && defined(__386__)
sezeroz@11318
    36
SDL_COMPILE_TIME_ASSERT(locksize, 4==sizeof(SDL_SpinLock));
sezeroz@11318
    37
extern _inline int _SDL_xchg_watcom(volatile int *a, int v);
sezeroz@11318
    38
#pragma aux _SDL_xchg_watcom = \
sezeroz@11318
    39
  "xchg [ecx], eax" \
sezeroz@11318
    40
  parm [ecx] [eax] \
sezeroz@11318
    41
  value [eax] \
sezeroz@11318
    42
  modify exact [eax];
sezeroz@11318
    43
#endif /* __WATCOMC__ && __386__ */
sezeroz@11318
    44
slouken@8582
    45
/* This function is where all the magic happens... */
slouken@8582
    46
SDL_bool
slouken@8582
    47
SDL_AtomicTryLock(SDL_SpinLock *lock)
slouken@8582
    48
{
slouken@8582
    49
#if SDL_ATOMIC_DISABLED
slouken@8582
    50
    /* Terrible terrible damage */
slouken@8582
    51
    static SDL_mutex *_spinlock_mutex;
slouken@8582
    52
slouken@8582
    53
    if (!_spinlock_mutex) {
slouken@8582
    54
        /* Race condition on first lock... */
slouken@8582
    55
        _spinlock_mutex = SDL_CreateMutex();
slouken@8582
    56
    }
slouken@8582
    57
    SDL_LockMutex(_spinlock_mutex);
slouken@8582
    58
    if (*lock == 0) {
slouken@8582
    59
        *lock = 1;
slouken@8582
    60
        SDL_UnlockMutex(_spinlock_mutex);
slouken@8582
    61
        return SDL_TRUE;
slouken@8582
    62
    } else {
slouken@8582
    63
        SDL_UnlockMutex(_spinlock_mutex);
slouken@8582
    64
        return SDL_FALSE;
slouken@8582
    65
    }
slouken@8582
    66
slouken@8582
    67
#elif defined(_MSC_VER)
slouken@8582
    68
    SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long));
slouken@8582
    69
    return (InterlockedExchange((long*)lock, 1) == 0);
slouken@8582
    70
sezeroz@11318
    71
#elif defined(__WATCOMC__) && defined(__386__)
sezeroz@11318
    72
    return _SDL_xchg_watcom(lock, 1) == 0;
sezeroz@11318
    73
slouken@8582
    74
#elif HAVE_GCC_ATOMICS || HAVE_GCC_SYNC_LOCK_TEST_AND_SET
slouken@8582
    75
    return (__sync_lock_test_and_set(lock, 1) == 0);
slouken@8582
    76
slouken@8582
    77
#elif defined(__GNUC__) && defined(__arm__) && \
slouken@8582
    78
        (defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \
slouken@8582
    79
         defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5TE__) || \
slouken@8582
    80
         defined(__ARM_ARCH_5TEJ__))
slouken@8582
    81
    int result;
slouken@8582
    82
    __asm__ __volatile__ (
slouken@8582
    83
        "swp %0, %1, [%2]\n"
slouken@8582
    84
        : "=&r,&r" (result) : "r,0" (1), "r,r" (lock) : "memory");
slouken@8582
    85
    return (result == 0);
slouken@8582
    86
slouken@8582
    87
#elif defined(__GNUC__) && defined(__arm__)
slouken@8582
    88
    int result;
slouken@8582
    89
    __asm__ __volatile__ (
slouken@8582
    90
        "ldrex %0, [%2]\nteq   %0, #0\nstrexeq %0, %1, [%2]"
slouken@8582
    91
        : "=&r" (result) : "r" (1), "r" (lock) : "cc", "memory");
slouken@8582
    92
    return (result == 0);
slouken@8582
    93
slouken@8582
    94
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
slouken@8582
    95
    int result;
slouken@8582
    96
    __asm__ __volatile__(
slouken@8582
    97
        "lock ; xchgl %0, (%1)\n"
slouken@8582
    98
        : "=r" (result) : "r" (lock), "0" (1) : "cc", "memory");
slouken@8582
    99
    return (result == 0);
slouken@8582
   100
slouken@8582
   101
#elif defined(__MACOSX__) || defined(__IPHONEOS__)
slouken@8582
   102
    /* Maybe used for PowerPC, but the Intel asm or gcc atomics are favored. */
slouken@8582
   103
    return OSAtomicCompareAndSwap32Barrier(0, 1, lock);
slouken@8582
   104
binarycrusader@8979
   105
#elif defined(__SOLARIS__) && defined(_LP64)
binarycrusader@8979
   106
    /* Used for Solaris with non-gcc compilers. */
binarycrusader@8979
   107
    return (SDL_bool) ((int) atomic_cas_64((volatile uint64_t*)lock, 0, 1) == 0);
binarycrusader@8979
   108
binarycrusader@8979
   109
#elif defined(__SOLARIS__) && !defined(_LP64)
binarycrusader@8979
   110
    /* Used for Solaris with non-gcc compilers. */
binarycrusader@8979
   111
    return (SDL_bool) ((int) atomic_cas_32((volatile uint32_t*)lock, 0, 1) == 0);
binarycrusader@8979
   112
slouken@8582
   113
#else
slouken@8582
   114
#error Please implement for your platform.
slouken@8582
   115
    return SDL_FALSE;
slouken@8582
   116
#endif
slouken@8582
   117
}
slouken@8582
   118
slouken@8582
   119
void
slouken@8582
   120
SDL_AtomicLock(SDL_SpinLock *lock)
slouken@8582
   121
{
slouken@8582
   122
    /* FIXME: Should we have an eventual timeout? */
slouken@8582
   123
    while (!SDL_AtomicTryLock(lock)) {
slouken@8582
   124
        SDL_Delay(0);
slouken@8582
   125
    }
slouken@8582
   126
}
slouken@8582
   127
slouken@8582
   128
void
slouken@8582
   129
SDL_AtomicUnlock(SDL_SpinLock *lock)
slouken@8582
   130
{
slouken@8582
   131
#if defined(_MSC_VER)
slouken@8582
   132
    _ReadWriteBarrier();
slouken@8582
   133
    *lock = 0;
slouken@8582
   134
sezeroz@11318
   135
#elif defined(__WATCOMC__) && defined(__386__)
sezeroz@11318
   136
    SDL_CompilerBarrier ();
sezeroz@11318
   137
    *lock = 0;
sezeroz@11318
   138
slouken@8582
   139
#elif HAVE_GCC_ATOMICS || HAVE_GCC_SYNC_LOCK_TEST_AND_SET
slouken@8582
   140
    __sync_lock_release(lock);
slouken@8582
   141
binarycrusader@8979
   142
#elif defined(__SOLARIS__)
binarycrusader@8979
   143
    /* Used for Solaris when not using gcc. */
binarycrusader@8979
   144
    *lock = 0;
binarycrusader@8979
   145
    membar_producer();
binarycrusader@8979
   146
slouken@8582
   147
#else
slouken@8582
   148
    *lock = 0;
slouken@8582
   149
#endif
slouken@8582
   150
}
slouken@8582
   151
slouken@8582
   152
/* vi: set ts=4 sw=4 expandtab: */