test/testatomic.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Sat, 21 Mar 2015 08:01:43 +0100
changeset 9417 86483b23f44a
parent 9356 e87d6e1e812a
child 9619 b94b6d0bff0f
permissions -rw-r--r--
Fixed confusing audio and touch events because of shared enumeration values.
     1 /*
     2   Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
     3 
     4   This software is provided 'as-is', without any express or implied
     5   warranty.  In no event will the authors be held liable for any damages
     6   arising from the use of this software.
     7 
     8   Permission is granted to anyone to use this software for any purpose,
     9   including commercial applications, and to alter it and redistribute it
    10   freely.
    11 */
    12 #include <stdio.h>
    13 
    14 #include "SDL.h"
    15 
    16 /*
    17   Absolutely basic tests just to see if we get the expected value
    18   after calling each function.
    19 */
    20 
    21 static
    22 char *
    23 tf(SDL_bool tf)
    24 {
    25     static char *t = "TRUE";
    26     static char *f = "FALSE";
    27 
    28     if (tf)
    29     {
    30        return t;
    31     }
    32 
    33     return f;
    34 }
    35 
    36 static
    37 void RunBasicTest()
    38 {
    39     int value;
    40     SDL_SpinLock lock = 0;
    41 
    42     SDL_atomic_t v;
    43     SDL_bool tfret = SDL_FALSE;
    44 
    45     SDL_Log("\nspin lock---------------------------------------\n\n");
    46 
    47     SDL_AtomicLock(&lock);
    48     SDL_Log("AtomicLock                   lock=%d\n", lock);
    49     SDL_AtomicUnlock(&lock);
    50     SDL_Log("AtomicUnlock                 lock=%d\n", lock);
    51 
    52     SDL_Log("\natomic -----------------------------------------\n\n");
    53 
    54     SDL_AtomicSet(&v, 0);
    55     tfret = SDL_AtomicSet(&v, 10) == 0 ? SDL_TRUE : SDL_FALSE;
    56     SDL_Log("AtomicSet(10)        tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
    57     tfret = SDL_AtomicAdd(&v, 10) == 10 ? SDL_TRUE : SDL_FALSE;
    58     SDL_Log("AtomicAdd(10)        tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
    59 
    60     SDL_AtomicSet(&v, 0);
    61     SDL_AtomicIncRef(&v);
    62     tfret = (SDL_AtomicGet(&v) == 1) ? SDL_TRUE : SDL_FALSE;
    63     SDL_Log("AtomicIncRef()       tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
    64     SDL_AtomicIncRef(&v);
    65     tfret = (SDL_AtomicGet(&v) == 2) ? SDL_TRUE : SDL_FALSE;
    66     SDL_Log("AtomicIncRef()       tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
    67     tfret = (SDL_AtomicDecRef(&v) == SDL_FALSE) ? SDL_TRUE : SDL_FALSE;
    68     SDL_Log("AtomicDecRef()       tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
    69     tfret = (SDL_AtomicDecRef(&v) == SDL_TRUE) ? SDL_TRUE : SDL_FALSE;
    70     SDL_Log("AtomicDecRef()       tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
    71 
    72     SDL_AtomicSet(&v, 10);
    73     tfret = (SDL_AtomicCAS(&v, 0, 20) == SDL_FALSE) ? SDL_TRUE : SDL_FALSE;
    74     SDL_Log("AtomicCAS()          tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
    75     value = SDL_AtomicGet(&v);
    76     tfret = (SDL_AtomicCAS(&v, value, 20) == SDL_TRUE) ? SDL_TRUE : SDL_FALSE;
    77     SDL_Log("AtomicCAS()          tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
    78 }
    79 
    80 /**************************************************************************/
    81 /* Atomic operation test
    82  * Adapted with permission from code by Michael Davidsaver at:
    83  *  http://bazaar.launchpad.net/~mdavidsaver/epics-base/atomic/revision/12105#src/libCom/test/epicsAtomicTest.c
    84  * Original copyright 2010 Brookhaven Science Associates as operator of Brookhaven National Lab
    85  * http://www.aps.anl.gov/epics/license/open.php
    86  */
    87 
    88 /* Tests semantics of atomic operations.  Also a stress test
    89  * to see if they are really atomic.
    90  *
    91  * Several threads adding to the same variable.
    92  * at the end the value is compared with the expected
    93  * and with a non-atomic counter.
    94  */
    95 
    96 /* Number of concurrent incrementers */
    97 #define NThreads 2
    98 #define CountInc 100
    99 #define VALBITS (sizeof(atomicValue)*8)
   100 
   101 #define atomicValue int
   102 #define CountTo ((atomicValue)((unsigned int)(1<<(VALBITS-1))-1))
   103 #define NInter (CountTo/CountInc/NThreads)
   104 #define Expect (CountTo-NInter*CountInc*NThreads)
   105 
   106 SDL_COMPILE_TIME_ASSERT(size, CountTo>0); /* check for rollover */
   107 
   108 static SDL_atomic_t good = { 42 };
   109 
   110 static atomicValue bad = 42;
   111 
   112 static SDL_atomic_t threadsRunning;
   113 
   114 static SDL_sem *threadDone;
   115 
   116 static
   117 int adder(void* junk)
   118 {
   119     unsigned long N=NInter;
   120     SDL_Log("Thread subtracting %d %lu times\n",CountInc,N);
   121     while (N--) {
   122         SDL_AtomicAdd(&good, -CountInc);
   123         bad-=CountInc;
   124     }
   125     SDL_AtomicAdd(&threadsRunning, -1);
   126     SDL_SemPost(threadDone);
   127     return 0;
   128 }
   129 
   130 static
   131 void runAdder(void)
   132 {
   133     Uint32 start, end;
   134     int T=NThreads;
   135 
   136     start = SDL_GetTicks();
   137 
   138     threadDone = SDL_CreateSemaphore(0);
   139 
   140     SDL_AtomicSet(&threadsRunning, NThreads);
   141 
   142     while (T--)
   143         SDL_CreateThread(adder, "Adder", NULL);
   144 
   145     while (SDL_AtomicGet(&threadsRunning) > 0)
   146         SDL_SemWait(threadDone);
   147 
   148     SDL_DestroySemaphore(threadDone);
   149 
   150     end = SDL_GetTicks();
   151 
   152     SDL_Log("Finished in %f sec\n", (end - start) / 1000.f);
   153 }
   154 
   155 static
   156 void RunEpicTest()
   157 {
   158     int b;
   159     atomicValue v;
   160 
   161     SDL_Log("\nepic test---------------------------------------\n\n");
   162 
   163     SDL_Log("Size asserted to be >= 32-bit\n");
   164     SDL_assert(sizeof(atomicValue)>=4);
   165 
   166     SDL_Log("Check static initializer\n");
   167     v=SDL_AtomicGet(&good);
   168     SDL_assert(v==42);
   169 
   170     SDL_assert(bad==42);
   171 
   172     SDL_Log("Test negative values\n");
   173     SDL_AtomicSet(&good, -5);
   174     v=SDL_AtomicGet(&good);
   175     SDL_assert(v==-5);
   176 
   177     SDL_Log("Verify maximum value\n");
   178     SDL_AtomicSet(&good, CountTo);
   179     v=SDL_AtomicGet(&good);
   180     SDL_assert(v==CountTo);
   181 
   182     SDL_Log("Test compare and exchange\n");
   183 
   184     b=SDL_AtomicCAS(&good, 500, 43);
   185     SDL_assert(!b); /* no swap since CountTo!=500 */
   186     v=SDL_AtomicGet(&good);
   187     SDL_assert(v==CountTo); /* ensure no swap */
   188 
   189     b=SDL_AtomicCAS(&good, CountTo, 44);
   190     SDL_assert(!!b); /* will swap */
   191     v=SDL_AtomicGet(&good);
   192     SDL_assert(v==44);
   193 
   194     SDL_Log("Test Add\n");
   195 
   196     v=SDL_AtomicAdd(&good, 1);
   197     SDL_assert(v==44);
   198     v=SDL_AtomicGet(&good);
   199     SDL_assert(v==45);
   200 
   201     v=SDL_AtomicAdd(&good, 10);
   202     SDL_assert(v==45);
   203     v=SDL_AtomicGet(&good);
   204     SDL_assert(v==55);
   205 
   206     SDL_Log("Test Add (Negative values)\n");
   207 
   208     v=SDL_AtomicAdd(&good, -20);
   209     SDL_assert(v==55);
   210     v=SDL_AtomicGet(&good);
   211     SDL_assert(v==35);
   212 
   213     v=SDL_AtomicAdd(&good, -50); /* crossing zero down */
   214     SDL_assert(v==35);
   215     v=SDL_AtomicGet(&good);
   216     SDL_assert(v==-15);
   217 
   218     v=SDL_AtomicAdd(&good, 30); /* crossing zero up */
   219     SDL_assert(v==-15);
   220     v=SDL_AtomicGet(&good);
   221     SDL_assert(v==15);
   222 
   223     SDL_Log("Reset before count down test\n");
   224     SDL_AtomicSet(&good, CountTo);
   225     v=SDL_AtomicGet(&good);
   226     SDL_assert(v==CountTo);
   227 
   228     bad=CountTo;
   229     SDL_assert(bad==CountTo);
   230 
   231     SDL_Log("Counting down from %d, Expect %d remaining\n",CountTo,Expect);
   232     runAdder();
   233 
   234     v=SDL_AtomicGet(&good);
   235     SDL_Log("Atomic %d Non-Atomic %d\n",v,bad);
   236     SDL_assert(v==Expect);
   237     SDL_assert(bad!=Expect);
   238 }
   239 
   240 /* End atomic operation test */
   241 /**************************************************************************/
   242 
   243 /**************************************************************************/
   244 /* Lock-free FIFO test */
   245 
   246 /* This is useful to test the impact of another thread locking the queue
   247    entirely for heavy-weight manipulation.
   248  */
   249 #define TEST_SPINLOCK_FIFO
   250 
   251 #define NUM_READERS 4
   252 #define NUM_WRITERS 4
   253 #define EVENTS_PER_WRITER   1000000
   254 
   255 /* The number of entries must be a power of 2 */
   256 #define MAX_ENTRIES 256
   257 #define WRAP_MASK   (MAX_ENTRIES-1)
   258 
   259 typedef struct
   260 {
   261     SDL_atomic_t sequence;
   262     SDL_Event event;
   263 } SDL_EventQueueEntry;
   264 
   265 typedef struct
   266 {
   267     SDL_EventQueueEntry entries[MAX_ENTRIES];
   268 
   269     char cache_pad1[SDL_CACHELINE_SIZE-((sizeof(SDL_EventQueueEntry)*MAX_ENTRIES)%SDL_CACHELINE_SIZE)];
   270 
   271     SDL_atomic_t enqueue_pos;
   272 
   273     char cache_pad2[SDL_CACHELINE_SIZE-sizeof(SDL_atomic_t)];
   274 
   275     SDL_atomic_t dequeue_pos;
   276 
   277     char cache_pad3[SDL_CACHELINE_SIZE-sizeof(SDL_atomic_t)];
   278 
   279 #ifdef TEST_SPINLOCK_FIFO
   280     SDL_SpinLock lock;
   281     SDL_atomic_t rwcount;
   282     SDL_atomic_t watcher;
   283 
   284     char cache_pad4[SDL_CACHELINE_SIZE-sizeof(SDL_SpinLock)-2*sizeof(SDL_atomic_t)];
   285 #endif
   286 
   287     volatile SDL_bool active;
   288 
   289     /* Only needed for the mutex test */
   290     SDL_mutex *mutex;
   291 
   292 } SDL_EventQueue;
   293 
   294 static void InitEventQueue(SDL_EventQueue *queue)
   295 {
   296     int i;
   297 
   298     for (i = 0; i < MAX_ENTRIES; ++i) {
   299         SDL_AtomicSet(&queue->entries[i].sequence, i);
   300     }
   301     SDL_AtomicSet(&queue->enqueue_pos, 0);
   302     SDL_AtomicSet(&queue->dequeue_pos, 0);
   303 #ifdef TEST_SPINLOCK_FIFO
   304     queue->lock = 0;
   305     SDL_AtomicSet(&queue->rwcount, 0);
   306     SDL_AtomicSet(&queue->watcher, 0);
   307 #endif
   308     queue->active = SDL_TRUE;
   309 }
   310 
   311 static SDL_bool EnqueueEvent_LockFree(SDL_EventQueue *queue, const SDL_Event *event)
   312 {
   313     SDL_EventQueueEntry *entry;
   314     unsigned queue_pos;
   315     unsigned entry_seq;
   316     int delta;
   317     SDL_bool status;
   318 
   319 #ifdef TEST_SPINLOCK_FIFO
   320     /* This is a gate so an external thread can lock the queue */
   321     SDL_AtomicLock(&queue->lock);
   322     SDL_assert(SDL_AtomicGet(&queue->watcher) == 0);
   323     SDL_AtomicIncRef(&queue->rwcount);
   324     SDL_AtomicUnlock(&queue->lock);
   325 #endif
   326 
   327     queue_pos = (unsigned)SDL_AtomicGet(&queue->enqueue_pos);
   328     for ( ; ; ) {
   329         entry = &queue->entries[queue_pos & WRAP_MASK];
   330         entry_seq = (unsigned)SDL_AtomicGet(&entry->sequence);
   331 
   332         delta = (int)(entry_seq - queue_pos);
   333         if (delta == 0) {
   334             /* The entry and the queue position match, try to increment the queue position */
   335             if (SDL_AtomicCAS(&queue->enqueue_pos, (int)queue_pos, (int)(queue_pos+1))) {
   336                 /* We own the object, fill it! */
   337                 entry->event = *event;
   338                 SDL_AtomicSet(&entry->sequence, (int)(queue_pos + 1));
   339                 status = SDL_TRUE;
   340                 break;
   341             }
   342         } else if (delta < 0) {
   343             /* We ran into an old queue entry, which means it still needs to be dequeued */
   344             status = SDL_FALSE;
   345             break;
   346         } else {
   347             /* We ran into a new queue entry, get the new queue position */
   348             queue_pos = (unsigned)SDL_AtomicGet(&queue->enqueue_pos);
   349         }
   350     }
   351 
   352 #ifdef TEST_SPINLOCK_FIFO
   353     SDL_AtomicDecRef(&queue->rwcount);
   354 #endif
   355     return status;
   356 }
   357 
   358 static SDL_bool DequeueEvent_LockFree(SDL_EventQueue *queue, SDL_Event *event)
   359 {
   360     SDL_EventQueueEntry *entry;
   361     unsigned queue_pos;
   362     unsigned entry_seq;
   363     int delta;
   364     SDL_bool status;
   365 
   366 #ifdef TEST_SPINLOCK_FIFO
   367     /* This is a gate so an external thread can lock the queue */
   368     SDL_AtomicLock(&queue->lock);
   369     SDL_assert(SDL_AtomicGet(&queue->watcher) == 0);
   370     SDL_AtomicIncRef(&queue->rwcount);
   371     SDL_AtomicUnlock(&queue->lock);
   372 #endif
   373 
   374     queue_pos = (unsigned)SDL_AtomicGet(&queue->dequeue_pos);
   375     for ( ; ; ) {
   376         entry = &queue->entries[queue_pos & WRAP_MASK];
   377         entry_seq = (unsigned)SDL_AtomicGet(&entry->sequence);
   378 
   379         delta = (int)(entry_seq - (queue_pos + 1));
   380         if (delta == 0) {
   381             /* The entry and the queue position match, try to increment the queue position */
   382             if (SDL_AtomicCAS(&queue->dequeue_pos, (int)queue_pos, (int)(queue_pos+1))) {
   383                 /* We own the object, fill it! */
   384                 *event = entry->event;
   385                 SDL_AtomicSet(&entry->sequence, (int)(queue_pos+MAX_ENTRIES));
   386                 status = SDL_TRUE;
   387                 break;
   388             }
   389         } else if (delta < 0) {
   390             /* We ran into an old queue entry, which means we've hit empty */
   391             status = SDL_FALSE;
   392             break;
   393         } else {
   394             /* We ran into a new queue entry, get the new queue position */
   395             queue_pos = (unsigned)SDL_AtomicGet(&queue->dequeue_pos);
   396         }
   397     }
   398 
   399 #ifdef TEST_SPINLOCK_FIFO
   400     SDL_AtomicDecRef(&queue->rwcount);
   401 #endif
   402     return status;
   403 }
   404 
   405 static SDL_bool EnqueueEvent_Mutex(SDL_EventQueue *queue, const SDL_Event *event)
   406 {
   407     SDL_EventQueueEntry *entry;
   408     unsigned queue_pos;
   409     unsigned entry_seq;
   410     int delta;
   411     SDL_bool status = SDL_FALSE;
   412 
   413     SDL_LockMutex(queue->mutex);
   414 
   415     queue_pos = (unsigned)queue->enqueue_pos.value;
   416     entry = &queue->entries[queue_pos & WRAP_MASK];
   417     entry_seq = (unsigned)entry->sequence.value;
   418 
   419     delta = (int)(entry_seq - queue_pos);
   420     if (delta == 0) {
   421         ++queue->enqueue_pos.value;
   422 
   423         /* We own the object, fill it! */
   424         entry->event = *event;
   425         entry->sequence.value = (int)(queue_pos + 1);
   426         status = SDL_TRUE;
   427     } else if (delta < 0) {
   428         /* We ran into an old queue entry, which means it still needs to be dequeued */
   429     } else {
   430         SDL_Log("ERROR: mutex failed!\n");
   431     }
   432 
   433     SDL_UnlockMutex(queue->mutex);
   434 
   435     return status;
   436 }
   437 
   438 static SDL_bool DequeueEvent_Mutex(SDL_EventQueue *queue, SDL_Event *event)
   439 {
   440     SDL_EventQueueEntry *entry;
   441     unsigned queue_pos;
   442     unsigned entry_seq;
   443     int delta;
   444     SDL_bool status = SDL_FALSE;
   445 
   446     SDL_LockMutex(queue->mutex);
   447 
   448     queue_pos = (unsigned)queue->dequeue_pos.value;
   449     entry = &queue->entries[queue_pos & WRAP_MASK];
   450     entry_seq = (unsigned)entry->sequence.value;
   451 
   452     delta = (int)(entry_seq - (queue_pos + 1));
   453     if (delta == 0) {
   454         ++queue->dequeue_pos.value;
   455 
   456         /* We own the object, fill it! */
   457         *event = entry->event;
   458         entry->sequence.value = (int)(queue_pos + MAX_ENTRIES);
   459         status = SDL_TRUE;
   460     } else if (delta < 0) {
   461         /* We ran into an old queue entry, which means we've hit empty */
   462     } else {
   463         SDL_Log("ERROR: mutex failed!\n");
   464     }
   465 
   466     SDL_UnlockMutex(queue->mutex);
   467 
   468     return status;
   469 }
   470 
   471 static SDL_sem *writersDone;
   472 static SDL_sem *readersDone;
   473 static SDL_atomic_t writersRunning;
   474 static SDL_atomic_t readersRunning;
   475 
   476 typedef struct
   477 {
   478     SDL_EventQueue *queue;
   479     int index;
   480     char padding1[SDL_CACHELINE_SIZE-(sizeof(SDL_EventQueue*)+sizeof(int))%SDL_CACHELINE_SIZE];
   481     int waits;
   482     SDL_bool lock_free;
   483     char padding2[SDL_CACHELINE_SIZE-sizeof(int)-sizeof(SDL_bool)];
   484 } WriterData;
   485 
   486 typedef struct
   487 {
   488     SDL_EventQueue *queue;
   489     int counters[NUM_WRITERS];
   490     int waits;
   491     SDL_bool lock_free;
   492     char padding[SDL_CACHELINE_SIZE-(sizeof(SDL_EventQueue*)+sizeof(int)*NUM_WRITERS+sizeof(int)+sizeof(SDL_bool))%SDL_CACHELINE_SIZE];
   493 } ReaderData;
   494 
   495 static int FIFO_Writer(void* _data)
   496 {
   497     WriterData *data = (WriterData *)_data;
   498     SDL_EventQueue *queue = data->queue;
   499     int i;
   500     SDL_Event event;
   501 
   502     event.type = SDL_USEREVENT;
   503     event.user.windowID = 0;
   504     event.user.code = 0;
   505     event.user.data1 = data;
   506     event.user.data2 = NULL;
   507 
   508     if (data->lock_free) {
   509         for (i = 0; i < EVENTS_PER_WRITER; ++i) {
   510             event.user.code = i;
   511             while (!EnqueueEvent_LockFree(queue, &event)) {
   512                 ++data->waits;
   513                 SDL_Delay(0);
   514             }
   515         }
   516     } else {
   517         for (i = 0; i < EVENTS_PER_WRITER; ++i) {
   518             event.user.code = i;
   519             while (!EnqueueEvent_Mutex(queue, &event)) {
   520                 ++data->waits;
   521                 SDL_Delay(0);
   522             }
   523         }
   524     }
   525     SDL_AtomicAdd(&writersRunning, -1);
   526     SDL_SemPost(writersDone);
   527     return 0;
   528 }
   529 
   530 static int FIFO_Reader(void* _data)
   531 {
   532     ReaderData *data = (ReaderData *)_data;
   533     SDL_EventQueue *queue = data->queue;
   534     SDL_Event event;
   535 
   536     if (data->lock_free) {
   537         for ( ; ; ) {
   538             if (DequeueEvent_LockFree(queue, &event)) {
   539                 WriterData *writer = (WriterData*)event.user.data1;
   540                 ++data->counters[writer->index];
   541             } else if (queue->active) {
   542                 ++data->waits;
   543                 SDL_Delay(0);
   544             } else {
   545                 /* We drained the queue, we're done! */
   546                 break;
   547             }
   548         }
   549     } else {
   550         for ( ; ; ) {
   551             if (DequeueEvent_Mutex(queue, &event)) {
   552                 WriterData *writer = (WriterData*)event.user.data1;
   553                 ++data->counters[writer->index];
   554             } else if (queue->active) {
   555                 ++data->waits;
   556                 SDL_Delay(0);
   557             } else {
   558                 /* We drained the queue, we're done! */
   559                 break;
   560             }
   561         }
   562     }
   563     SDL_AtomicAdd(&readersRunning, -1);
   564     SDL_SemPost(readersDone);
   565     return 0;
   566 }
   567 
   568 #ifdef TEST_SPINLOCK_FIFO
   569 /* This thread periodically locks the queue for no particular reason */
   570 static int FIFO_Watcher(void* _data)
   571 {
   572     SDL_EventQueue *queue = (SDL_EventQueue *)_data;
   573 
   574     while (queue->active) {
   575         SDL_AtomicLock(&queue->lock);
   576         SDL_AtomicIncRef(&queue->watcher);
   577         while (SDL_AtomicGet(&queue->rwcount) > 0) {
   578             SDL_Delay(0);
   579         }
   580         /* Do queue manipulation here... */
   581         SDL_AtomicDecRef(&queue->watcher);
   582         SDL_AtomicUnlock(&queue->lock);
   583 
   584         /* Wait a bit... */
   585         SDL_Delay(1);
   586     }
   587     return 0;
   588 }
   589 #endif /* TEST_SPINLOCK_FIFO */
   590 
   591 static void RunFIFOTest(SDL_bool lock_free)
   592 {
   593     SDL_EventQueue queue;
   594     WriterData writerData[NUM_WRITERS];
   595     ReaderData readerData[NUM_READERS];
   596     Uint32 start, end;
   597     int i, j;
   598     int grand_total;
   599 	char textBuffer[1024];
   600 	int len;
   601 
   602     SDL_Log("\nFIFO test---------------------------------------\n\n");
   603     SDL_Log("Mode: %s\n", lock_free ? "LockFree" : "Mutex");
   604 
   605     readersDone = SDL_CreateSemaphore(0);
   606     writersDone = SDL_CreateSemaphore(0);
   607 
   608     SDL_memset(&queue, 0xff, sizeof(queue));
   609 
   610     InitEventQueue(&queue);
   611     if (!lock_free) {
   612         queue.mutex = SDL_CreateMutex();
   613     }
   614 
   615     start = SDL_GetTicks();
   616 
   617 #ifdef TEST_SPINLOCK_FIFO
   618     /* Start a monitoring thread */
   619     if (lock_free) {
   620         SDL_CreateThread(FIFO_Watcher, "FIFOWatcher", &queue);
   621     }
   622 #endif
   623 
   624     /* Start the readers first */
   625     SDL_Log("Starting %d readers\n", NUM_READERS);
   626     SDL_zero(readerData);
   627     SDL_AtomicSet(&readersRunning, NUM_READERS);
   628     for (i = 0; i < NUM_READERS; ++i) {
   629         char name[64];
   630         SDL_snprintf(name, sizeof (name), "FIFOReader%d", i);
   631         readerData[i].queue = &queue;
   632         readerData[i].lock_free = lock_free;
   633         SDL_CreateThread(FIFO_Reader, name, &readerData[i]);
   634     }
   635 
   636     /* Start up the writers */
   637     SDL_Log("Starting %d writers\n", NUM_WRITERS);
   638     SDL_zero(writerData);
   639     SDL_AtomicSet(&writersRunning, NUM_WRITERS);
   640     for (i = 0; i < NUM_WRITERS; ++i) {
   641         char name[64];
   642         SDL_snprintf(name, sizeof (name), "FIFOWriter%d", i);
   643         writerData[i].queue = &queue;
   644         writerData[i].index = i;
   645         writerData[i].lock_free = lock_free;
   646         SDL_CreateThread(FIFO_Writer, name, &writerData[i]);
   647     }
   648 
   649     /* Wait for the writers */
   650     while (SDL_AtomicGet(&writersRunning) > 0) {
   651         SDL_SemWait(writersDone);
   652     }
   653 
   654     /* Shut down the queue so readers exit */
   655     queue.active = SDL_FALSE;
   656 
   657     /* Wait for the readers */
   658     while (SDL_AtomicGet(&readersRunning) > 0) {
   659         SDL_SemWait(readersDone);
   660     }
   661 
   662     end = SDL_GetTicks();
   663 
   664     SDL_DestroySemaphore(readersDone);
   665     SDL_DestroySemaphore(writersDone);
   666 
   667     if (!lock_free) {
   668         SDL_DestroyMutex(queue.mutex);
   669     }
   670 
   671     SDL_Log("Finished in %f sec\n", (end - start) / 1000.f);
   672 
   673     SDL_Log("\n");
   674     for (i = 0; i < NUM_WRITERS; ++i) {
   675         SDL_Log("Writer %d wrote %d events, had %d waits\n", i, EVENTS_PER_WRITER, writerData[i].waits);
   676     }
   677     SDL_Log("Writers wrote %d total events\n", NUM_WRITERS*EVENTS_PER_WRITER);
   678 
   679     /* Print a breakdown of which readers read messages from which writer */
   680     SDL_Log("\n");
   681     grand_total = 0;
   682     for (i = 0; i < NUM_READERS; ++i) {
   683         int total = 0;
   684         for (j = 0; j < NUM_WRITERS; ++j) {
   685             total += readerData[i].counters[j];
   686         }
   687         grand_total += total;
   688         SDL_Log("Reader %d read %d events, had %d waits\n", i, total, readerData[i].waits);
   689 		SDL_snprintf(textBuffer, sizeof(textBuffer), "  { ");
   690         for (j = 0; j < NUM_WRITERS; ++j) {
   691             if (j > 0) {
   692 				len = SDL_strlen(textBuffer);
   693                 SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, ", ");
   694             }
   695             len = SDL_strlen(textBuffer);
   696             SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, "%d", readerData[i].counters[j]);
   697         }
   698         len = SDL_strlen(textBuffer);
   699         SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, " }\n");
   700 		SDL_Log("%s", textBuffer);
   701     }
   702     SDL_Log("Readers read %d total events\n", grand_total);
   703 }
   704 
   705 /* End FIFO test */
   706 /**************************************************************************/
   707 
   708 int
   709 main(int argc, char *argv[])
   710 {
   711 	/* Enable standard application logging */
   712 	SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
   713 
   714     RunBasicTest();
   715     RunEpicTest();
   716 /* This test is really slow, so don't run it by default */
   717 #if 0
   718     RunFIFOTest(SDL_FALSE);
   719 #endif
   720     RunFIFOTest(SDL_TRUE);
   721     return 0;
   722 }
   723 
   724 /* vi: set ts=4 sw=4 expandtab: */