src/atomic/SDL_atomic.c
author Sam Lantinga
Fri, 11 Feb 2011 22:37:15 -0800
changeset 5262 b530ef003506
parent 5095 dceec93471e7
child 5535 96594ac5fd1a
permissions -rw-r--r--
Happy 2011! :)
slouken@5003
     1
/*
slouken@5003
     2
  SDL - Simple DirectMedia Layer
slouken@5262
     3
  Copyright (C) 1997-2011 Sam Lantinga
slouken@5003
     4
slouken@5003
     5
  This library is free software; you can redistribute it and/or
slouken@5003
     6
  modify it under the terms of the GNU Lesser General Public
slouken@5003
     7
  License as published by the Free Software Foundation; either
slouken@5003
     8
  version 2.1 of the License, or (at your option) any later version.
slouken@5003
     9
slouken@5003
    10
  This library is distributed in the hope that it will be useful,
slouken@5003
    11
  but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@5003
    12
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@5003
    13
  Lesser General Public License for more details.
slouken@5003
    14
slouken@5003
    15
  You should have received a copy of the GNU Lesser General Public
slouken@5003
    16
  License along with this library; if not, write to the Free Software
slouken@5003
    17
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@5003
    18
slouken@5003
    19
  Sam Lantinga
slouken@5003
    20
  slouken@libsdl.org
slouken@5003
    21
*/
slouken@5003
    22
#include "SDL_stdinc.h"
slouken@5003
    23
slouken@5003
    24
#include "SDL_atomic.h"
slouken@5003
    25
slouken@5004
    26
/* Note that we undefine the atomic operations here, in case they are
slouken@5004
    27
   defined as compiler intrinsics while building SDL but the library user
slouken@5004
    28
   doesn't have that compiler.  That way we always have a working set of
slouken@5004
    29
   atomic operations built into the library.
slouken@5004
    30
*/
slouken@5004
    31
 
slouken@5003
    32
/* 
slouken@5003
    33
  If any of the operations are not provided then we must emulate some
slouken@5003
    34
  of them. That means we need a nice implementation of spin locks
slouken@5003
    35
  that avoids the "one big lock" problem. We use a vector of spin
slouken@5003
    36
  locks and pick which one to use based on the address of the operand
slouken@5003
    37
  of the function.
slouken@5003
    38
slouken@5003
    39
  To generate the index of the lock we first shift by 3 bits to get
slouken@5003
    40
  rid on the zero bits that result from 32 and 64 bit allignment of
slouken@5003
    41
  data. We then mask off all but 5 bits and use those 5 bits as an
slouken@5003
    42
  index into the table. 
slouken@5003
    43
slouken@5003
    44
  Picking the lock this way insures that accesses to the same data at
slouken@5003
    45
  the same time will go to the same lock. OTOH, accesses to different
slouken@5003
    46
  data have only a 1/32 chance of hitting the same lock. That should
slouken@5003
    47
  pretty much eliminate the chances of several atomic operations on
slouken@5003
    48
  different data from waiting on the same "big lock". If it isn't
slouken@5003
    49
  then the table of locks can be expanded to a new size so long as
slouken@5003
    50
  the new size is a power of two.
slouken@5003
    51
slouken@5003
    52
  Contributed by Bob Pendleton, bob@pendleton.com
slouken@5003
    53
*/
slouken@5003
    54
slouken@5003
    55
static SDL_SpinLock locks[32];
slouken@5003
    56
slouken@5003
    57
static __inline__ void
slouken@5003
    58
enterLock(void *a)
slouken@5003
    59
{
slouken@5004
    60
    uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
slouken@5003
    61
slouken@5004
    62
    SDL_AtomicLock(&locks[index]);
slouken@5003
    63
}
slouken@5003
    64
slouken@5003
    65
static __inline__ void
slouken@5003
    66
leaveLock(void *a)
slouken@5003
    67
{
slouken@5004
    68
    uintptr_t index = ((((uintptr_t)a) >> 3) & 0x1f);
slouken@5003
    69
slouken@5004
    70
    SDL_AtomicUnlock(&locks[index]);
slouken@5003
    71
}
slouken@5003
    72
slouken@5003
    73
SDL_bool
slouken@5095
    74
SDL_AtomicCAS_(SDL_atomic_t *a, int oldval, int newval)
slouken@5003
    75
{
slouken@5004
    76
    SDL_bool retval = SDL_FALSE;
slouken@5003
    77
slouken@5003
    78
    enterLock(a);
slouken@5004
    79
    if (a->value == oldval) {
slouken@5003
    80
        a->value = newval;
slouken@5004
    81
        retval = SDL_TRUE;
slouken@5003
    82
    }
slouken@5003
    83
    leaveLock(a);
slouken@5003
    84
slouken@5004
    85
    return retval;
slouken@5003
    86
}
slouken@5003
    87
slouken@5095
    88
SDL_bool
slouken@5095
    89
SDL_AtomicCASPtr_(void **a, void *oldval, void *newval)
slouken@5003
    90
{
slouken@5004
    91
    SDL_bool retval = SDL_FALSE;
slouken@5003
    92
slouken@5003
    93
    enterLock(a);
slouken@5003
    94
    if (*a == oldval) {
slouken@5003
    95
        *a = newval;
slouken@5004
    96
        retval = SDL_TRUE;
slouken@5003
    97
    }
slouken@5003
    98
    leaveLock(a);
slouken@5003
    99
slouken@5004
   100
    return retval;
slouken@5003
   101
}
slouken@5003
   102
slouken@5003
   103
/* vi: set ts=4 sw=4 expandtab: */