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