src/atomic/dummy/SDL_atomic.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 15 Dec 2009 08:11:06 +0000
changeset 3565 f43c8f688f77
parent 3308 0e000afe3dc0
child 3697 f7b03b6838cb
permissions -rw-r--r--
Fixed bug #906

Added better error reporting for OpenGL context creation failing.
     1 /*
     2   SDL - Simple DirectMedia Layer
     3   Copyright (C) 1997-2009 Sam Lantinga
     4 
     5   This library is free software; you can redistribute it and/or
     6   modify it under the terms of the GNU Lesser General Public
     7   License as published by the Free Software Foundation; either
     8   version 2.1 of the License, or (at your option) any later version.
     9 
    10   This library is distributed in the hope that it will be useful,
    11   but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13   Lesser General Public License for more details.
    14 
    15   You should have received a copy of the GNU Lesser General Public
    16   License along with this library; if not, write to the Free Software
    17   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
    18 
    19   Sam Lantinga
    20   slouken@libsdl.org
    21 
    22   Contributed by Bob Pendleton, bob@pendleton.com
    23 */
    24 
    25 #include "SDL_stdinc.h"
    26 #include "SDL_atomic.h"
    27 
    28 #include "SDL_error.h"
    29 
    30 /*
    31   This file provides 32, and 64 bit atomic operations. If the
    32   operations are provided by the native hardware and operating system
    33   they are used. If they are not then the operations are emulated
    34   using the SDL spin lock operations. If spin lock can not be
    35   implemented then these functions must fail.
    36 */
    37 
    38 /* 
    39   DUMMY VERSION.
    40 
    41   This version of the code assumes there is no support for atomic
    42   operations. Therefore, every function sets the SDL error
    43   message. Oddly enough, if you only have one thread then this
    44   version actuallys works.
    45 */
    46 
    47 /*
    48   Native spinlock routines. Because this is the dummy implementation
    49   these will always call SDL_SetError() and do nothing.
    50 */
    51 
    52 void 
    53 SDL_AtomicLock(SDL_SpinLock *lock)
    54 {
    55    SDL_SetError("SDL_atomic.c: is not implemented on this platform");
    56 }
    57 
    58 void 
    59 SDL_AtomicUnlock(SDL_SpinLock *lock)
    60 {
    61    SDL_SetError("SDL_atomic.c: is not implemented on this platform");
    62 }
    63 
    64 /*
    65   Note that platform specific versions can be built from this version
    66   by changing the #undefs to #defines and adding platform specific
    67   code.
    68 */
    69 
    70 #undef  nativeTestThenSet32
    71 #undef  nativeClear32
    72 #undef  nativeFetchThenIncrement32
    73 #undef  nativeFetchThenDecrement32
    74 #undef  nativeFetchThenAdd32
    75 #undef  nativeFetchThenSubtract32
    76 #undef  nativeIncrementThenFetch32
    77 #undef  nativeDecrementThenFetch32
    78 #undef  nativeAddThenFetch32
    79 #undef  nativeSubtractThenFetch32
    80 
    81 #undef  nativeTestThenSet64
    82 #undef  nativeClear64
    83 #undef  nativeFetchThenIncrement64
    84 #undef  nativeFetchThenDecrement64
    85 #undef  nativeFetchThenAdd64
    86 #undef  nativeFetchThenSubtract64
    87 #undef  nativeIncrementThenFetch64
    88 #undef  nativeDecrementThenFetch64
    89 #undef  nativeAddThenFetch64
    90 #undef  nativeSubtractThenFetch64
    91 
    92 /* 
    93   If any of the operations are not provided then we must emulate some
    94   of them. That means we need a nice implementation of spin locks
    95   that avoids the "one big lock" problem. We use a vector of spin
    96   locks and pick which one to use based on the address of the operand
    97   of the function.
    98 
    99   To generate the index of the lock we first shift by 3 bits to get
   100   rid on the zero bits that result from 32 and 64 bit allignment of
   101   data. We then mask off all but 5 bits and use those 5 bits as an
   102   index into the table. 
   103 
   104   Picking the lock this way insures that accesses to the same data at
   105   the same time will go to the same lock. OTOH, accesses to different
   106   data have only a 1/32 chance of hitting the same lock. That should
   107   pretty much eliminate the chances of several atomic operations on
   108   different data from waiting on the same "big lock". If it isn't
   109   then the table of locks can be expanded to a new size so long as
   110   the new size is a power of two.
   111 */
   112 
   113 static SDL_SpinLock locks[32] = {
   114    0, 0, 0, 0, 0, 0, 0, 0,
   115    0, 0, 0, 0, 0, 0, 0, 0,
   116    0, 0, 0, 0, 0, 0, 0, 0,
   117    0, 0, 0, 0, 0, 0, 0, 0,
   118 };
   119 
   120 static __inline__ void
   121 privateWaitLock(volatile void *ptr)
   122 {
   123 #if SIZEOF_VOIDP == 4
   124    Uint32 index = ((((Uint32)ptr) >> 3) & 0x1f);
   125 #elif SIZEOF_VOIDP == 8
   126    Uint64 index = ((((Uint64)ptr) >> 3) & 0x1f);
   127 #endif
   128 
   129    SDL_AtomicLock(&locks[index]);
   130 }
   131 
   132 static __inline__ void
   133 privateUnlock(volatile void *ptr)
   134 {
   135 #if SIZEOF_VOIDP == 4
   136    Uint32 index = ((((Uint32)ptr) >> 3) & 0x1f);
   137 #elif SIZEOF_VOIDP == 8
   138    Uint64 index = ((((Uint64)ptr) >> 3) & 0x1f);
   139 #endif
   140 
   141    SDL_AtomicUnlock(&locks[index]);
   142 }
   143 
   144 /* 32 bit atomic operations */
   145 
   146 SDL_bool
   147 SDL_AtomicTestThenSet32(volatile Uint32 * ptr)
   148 {
   149 #ifdef nativeTestThenSet32
   150 #else
   151    SDL_bool result = SDL_FALSE;
   152 
   153    privateWaitLock(ptr);
   154    result = (*ptr == 0);
   155    if (result)
   156    {
   157       *ptr = 1;
   158    }
   159    privateUnlock(ptr);
   160 
   161    return result;
   162 #endif
   163 }
   164 
   165 void
   166 SDL_AtomicClear32(volatile Uint32 * ptr)
   167 {
   168 #ifdef nativeClear32
   169 #else
   170    privateWaitLock(ptr);
   171    *ptr = 0;
   172    privateUnlock(ptr);
   173 
   174    return;
   175 #endif
   176 }
   177 
   178 Uint32
   179 SDL_AtomicFetchThenIncrement32(volatile Uint32 * ptr)
   180 {
   181 #ifdef nativeFetchThenIncrement32
   182 #else
   183    Uint32 tmp = 0;
   184 
   185    privateWaitLock(ptr);
   186    tmp = *ptr;
   187    (*ptr)+= 1;
   188    privateUnlock(ptr);
   189 
   190    return tmp;
   191 #endif
   192 }
   193 
   194 Uint32
   195 SDL_AtomicFetchThenDecrement32(volatile Uint32 * ptr)
   196 {
   197 #ifdef nativeFetchThenDecrement32
   198 #else
   199    Uint32 tmp = 0;
   200 
   201    privateWaitLock(ptr);
   202    tmp = *ptr;
   203    (*ptr) -= 1;
   204    privateUnlock(ptr);
   205 
   206    return tmp;
   207 #endif
   208 }
   209 
   210 Uint32
   211 SDL_AtomicFetchThenAdd32(volatile Uint32 * ptr, Uint32 value)
   212 {
   213 #ifdef nativeFetchThenAdd32
   214 #else
   215    Uint32 tmp = 0;
   216 
   217    privateWaitLock(ptr);
   218    tmp = *ptr;
   219    (*ptr)+= value;
   220    privateUnlock(ptr);
   221 
   222    return tmp;
   223 #endif
   224 }
   225 
   226 Uint32
   227 SDL_AtomicFetchThenSubtract32(volatile Uint32 * ptr, Uint32 value)
   228 {
   229 #ifdef nativeFetchThenSubtract32
   230 #else
   231    Uint32 tmp = 0;
   232 
   233    privateWaitLock(ptr);
   234    tmp = *ptr;
   235    (*ptr)-= value;
   236    privateUnlock(ptr);
   237 
   238    return tmp;
   239 #endif
   240 }
   241 
   242 Uint32
   243 SDL_AtomicIncrementThenFetch32(volatile Uint32 * ptr)
   244 {
   245 #ifdef nativeIncrementThenFetch32
   246 #else
   247    Uint32 tmp = 0;
   248 
   249    privateWaitLock(ptr);
   250    (*ptr)+= 1;
   251    tmp = *ptr;
   252    privateUnlock(ptr);
   253 
   254    return tmp;
   255 #endif
   256 }
   257 
   258 Uint32
   259 SDL_AtomicDecrementThenFetch32(volatile Uint32 * ptr)
   260 {
   261 #ifdef nativeDecrementThenFetch32
   262 #else
   263    Uint32 tmp = 0;
   264 
   265    privateWaitLock(ptr);
   266    (*ptr)-= 1;
   267    tmp = *ptr;
   268    privateUnlock(ptr);
   269 
   270    return tmp;
   271 #endif
   272 }
   273 
   274 Uint32
   275 SDL_AtomicAddThenFetch32(volatile Uint32 * ptr, Uint32 value)
   276 {
   277 #ifdef nativeAddThenFetch32
   278 #else
   279    Uint32 tmp = 0;
   280 
   281    privateWaitLock(ptr);
   282    (*ptr)+= value;
   283    tmp = *ptr;
   284    privateUnlock(ptr);
   285 
   286    return tmp;
   287 #endif
   288 }
   289 
   290 Uint32
   291 SDL_AtomicSubtractThenFetch32(volatile Uint32 * ptr, Uint32 value)
   292 {
   293 #ifdef nativeSubtractThenFetch32
   294 #else
   295    Uint32 tmp = 0;
   296 
   297    privateWaitLock(ptr);
   298    (*ptr)-= value;
   299    tmp = *ptr;
   300    privateUnlock(ptr);
   301 
   302    return tmp;
   303 #endif
   304 }
   305 
   306 /* 64 bit atomic operations */
   307 #ifdef SDL_HAS_64BIT_TYPE
   308 
   309 SDL_bool
   310 SDL_AtomicTestThenSet64(volatile Uint64 * ptr)
   311 {
   312 #ifdef nativeTestThenSet64
   313 #else
   314    SDL_bool result = SDL_FALSE;
   315 
   316    privateWaitLock(ptr);
   317    result = (*ptr == 0);
   318    if (result)
   319    {
   320       *ptr = 1;
   321    }
   322    privateUnlock(ptr);
   323 
   324    return result;
   325 #endif
   326 }
   327 
   328 void
   329 SDL_AtomicClear64(volatile Uint64 * ptr)
   330 {
   331 #ifdef nativeClear64
   332 #else
   333    privateWaitLock(ptr);
   334    *ptr = 0;
   335    privateUnlock(ptr);
   336 
   337    return;
   338 #endif
   339 }
   340 
   341 Uint64
   342 SDL_AtomicFetchThenIncrement64(volatile Uint64 * ptr)
   343 {
   344 #ifdef nativeFetchThenIncrement64
   345 #else
   346    Uint64 tmp = 0;
   347 
   348    privateWaitLock(ptr);
   349    tmp = *ptr;
   350    (*ptr)+= 1;
   351    privateUnlock(ptr);
   352 
   353    return tmp;
   354 #endif
   355 }
   356 
   357 Uint64
   358 SDL_AtomicFetchThenDecrement64(volatile Uint64 * ptr)
   359 {
   360 #ifdef nativeFetchThenDecrement64
   361 #else
   362    Uint64 tmp = 0;
   363 
   364    privateWaitLock(ptr);
   365    tmp = *ptr;
   366    (*ptr) -= 1;
   367    privateUnlock(ptr);
   368 
   369    return tmp;
   370 #endif
   371 }
   372 
   373 Uint64
   374 SDL_AtomicFetchThenAdd64(volatile Uint64 * ptr, Uint64 value)
   375 {
   376 #ifdef nativeFetchThenAdd64
   377 #else
   378    Uint64 tmp = 0;
   379 
   380    privateWaitLock(ptr);
   381    tmp = *ptr;
   382    (*ptr)+= value;
   383    privateUnlock(ptr);
   384 
   385    return tmp;
   386 #endif
   387 }
   388 
   389 Uint64
   390 SDL_AtomicFetchThenSubtract64(volatile Uint64 * ptr, Uint64 value)
   391 {
   392 #ifdef nativeFetchThenSubtract64
   393 #else
   394    Uint64 tmp = 0;
   395 
   396    privateWaitLock(ptr);
   397    tmp = *ptr;
   398    (*ptr)-= value;
   399    privateUnlock(ptr);
   400 
   401    return tmp;
   402 #endif
   403 }
   404 
   405 Uint64
   406 SDL_AtomicIncrementThenFetch64(volatile Uint64 * ptr)
   407 {
   408 #ifdef nativeIncrementThenFetch64
   409 #else
   410    Uint64 tmp = 0;
   411 
   412    privateWaitLock(ptr);
   413    (*ptr)+= 1;
   414    tmp = *ptr;
   415    privateUnlock(ptr);
   416 
   417    return tmp;
   418 #endif
   419 }
   420 
   421 Uint64
   422 SDL_AtomicDecrementThenFetch64(volatile Uint64 * ptr)
   423 {
   424 #ifdef nativeDecrementThenFetch64
   425 #else
   426    Uint64 tmp = 0;
   427 
   428    privateWaitLock(ptr);
   429    (*ptr)-= 1;
   430    tmp = *ptr;
   431    privateUnlock(ptr);
   432 
   433    return tmp;
   434 #endif
   435 }
   436 
   437 Uint64
   438 SDL_AtomicAddThenFetch64(volatile Uint64 * ptr, Uint64 value)
   439 {
   440 #ifdef nativeAddThenFetch64
   441 #else
   442    Uint64 tmp = 0;
   443 
   444    privateWaitLock(ptr);
   445    (*ptr)+= value;
   446    tmp = *ptr;
   447    privateUnlock(ptr);
   448 
   449    return tmp;
   450 #endif
   451 }
   452 
   453 Uint64
   454 SDL_AtomicSubtractThenFetch64(volatile Uint64 * ptr, Uint64 value)
   455 {
   456 #ifdef nativeSubtractThenFetch64
   457 #else
   458    Uint64 tmp = 0;
   459 
   460    privateWaitLock(ptr);
   461    (*ptr)-= value;
   462    tmp = *ptr;
   463    privateUnlock(ptr);
   464 
   465    return tmp;
   466 #endif
   467 }
   468 #endif
   469