view test/testatomic.c @ 5004:0c72ae7b7cb2

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
author Sam Lantinga <slouken@libsdl.org>
date Sun, 16 Jan 2011 15:16:39 -0800
parents 3a95a2b93eb3
children 8e8876e4aec6
line wrap: on
line source

#include <stdio.h>
#include "SDL.h"
#include "SDL_assert.h"

/*
  Absolutely basic tests just to see if we get the expected value
  after calling each function.
*/

static
char *
tf(SDL_bool tf)
{
    static char *t = "TRUE";
    static char *f = "FALSE";

    if (tf)
    {
       return t;
    }

    return f;
}

static
void RunBasicTest()
{
    int value;
    SDL_SpinLock lock = 0;

    SDL_bool tfret = SDL_FALSE;

    printf("\nspin lock---------------------------------------\n\n");

    SDL_AtomicLock(&lock);
    printf("AtomicLock                   lock=%d\n", lock);
    SDL_AtomicUnlock(&lock);
    printf("AtomicUnlock                 lock=%d\n", lock);

    printf("\natomic -----------------------------------------\n\n");

    SDL_atomic_t v;
     
    SDL_AtomicSet(&v, 0);
    tfret = SDL_AtomicSet(&v, 10) == 0;
    printf("AtomicSet(10)        tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
    tfret = SDL_AtomicAdd(&v, 10) == 10;
    printf("AtomicAdd(10)        tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));

    SDL_AtomicSet(&v, 0);
    SDL_AtomicIncRef(&v);
    tfret = (SDL_AtomicGet(&v) == 1);
    printf("AtomicIncRef()       tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
    SDL_AtomicIncRef(&v);
    tfret = (SDL_AtomicGet(&v) == 2);
    printf("AtomicIncRef()       tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
    tfret = (SDL_AtomicDecRef(&v) == SDL_FALSE);
    printf("AtomicDecRef()       tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
    tfret = (SDL_AtomicDecRef(&v) == SDL_TRUE);
    printf("AtomicDecRef()       tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));

    SDL_AtomicSet(&v, 10);
    tfret = (SDL_AtomicCAS(&v, 0, 20) == SDL_FALSE);
    printf("AtomicCAS()          tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
    value = SDL_AtomicGet(&v);
    tfret = (SDL_AtomicCAS(&v, value, 20) == SDL_TRUE);
    printf("AtomicCAS()          tfret=%s val=%"PRIu32"\n", tf(tfret), SDL_AtomicGet(&v));
}

/* Atomic operation test, adapted from code by Michael Davidsaver at:
    http://bazaar.launchpad.net/~mdavidsaver/epics-base/atomic/revision/12105#src/libCom/test/epicsAtomicTest.c
*/

/* Tests semantics of atomic operations.  Also a stress test
 * to see if they are really atomic.
 *
 * Serveral threads adding to the same variable.
 * at the end the value is compared with the expected
 * and with a non-atomic counter.
 */
 
/* Number of concurrent incrementers */
#define NThreads 2
#define CountInc 100
#define VALBITS (sizeof(atomicValue)*8)
 
#define atomicValue int
#define CountTo ((atomicValue)((unsigned int)(1<<(VALBITS-1))-1))
#define NInter (CountTo/CountInc/NThreads)
#define Expect (CountTo-NInter*CountInc*NThreads)
 
SDL_COMPILE_TIME_ASSERT(size, CountTo>0); /* check for rollover */
 
static SDL_atomic_t good = { 42 };
 
static atomicValue bad = 42;
 
static SDL_atomic_t threadsRunning;

static SDL_sem *threadDone;
 
static
int adder(void* junk)
{
    unsigned long N=NInter;
    printf("Thread subtracting %d %lu times\n",CountInc,N);
    while (N--) {
        SDL_AtomicAdd(&good, -CountInc);
        bad-=CountInc;
    }
    SDL_AtomicAdd(&threadsRunning, -1);
    SDL_SemPost(threadDone);
    return 0;
}
 
static
void runAdder(void)
{
    Uint32 start, end;
    int T=NThreads;
 
    start = SDL_GetTicks();
 
    threadDone = SDL_CreateSemaphore(0);

    SDL_AtomicSet(&threadsRunning, NThreads);

    while (T--)
        SDL_CreateThread(adder, NULL);
 
    while (SDL_AtomicGet(&threadsRunning) > 0)
        SDL_SemWait(threadDone);
 
    SDL_DestroySemaphore(threadDone);

    end = SDL_GetTicks();
 
    printf("Finished in %f sec\n", (end - start) / 1000.f);
}
 
static
void RunEpicTest()
{
    int b;
    atomicValue v;
 
    printf("\nepic test---------------------------------------\n\n");

    printf("Size asserted to be >= 32-bit\n");
    SDL_assert(sizeof(atomicValue)>=4);
 
    printf("Check static initializer\n");
    v=SDL_AtomicGet(&good);
    SDL_assert(v==42);
 
    SDL_assert(bad==42);
 
    printf("Test negative values\n");
    SDL_AtomicSet(&good, -5);
    v=SDL_AtomicGet(&good);
    SDL_assert(v==-5);
 
    printf("Verify maximum value\n");
    SDL_AtomicSet(&good, CountTo);
    v=SDL_AtomicGet(&good);
    SDL_assert(v==CountTo);
 
    printf("Test compare and exchange\n");
 
    b=SDL_AtomicCAS(&good, 500, 43);
    SDL_assert(!b); /* no swap since CountTo!=500 */
    v=SDL_AtomicGet(&good);
    SDL_assert(v==CountTo); /* ensure no swap */
 
    b=SDL_AtomicCAS(&good, CountTo, 44);
    SDL_assert(!!b); /* will swap */
    v=SDL_AtomicGet(&good);
    SDL_assert(v==44);
 
    printf("Test Add\n");
 
    v=SDL_AtomicAdd(&good, 1);
    SDL_assert(v==44);
    v=SDL_AtomicGet(&good);
    SDL_assert(v==45);
 
    v=SDL_AtomicAdd(&good, 10);
    SDL_assert(v==45);
    v=SDL_AtomicGet(&good);
    SDL_assert(v==55);
 
    printf("Test Add (Negative values)\n");
 
    v=SDL_AtomicAdd(&good, -20);
    SDL_assert(v==55);
    v=SDL_AtomicGet(&good);
    SDL_assert(v==35);
 
    v=SDL_AtomicAdd(&good, -50); /* crossing zero down */
    SDL_assert(v==35);
    v=SDL_AtomicGet(&good);
    SDL_assert(v==-15);
 
    v=SDL_AtomicAdd(&good, 30); /* crossing zero up */
    SDL_assert(v==-15);
    v=SDL_AtomicGet(&good);
    SDL_assert(v==15);
 
    printf("Reset before count down test\n");
    SDL_AtomicSet(&good, CountTo);
    v=SDL_AtomicGet(&good);
    SDL_assert(v==CountTo);
 
    bad=CountTo;
    SDL_assert(bad==CountTo);
 
    printf("Counting down from %d, Expect %d remaining\n",CountTo,Expect);
    runAdder();
 
    v=SDL_AtomicGet(&good);
    printf("Atomic %d Non-Atomic %d\n",v,bad);
    SDL_assert(v==Expect);
    SDL_assert(bad!=Expect);
}

int
main(int argc, char *argv[])
{
    RunBasicTest();
    RunEpicTest();
    return 0;
}