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