src/atomic/SDL_spinlock.c
author David Ludwig <dludwig@pobox.com>
Sun, 27 Oct 2013 21:26:46 -0400
changeset 8535 e8ee0708ef5c
parent 8477 ad08f0d710f3
parent 7828 1451063c8ecd
child 8536 a2be4a225f91
permissions -rw-r--r--
WinRT: merged with SDL 2.0.1 codebase
dludwig@8535
     1
/*
dludwig@8535
     2
  Simple DirectMedia Layer
dludwig@8535
     3
  Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
dludwig@8535
     4
dludwig@8535
     5
  This software is provided 'as-is', without any express or implied
dludwig@8535
     6
  warranty.  In no event will the authors be held liable for any damages
dludwig@8535
     7
  arising from the use of this software.
dludwig@8535
     8
dludwig@8535
     9
  Permission is granted to anyone to use this software for any purpose,
dludwig@8535
    10
  including commercial applications, and to alter it and redistribute it
dludwig@8535
    11
  freely, subject to the following restrictions:
dludwig@8535
    12
dludwig@8535
    13
  1. The origin of this software must not be misrepresented; you must not
dludwig@8535
    14
     claim that you wrote the original software. If you use this software
dludwig@8535
    15
     in a product, an acknowledgment in the product documentation would be
dludwig@8535
    16
     appreciated but is not required.
dludwig@8535
    17
  2. Altered source versions must be plainly marked as such, and must not be
dludwig@8535
    18
     misrepresented as being the original software.
dludwig@8535
    19
  3. This notice may not be removed or altered from any source distribution.
dludwig@8535
    20
*/
dludwig@8535
    21
#include "SDL_config.h"
dludwig@8535
    22
dludwig@8535
    23
#ifdef __WIN32__
dludwig@8535
    24
#include "../core/windows/SDL_windows.h"
dludwig@8535
    25
#endif
dludwig@8535
    26
dludwig@8535
    27
#include "SDL_atomic.h"
dludwig@8535
    28
#include "SDL_mutex.h"
dludwig@8535
    29
#include "SDL_timer.h"
dludwig@8535
    30
dludwig@8535
    31
dludwig@8535
    32
/* This function is where all the magic happens... */
dludwig@8535
    33
SDL_bool
dludwig@8535
    34
SDL_AtomicTryLock(SDL_SpinLock *lock)
dludwig@8535
    35
{
dludwig@8535
    36
#if SDL_ATOMIC_DISABLED
dludwig@8535
    37
    /* Terrible terrible damage */
dludwig@8535
    38
    static SDL_mutex *_spinlock_mutex;
dludwig@8535
    39
dludwig@8535
    40
    if (!_spinlock_mutex) {
dludwig@8535
    41
        /* Race condition on first lock... */
dludwig@8535
    42
        _spinlock_mutex = SDL_CreateMutex();
dludwig@8535
    43
    }
dludwig@8535
    44
    SDL_LockMutex(_spinlock_mutex);
dludwig@8535
    45
    if (*lock == 0) {
dludwig@8535
    46
        *lock = 1;
dludwig@8535
    47
        SDL_UnlockMutex(_spinlock_mutex);
dludwig@8535
    48
        return SDL_TRUE;
dludwig@8535
    49
    } else {
dludwig@8535
    50
        SDL_UnlockMutex(_spinlock_mutex);
dludwig@8535
    51
        return SDL_FALSE;
dludwig@8535
    52
    }
dludwig@8535
    53
dludwig@8535
    54
#elif defined(_MSC_VER)
dludwig@8535
    55
    SDL_COMPILE_TIME_ASSERT(locksize, sizeof(*lock) == sizeof(long));
dludwig@8535
    56
    return (InterlockedExchange((long*)lock, 1) == 0);
dludwig@8535
    57
dludwig@8535
    58
#elif HAVE_GCC_ATOMICS || HAVE_GCC_SYNC_LOCK_TEST_AND_SET
dludwig@8535
    59
    return (__sync_lock_test_and_set(lock, 1) == 0);
dludwig@8535
    60
dludwig@8535
    61
#elif defined(__GNUC__) && defined(__arm__) && \
dludwig@8535
    62
        (defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) || \
dludwig@8535
    63
         defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5TE__) || \
dludwig@8535
    64
         defined(__ARM_ARCH_5TEJ__))
dludwig@8535
    65
    int result;
dludwig@8535
    66
    __asm__ __volatile__ (
dludwig@8535
    67
        "swp %0, %1, [%2]\n"
dludwig@8535
    68
        : "=&r,&r" (result) : "r,0" (1), "r,r" (lock) : "memory");
dludwig@8535
    69
    return (result == 0);
dludwig@8535
    70
dludwig@8535
    71
#elif defined(__GNUC__) && defined(__arm__)
dludwig@8535
    72
    int result;
dludwig@8535
    73
    __asm__ __volatile__ (
dludwig@8535
    74
        "ldrex %0, [%2]\nteq   %0, #0\nstrexeq %0, %1, [%2]"
dludwig@8535
    75
        : "=&r" (result) : "r" (1), "r" (lock) : "cc", "memory");
dludwig@8535
    76
    return (result == 0);
dludwig@8535
    77
dludwig@8535
    78
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
dludwig@8535
    79
    int result;
dludwig@8535
    80
    __asm__ __volatile__(
dludwig@8535
    81
        "lock ; xchgl %0, (%1)\n"
dludwig@8535
    82
        : "=r" (result) : "r" (lock), "0" (1) : "cc", "memory");
dludwig@8535
    83
    return (result == 0);
dludwig@8535
    84
dludwig@8535
    85
#elif defined(__MACOSX__) || defined(__IPHONEOS__)
dludwig@8535
    86
    /* Maybe used for PowerPC, but the Intel asm or gcc atomics are favored. */
dludwig@8535
    87
    return OSAtomicCompareAndSwap32Barrier(0, 1, lock);
dludwig@8535
    88
dludwig@8535
    89
#elif HAVE_PTHREAD_SPINLOCK
dludwig@8535
    90
    /* pthread instructions */
dludwig@8535
    91
    return (pthread_spin_trylock(lock) == 0);
dludwig@8535
    92
dludwig@8535
    93
#else
dludwig@8535
    94
#error Please implement for your platform.
dludwig@8535
    95
    return SDL_FALSE;
dludwig@8535
    96
#endif
dludwig@8535
    97
}
dludwig@8535
    98
dludwig@8535
    99
void
dludwig@8535
   100
SDL_AtomicLock(SDL_SpinLock *lock)
dludwig@8535
   101
{
dludwig@8535
   102
    /* FIXME: Should we have an eventual timeout? */
dludwig@8535
   103
    while (!SDL_AtomicTryLock(lock)) {
dludwig@8535
   104
        SDL_Delay(0);
dludwig@8535
   105
    }
dludwig@8535
   106
}
dludwig@8535
   107
dludwig@8535
   108
void
dludwig@8535
   109
SDL_AtomicUnlock(SDL_SpinLock *lock)
dludwig@8535
   110
{
dludwig@8535
   111
#if defined(_MSC_VER)
dludwig@8535
   112
    _ReadWriteBarrier();
dludwig@8535
   113
    *lock = 0;
dludwig@8535
   114
dludwig@8535
   115
#elif HAVE_GCC_ATOMICS || HAVE_GCC_SYNC_LOCK_TEST_AND_SET
dludwig@8535
   116
    __sync_lock_release(lock);
dludwig@8535
   117
dludwig@8535
   118
#elif HAVE_PTHREAD_SPINLOCK
dludwig@8535
   119
    pthread_spin_unlock(lock);
dludwig@8535
   120
dludwig@8535
   121
#else
dludwig@8535
   122
    *lock = 0;
dludwig@8535
   123
#endif
dludwig@8535
   124
}
dludwig@8535
   125
dludwig@8535
   126
/* vi: set ts=4 sw=4 expandtab: */