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