src/atomic/SDL_atomic.c
author Sam Lantinga
Mon, 09 Jan 2017 11:58:01 -0800
changeset 10802 6afc9b833867
parent 10737 3406a0f8b041
child 10879 773cbb61ad27
permissions -rw-r--r--
We only need the first few keymaps corresponding to the following constants:
K_NORMTAB, K_SHIFTTAB, K_ALTTAB, K_ALTSHIFTTAB

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