test/testatomic.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 16 Jan 2011 15:16:39 -0800
changeset 5004 0c72ae7b7cb2
parent 5003 3a95a2b93eb3
child 5006 8e8876e4aec6
permissions -rw-r--r--
Added native atomic operations for Windows, Mac OS X, and gcc compiler intrinsics.
Changed the CAS return value to bool, so it's efficient with OSAtomicCompareAndSwap32Barrier()
Added an atomic test adapted from code by Michael Davidsaver
slouken@3338
     1
#include <stdio.h>
bob@3180
     2
#include "SDL.h"
slouken@5004
     3
#include "SDL_assert.h"
bob@3180
     4
bob@3201
     5
/*
bob@3202
     6
  Absolutely basic tests just to see if we get the expected value
bob@3202
     7
  after calling each function.
bob@3201
     8
*/
bob@3201
     9
slouken@5004
    10
static
slouken@3338
    11
char *
bob@3202
    12
tf(SDL_bool tf)
bob@3202
    13
{
slouken@5003
    14
    static char *t = "TRUE";
slouken@5003
    15
    static char *f = "FALSE";
bob@3202
    16
slouken@5003
    17
    if (tf)
slouken@5003
    18
    {
slouken@5003
    19
       return t;
slouken@5003
    20
    }
bob@3202
    21
slouken@5003
    22
    return f;
bob@3202
    23
}
slouken@3338
    24
slouken@5004
    25
static
slouken@5004
    26
void RunBasicTest()
bob@3180
    27
{
slouken@5003
    28
    int value;
slouken@5003
    29
    SDL_SpinLock lock = 0;
bob@3180
    30
slouken@5003
    31
    SDL_bool tfret = SDL_FALSE;
bob@3180
    32
slouken@5003
    33
    printf("\nspin lock---------------------------------------\n\n");
bob@3180
    34
slouken@5003
    35
    SDL_AtomicLock(&lock);
slouken@5003
    36
    printf("AtomicLock                   lock=%d\n", lock);
slouken@5003
    37
    SDL_AtomicUnlock(&lock);
slouken@5003
    38
    printf("AtomicUnlock                 lock=%d\n", lock);
bob@3261
    39
slouken@5003
    40
    printf("\natomic -----------------------------------------\n\n");
bob@3202
    41
slouken@5003
    42
    SDL_atomic_t v;
slouken@5003
    43
     
slouken@5003
    44
    SDL_AtomicSet(&v, 0);
slouken@5003
    45
    tfret = SDL_AtomicSet(&v, 10) == 0;
slouken@5003
    46
    printf("AtomicSet(10)        tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
slouken@5003
    47
    tfret = SDL_AtomicAdd(&v, 10) == 10;
slouken@5003
    48
    printf("AtomicAdd(10)        tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
slouken@3186
    49
slouken@5003
    50
    SDL_AtomicSet(&v, 0);
slouken@5003
    51
    SDL_AtomicIncRef(&v);
slouken@5003
    52
    tfret = (SDL_AtomicGet(&v) == 1);
slouken@5003
    53
    printf("AtomicIncRef()       tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
slouken@5003
    54
    SDL_AtomicIncRef(&v);
slouken@5003
    55
    tfret = (SDL_AtomicGet(&v) == 2);
slouken@5003
    56
    printf("AtomicIncRef()       tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
slouken@5003
    57
    tfret = (SDL_AtomicDecRef(&v) == SDL_FALSE);
slouken@5003
    58
    printf("AtomicDecRef()       tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
slouken@5003
    59
    tfret = (SDL_AtomicDecRef(&v) == SDL_TRUE);
slouken@5003
    60
    printf("AtomicDecRef()       tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
bob@3202
    61
slouken@5003
    62
    SDL_AtomicSet(&v, 10);
slouken@5004
    63
    tfret = (SDL_AtomicCAS(&v, 0, 20) == SDL_FALSE);
slouken@5003
    64
    printf("AtomicCAS()          tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
slouken@5003
    65
    value = SDL_AtomicGet(&v);
slouken@5004
    66
    tfret = (SDL_AtomicCAS(&v, value, 20) == SDL_TRUE);
slouken@5003
    67
    printf("AtomicCAS()          tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
slouken@5004
    68
}
bob@3202
    69
slouken@5004
    70
/* Atomic operation test, adapted from code by Michael Davidsaver at:
slouken@5004
    71
    http://bazaar.launchpad.net/~mdavidsaver/epics-base/atomic/revision/12105#src/libCom/test/epicsAtomicTest.c
slouken@5004
    72
*/
slouken@5004
    73
slouken@5004
    74
/* Tests semantics of atomic operations.  Also a stress test
slouken@5004
    75
 * to see if they are really atomic.
slouken@5004
    76
 *
slouken@5004
    77
 * Serveral threads adding to the same variable.
slouken@5004
    78
 * at the end the value is compared with the expected
slouken@5004
    79
 * and with a non-atomic counter.
slouken@5004
    80
 */
slouken@5004
    81
 
slouken@5004
    82
/* Number of concurrent incrementers */
slouken@5004
    83
#define NThreads 2
slouken@5004
    84
#define CountInc 100
slouken@5004
    85
#define VALBITS (sizeof(atomicValue)*8)
slouken@5004
    86
 
slouken@5004
    87
#define atomicValue int
slouken@5004
    88
#define CountTo ((atomicValue)((unsigned int)(1<<(VALBITS-1))-1))
slouken@5004
    89
#define NInter (CountTo/CountInc/NThreads)
slouken@5004
    90
#define Expect (CountTo-NInter*CountInc*NThreads)
slouken@5004
    91
 
slouken@5004
    92
SDL_COMPILE_TIME_ASSERT(size, CountTo>0); /* check for rollover */
slouken@5004
    93
 
slouken@5004
    94
static SDL_atomic_t good = { 42 };
slouken@5004
    95
 
slouken@5004
    96
static atomicValue bad = 42;
slouken@5004
    97
 
slouken@5004
    98
static SDL_atomic_t threadsRunning;
slouken@5004
    99
slouken@5004
   100
static SDL_sem *threadDone;
slouken@5004
   101
 
slouken@5004
   102
static
slouken@5004
   103
int adder(void* junk)
slouken@5004
   104
{
slouken@5004
   105
    unsigned long N=NInter;
slouken@5004
   106
    printf("Thread subtracting %d %lu times\n",CountInc,N);
slouken@5004
   107
    while (N--) {
slouken@5004
   108
        SDL_AtomicAdd(&good, -CountInc);
slouken@5004
   109
        bad-=CountInc;
slouken@5004
   110
    }
slouken@5004
   111
    SDL_AtomicAdd(&threadsRunning, -1);
slouken@5004
   112
    SDL_SemPost(threadDone);
slouken@5003
   113
    return 0;
slouken@5003
   114
}
slouken@5004
   115
 
slouken@5004
   116
static
slouken@5004
   117
void runAdder(void)
slouken@5004
   118
{
slouken@5004
   119
    Uint32 start, end;
slouken@5004
   120
    int T=NThreads;
slouken@5004
   121
 
slouken@5004
   122
    start = SDL_GetTicks();
slouken@5004
   123
 
slouken@5004
   124
    threadDone = SDL_CreateSemaphore(0);
slouken@5004
   125
slouken@5004
   126
    SDL_AtomicSet(&threadsRunning, NThreads);
slouken@5004
   127
slouken@5004
   128
    while (T--)
slouken@5004
   129
        SDL_CreateThread(adder, NULL);
slouken@5004
   130
 
slouken@5004
   131
    while (SDL_AtomicGet(&threadsRunning) > 0)
slouken@5004
   132
        SDL_SemWait(threadDone);
slouken@5004
   133
 
slouken@5004
   134
    SDL_DestroySemaphore(threadDone);
slouken@5004
   135
slouken@5004
   136
    end = SDL_GetTicks();
slouken@5004
   137
 
slouken@5004
   138
    printf("Finished in %f sec\n", (end - start) / 1000.f);
slouken@5004
   139
}
slouken@5004
   140
 
slouken@5004
   141
static
slouken@5004
   142
void RunEpicTest()
slouken@5004
   143
{
slouken@5004
   144
    int b;
slouken@5004
   145
    atomicValue v;
slouken@5004
   146
 
slouken@5004
   147
    printf("\nepic test---------------------------------------\n\n");
slouken@5004
   148
slouken@5004
   149
    printf("Size asserted to be >= 32-bit\n");
slouken@5004
   150
    SDL_assert(sizeof(atomicValue)>=4);
slouken@5004
   151
 
slouken@5004
   152
    printf("Check static initializer\n");
slouken@5004
   153
    v=SDL_AtomicGet(&good);
slouken@5004
   154
    SDL_assert(v==42);
slouken@5004
   155
 
slouken@5004
   156
    SDL_assert(bad==42);
slouken@5004
   157
 
slouken@5004
   158
    printf("Test negative values\n");
slouken@5004
   159
    SDL_AtomicSet(&good, -5);
slouken@5004
   160
    v=SDL_AtomicGet(&good);
slouken@5004
   161
    SDL_assert(v==-5);
slouken@5004
   162
 
slouken@5004
   163
    printf("Verify maximum value\n");
slouken@5004
   164
    SDL_AtomicSet(&good, CountTo);
slouken@5004
   165
    v=SDL_AtomicGet(&good);
slouken@5004
   166
    SDL_assert(v==CountTo);
slouken@5004
   167
 
slouken@5004
   168
    printf("Test compare and exchange\n");
slouken@5004
   169
 
slouken@5004
   170
    b=SDL_AtomicCAS(&good, 500, 43);
slouken@5004
   171
    SDL_assert(!b); /* no swap since CountTo!=500 */
slouken@5004
   172
    v=SDL_AtomicGet(&good);
slouken@5004
   173
    SDL_assert(v==CountTo); /* ensure no swap */
slouken@5004
   174
 
slouken@5004
   175
    b=SDL_AtomicCAS(&good, CountTo, 44);
slouken@5004
   176
    SDL_assert(!!b); /* will swap */
slouken@5004
   177
    v=SDL_AtomicGet(&good);
slouken@5004
   178
    SDL_assert(v==44);
slouken@5004
   179
 
slouken@5004
   180
    printf("Test Add\n");
slouken@5004
   181
 
slouken@5004
   182
    v=SDL_AtomicAdd(&good, 1);
slouken@5004
   183
    SDL_assert(v==44);
slouken@5004
   184
    v=SDL_AtomicGet(&good);
slouken@5004
   185
    SDL_assert(v==45);
slouken@5004
   186
 
slouken@5004
   187
    v=SDL_AtomicAdd(&good, 10);
slouken@5004
   188
    SDL_assert(v==45);
slouken@5004
   189
    v=SDL_AtomicGet(&good);
slouken@5004
   190
    SDL_assert(v==55);
slouken@5004
   191
 
slouken@5004
   192
    printf("Test Add (Negative values)\n");
slouken@5004
   193
 
slouken@5004
   194
    v=SDL_AtomicAdd(&good, -20);
slouken@5004
   195
    SDL_assert(v==55);
slouken@5004
   196
    v=SDL_AtomicGet(&good);
slouken@5004
   197
    SDL_assert(v==35);
slouken@5004
   198
 
slouken@5004
   199
    v=SDL_AtomicAdd(&good, -50); /* crossing zero down */
slouken@5004
   200
    SDL_assert(v==35);
slouken@5004
   201
    v=SDL_AtomicGet(&good);
slouken@5004
   202
    SDL_assert(v==-15);
slouken@5004
   203
 
slouken@5004
   204
    v=SDL_AtomicAdd(&good, 30); /* crossing zero up */
slouken@5004
   205
    SDL_assert(v==-15);
slouken@5004
   206
    v=SDL_AtomicGet(&good);
slouken@5004
   207
    SDL_assert(v==15);
slouken@5004
   208
 
slouken@5004
   209
    printf("Reset before count down test\n");
slouken@5004
   210
    SDL_AtomicSet(&good, CountTo);
slouken@5004
   211
    v=SDL_AtomicGet(&good);
slouken@5004
   212
    SDL_assert(v==CountTo);
slouken@5004
   213
 
slouken@5004
   214
    bad=CountTo;
slouken@5004
   215
    SDL_assert(bad==CountTo);
slouken@5004
   216
 
slouken@5004
   217
    printf("Counting down from %d, Expect %d remaining\n",CountTo,Expect);
slouken@5004
   218
    runAdder();
slouken@5004
   219
 
slouken@5004
   220
    v=SDL_AtomicGet(&good);
slouken@5004
   221
    printf("Atomic %d Non-Atomic %d\n",v,bad);
slouken@5004
   222
    SDL_assert(v==Expect);
slouken@5004
   223
    SDL_assert(bad!=Expect);
slouken@5004
   224
}
slouken@5004
   225
slouken@5004
   226
int
slouken@5004
   227
main(int argc, char *argv[])
slouken@5004
   228
{
slouken@5004
   229
    RunBasicTest();
slouken@5004
   230
    RunEpicTest();
slouken@5004
   231
    return 0;
slouken@5004
   232
}