123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756 |
- /*
- Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org>
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely.
- */
- #include <SDL3/SDL.h>
- #include <SDL3/SDL_main.h>
- #include <SDL3/SDL_test.h>
- /*
- Absolutely basic tests just to see if we get the expected value
- after calling each function.
- */
- static const char *
- tf(bool _tf)
- {
- static const char *t = "TRUE";
- static const char *f = "FALSE";
- if (_tf) {
- return t;
- }
- return f;
- }
- static void RunBasicTest(void)
- {
- int value;
- SDL_SpinLock lock = 0;
- SDL_AtomicInt v;
- bool tfret = false;
- SDL_Log("\nspin lock---------------------------------------\n\n");
- SDL_LockSpinlock(&lock);
- SDL_Log("AtomicLock lock=%d\n", lock);
- SDL_UnlockSpinlock(&lock);
- SDL_Log("AtomicUnlock lock=%d\n", lock);
- SDL_Log("\natomic -----------------------------------------\n\n");
- SDL_SetAtomicInt(&v, 0);
- tfret = SDL_SetAtomicInt(&v, 10) == 0;
- SDL_Log("AtomicSet(10) tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v));
- tfret = SDL_AddAtomicInt(&v, 10) == 10;
- SDL_Log("AtomicAdd(10) tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v));
- SDL_SetAtomicInt(&v, 0);
- SDL_AtomicIncRef(&v);
- tfret = (SDL_GetAtomicInt(&v) == 1);
- SDL_Log("AtomicIncRef() tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v));
- SDL_AtomicIncRef(&v);
- tfret = (SDL_GetAtomicInt(&v) == 2);
- SDL_Log("AtomicIncRef() tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v));
- tfret = (SDL_AtomicDecRef(&v) == false);
- SDL_Log("AtomicDecRef() tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v));
- tfret = (SDL_AtomicDecRef(&v) == true);
- SDL_Log("AtomicDecRef() tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v));
- SDL_SetAtomicInt(&v, 10);
- tfret = (SDL_CompareAndSwapAtomicInt(&v, 0, 20) == false);
- SDL_Log("AtomicCAS() tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v));
- value = SDL_GetAtomicInt(&v);
- tfret = (SDL_CompareAndSwapAtomicInt(&v, value, 20) == true);
- SDL_Log("AtomicCAS() tfret=%s val=%d\n", tf(tfret), SDL_GetAtomicInt(&v));
- }
- /**************************************************************************/
- /* Atomic operation test
- * Adapted with permission from code by Michael Davidsaver at:
- * http://bazaar.launchpad.net/~mdavidsaver/epics-base/atomic/revision/12105#src/libCom/test/epicsAtomicTest.c
- * Original copyright 2010 Brookhaven Science Associates as operator of Brookhaven National Lab
- * http://www.aps.anl.gov/epics/license/open.php
- */
- /* Tests semantics of atomic operations. Also a stress test
- * to see if they are really atomic.
- *
- * Several 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)
- enum
- {
- CountTo_GreaterThanZero = CountTo > 0,
- };
- SDL_COMPILE_TIME_ASSERT(size, CountTo_GreaterThanZero); /* check for rollover */
- static SDL_AtomicInt good = { 42 };
- static atomicValue bad = 42;
- static SDL_AtomicInt threadsRunning;
- static SDL_Semaphore *threadDone;
- static int SDLCALL adder(void *junk)
- {
- unsigned long N = NInter;
- SDL_Log("Thread subtracting %d %lu times\n", CountInc, N);
- while (N--) {
- SDL_AddAtomicInt(&good, -CountInc);
- bad -= CountInc;
- }
- SDL_AddAtomicInt(&threadsRunning, -1);
- SDL_SignalSemaphore(threadDone);
- return 0;
- }
- static void runAdder(void)
- {
- Uint64 start, end;
- int i;
- SDL_Thread *threads[NThreads];
- start = SDL_GetTicksNS();
- threadDone = SDL_CreateSemaphore(0);
- SDL_SetAtomicInt(&threadsRunning, NThreads);
- for (i = 0; i < NThreads; i++) {
- threads[i] = SDL_CreateThread(adder, "Adder", NULL);
- }
- while (SDL_GetAtomicInt(&threadsRunning) > 0) {
- SDL_WaitSemaphore(threadDone);
- }
- for (i = 0; i < NThreads; i++) {
- SDL_WaitThread(threads[i], NULL);
- }
- SDL_DestroySemaphore(threadDone);
- end = SDL_GetTicksNS();
- SDL_Log("Finished in %f sec\n", (end - start) / 1000000000.0);
- }
- static void RunEpicTest(void)
- {
- int b;
- atomicValue v;
- SDL_Log("\nepic test---------------------------------------\n\n");
- SDL_Log("Size asserted to be >= 32-bit\n");
- SDL_assert(sizeof(atomicValue) >= 4);
- SDL_Log("Check static initializer\n");
- v = SDL_GetAtomicInt(&good);
- SDL_assert(v == 42);
- SDL_assert(bad == 42);
- SDL_Log("Test negative values\n");
- SDL_SetAtomicInt(&good, -5);
- v = SDL_GetAtomicInt(&good);
- SDL_assert(v == -5);
- SDL_Log("Verify maximum value\n");
- SDL_SetAtomicInt(&good, CountTo);
- v = SDL_GetAtomicInt(&good);
- SDL_assert(v == CountTo);
- SDL_Log("Test compare and exchange\n");
- b = SDL_CompareAndSwapAtomicInt(&good, 500, 43);
- SDL_assert(!b); /* no swap since CountTo!=500 */
- v = SDL_GetAtomicInt(&good);
- SDL_assert(v == CountTo); /* ensure no swap */
- b = SDL_CompareAndSwapAtomicInt(&good, CountTo, 44);
- SDL_assert(!!b); /* will swap */
- v = SDL_GetAtomicInt(&good);
- SDL_assert(v == 44);
- SDL_Log("Test Add\n");
- v = SDL_AddAtomicInt(&good, 1);
- SDL_assert(v == 44);
- v = SDL_GetAtomicInt(&good);
- SDL_assert(v == 45);
- v = SDL_AddAtomicInt(&good, 10);
- SDL_assert(v == 45);
- v = SDL_GetAtomicInt(&good);
- SDL_assert(v == 55);
- SDL_Log("Test Add (Negative values)\n");
- v = SDL_AddAtomicInt(&good, -20);
- SDL_assert(v == 55);
- v = SDL_GetAtomicInt(&good);
- SDL_assert(v == 35);
- v = SDL_AddAtomicInt(&good, -50); /* crossing zero down */
- SDL_assert(v == 35);
- v = SDL_GetAtomicInt(&good);
- SDL_assert(v == -15);
- v = SDL_AddAtomicInt(&good, 30); /* crossing zero up */
- SDL_assert(v == -15);
- v = SDL_GetAtomicInt(&good);
- SDL_assert(v == 15);
- SDL_Log("Reset before count down test\n");
- SDL_SetAtomicInt(&good, CountTo);
- v = SDL_GetAtomicInt(&good);
- SDL_assert(v == CountTo);
- bad = CountTo;
- SDL_assert(bad == CountTo);
- SDL_Log("Counting down from %d, Expect %d remaining\n", CountTo, Expect);
- runAdder();
- v = SDL_GetAtomicInt(&good);
- SDL_Log("Atomic %d Non-Atomic %d\n", v, bad);
- SDL_assert(v == Expect);
- /* We can't guarantee that bad != Expect, this would happen on a single core system, for example. */
- /*SDL_assert(bad != Expect);*/
- }
- /* End atomic operation test */
- /**************************************************************************/
- /**************************************************************************/
- /* Lock-free FIFO test */
- /* This is useful to test the impact of another thread locking the queue
- entirely for heavy-weight manipulation.
- */
- #define TEST_SPINLOCK_FIFO
- #define NUM_READERS 4
- #define NUM_WRITERS 4
- #define EVENTS_PER_WRITER 1000000
- /* The number of entries must be a power of 2 */
- #define MAX_ENTRIES 256
- #define WRAP_MASK (MAX_ENTRIES - 1)
- typedef struct
- {
- SDL_AtomicInt sequence;
- SDL_Event event;
- } SDL_EventQueueEntry;
- typedef struct
- {
- SDL_EventQueueEntry entries[MAX_ENTRIES];
- char cache_pad1[SDL_CACHELINE_SIZE - ((sizeof(SDL_EventQueueEntry) * MAX_ENTRIES) % SDL_CACHELINE_SIZE)];
- SDL_AtomicInt enqueue_pos;
- char cache_pad2[SDL_CACHELINE_SIZE - sizeof(SDL_AtomicInt)];
- SDL_AtomicInt dequeue_pos;
- char cache_pad3[SDL_CACHELINE_SIZE - sizeof(SDL_AtomicInt)];
- #ifdef TEST_SPINLOCK_FIFO
- SDL_SpinLock lock;
- SDL_AtomicInt rwcount;
- SDL_AtomicInt watcher;
- char cache_pad4[SDL_CACHELINE_SIZE - sizeof(SDL_SpinLock) - 2 * sizeof(SDL_AtomicInt)];
- #endif
- SDL_AtomicInt active;
- /* Only needed for the mutex test */
- SDL_Mutex *mutex;
- } SDL_EventQueue;
- static void InitEventQueue(SDL_EventQueue *queue)
- {
- int i;
- for (i = 0; i < MAX_ENTRIES; ++i) {
- SDL_SetAtomicInt(&queue->entries[i].sequence, i);
- }
- SDL_SetAtomicInt(&queue->enqueue_pos, 0);
- SDL_SetAtomicInt(&queue->dequeue_pos, 0);
- #ifdef TEST_SPINLOCK_FIFO
- queue->lock = 0;
- SDL_SetAtomicInt(&queue->rwcount, 0);
- SDL_SetAtomicInt(&queue->watcher, 0);
- #endif
- SDL_SetAtomicInt(&queue->active, 1);
- }
- static bool EnqueueEvent_LockFree(SDL_EventQueue *queue, const SDL_Event *event)
- {
- SDL_EventQueueEntry *entry;
- unsigned queue_pos;
- unsigned entry_seq;
- int delta;
- bool status;
- #ifdef TEST_SPINLOCK_FIFO
- /* This is a gate so an external thread can lock the queue */
- SDL_LockSpinlock(&queue->lock);
- SDL_assert(SDL_GetAtomicInt(&queue->watcher) == 0);
- SDL_AtomicIncRef(&queue->rwcount);
- SDL_UnlockSpinlock(&queue->lock);
- #endif
- queue_pos = (unsigned)SDL_GetAtomicInt(&queue->enqueue_pos);
- for (;;) {
- entry = &queue->entries[queue_pos & WRAP_MASK];
- entry_seq = (unsigned)SDL_GetAtomicInt(&entry->sequence);
- delta = (int)(entry_seq - queue_pos);
- if (delta == 0) {
- /* The entry and the queue position match, try to increment the queue position */
- if (SDL_CompareAndSwapAtomicInt(&queue->enqueue_pos, (int)queue_pos, (int)(queue_pos + 1))) {
- /* We own the object, fill it! */
- entry->event = *event;
- SDL_SetAtomicInt(&entry->sequence, (int)(queue_pos + 1));
- status = true;
- break;
- }
- } else if (delta < 0) {
- /* We ran into an old queue entry, which means it still needs to be dequeued */
- status = false;
- break;
- } else {
- /* We ran into a new queue entry, get the new queue position */
- queue_pos = (unsigned)SDL_GetAtomicInt(&queue->enqueue_pos);
- }
- }
- #ifdef TEST_SPINLOCK_FIFO
- (void)SDL_AtomicDecRef(&queue->rwcount);
- #endif
- return status;
- }
- static bool DequeueEvent_LockFree(SDL_EventQueue *queue, SDL_Event *event)
- {
- SDL_EventQueueEntry *entry;
- unsigned queue_pos;
- unsigned entry_seq;
- int delta;
- bool status;
- #ifdef TEST_SPINLOCK_FIFO
- /* This is a gate so an external thread can lock the queue */
- SDL_LockSpinlock(&queue->lock);
- SDL_assert(SDL_GetAtomicInt(&queue->watcher) == 0);
- SDL_AtomicIncRef(&queue->rwcount);
- SDL_UnlockSpinlock(&queue->lock);
- #endif
- queue_pos = (unsigned)SDL_GetAtomicInt(&queue->dequeue_pos);
- for (;;) {
- entry = &queue->entries[queue_pos & WRAP_MASK];
- entry_seq = (unsigned)SDL_GetAtomicInt(&entry->sequence);
- delta = (int)(entry_seq - (queue_pos + 1));
- if (delta == 0) {
- /* The entry and the queue position match, try to increment the queue position */
- if (SDL_CompareAndSwapAtomicInt(&queue->dequeue_pos, (int)queue_pos, (int)(queue_pos + 1))) {
- /* We own the object, fill it! */
- *event = entry->event;
- SDL_SetAtomicInt(&entry->sequence, (int)(queue_pos + MAX_ENTRIES));
- status = true;
- break;
- }
- } else if (delta < 0) {
- /* We ran into an old queue entry, which means we've hit empty */
- status = false;
- break;
- } else {
- /* We ran into a new queue entry, get the new queue position */
- queue_pos = (unsigned)SDL_GetAtomicInt(&queue->dequeue_pos);
- }
- }
- #ifdef TEST_SPINLOCK_FIFO
- (void)SDL_AtomicDecRef(&queue->rwcount);
- #endif
- return status;
- }
- static bool EnqueueEvent_Mutex(SDL_EventQueue *queue, const SDL_Event *event)
- {
- SDL_EventQueueEntry *entry;
- unsigned queue_pos;
- unsigned entry_seq;
- int delta;
- bool status = false;
- SDL_LockMutex(queue->mutex);
- queue_pos = (unsigned)queue->enqueue_pos.value;
- entry = &queue->entries[queue_pos & WRAP_MASK];
- entry_seq = (unsigned)entry->sequence.value;
- delta = (int)(entry_seq - queue_pos);
- if (delta == 0) {
- ++queue->enqueue_pos.value;
- /* We own the object, fill it! */
- entry->event = *event;
- entry->sequence.value = (int)(queue_pos + 1);
- status = true;
- } else if (delta < 0) {
- /* We ran into an old queue entry, which means it still needs to be dequeued */
- } else {
- SDL_Log("ERROR: mutex failed!\n");
- }
- SDL_UnlockMutex(queue->mutex);
- return status;
- }
- static bool DequeueEvent_Mutex(SDL_EventQueue *queue, SDL_Event *event)
- {
- SDL_EventQueueEntry *entry;
- unsigned queue_pos;
- unsigned entry_seq;
- int delta;
- bool status = false;
- SDL_LockMutex(queue->mutex);
- queue_pos = (unsigned)queue->dequeue_pos.value;
- entry = &queue->entries[queue_pos & WRAP_MASK];
- entry_seq = (unsigned)entry->sequence.value;
- delta = (int)(entry_seq - (queue_pos + 1));
- if (delta == 0) {
- ++queue->dequeue_pos.value;
- /* We own the object, fill it! */
- *event = entry->event;
- entry->sequence.value = (int)(queue_pos + MAX_ENTRIES);
- status = true;
- } else if (delta < 0) {
- /* We ran into an old queue entry, which means we've hit empty */
- } else {
- SDL_Log("ERROR: mutex failed!\n");
- }
- SDL_UnlockMutex(queue->mutex);
- return status;
- }
- typedef struct
- {
- SDL_EventQueue *queue;
- int index;
- char padding1[SDL_CACHELINE_SIZE - (sizeof(SDL_EventQueue *) + sizeof(int)) % SDL_CACHELINE_SIZE];
- int waits;
- bool lock_free;
- char padding2[SDL_CACHELINE_SIZE - sizeof(int) - sizeof(bool)];
- SDL_Thread *thread;
- } WriterData;
- typedef struct
- {
- SDL_EventQueue *queue;
- int counters[NUM_WRITERS];
- int waits;
- bool lock_free;
- char padding[SDL_CACHELINE_SIZE - (sizeof(SDL_EventQueue *) + sizeof(int) * NUM_WRITERS + sizeof(int) + sizeof(bool)) % SDL_CACHELINE_SIZE];
- SDL_Thread *thread;
- } ReaderData;
- static int SDLCALL FIFO_Writer(void *_data)
- {
- WriterData *data = (WriterData *)_data;
- SDL_EventQueue *queue = data->queue;
- int i;
- SDL_Event event;
- event.type = SDL_EVENT_USER;
- event.user.windowID = 0;
- event.user.code = 0;
- event.user.data1 = data;
- event.user.data2 = NULL;
- if (data->lock_free) {
- for (i = 0; i < EVENTS_PER_WRITER; ++i) {
- event.user.code = i;
- while (!EnqueueEvent_LockFree(queue, &event)) {
- ++data->waits;
- SDL_Delay(0);
- }
- }
- } else {
- for (i = 0; i < EVENTS_PER_WRITER; ++i) {
- event.user.code = i;
- while (!EnqueueEvent_Mutex(queue, &event)) {
- ++data->waits;
- SDL_Delay(0);
- }
- }
- }
- return 0;
- }
- static int SDLCALL FIFO_Reader(void *_data)
- {
- ReaderData *data = (ReaderData *)_data;
- SDL_EventQueue *queue = data->queue;
- SDL_Event event;
- if (data->lock_free) {
- for (;;) {
- if (DequeueEvent_LockFree(queue, &event)) {
- WriterData *writer = (WriterData *)event.user.data1;
- ++data->counters[writer->index];
- } else if (SDL_GetAtomicInt(&queue->active)) {
- ++data->waits;
- SDL_Delay(0);
- } else {
- /* We drained the queue, we're done! */
- break;
- }
- }
- } else {
- for (;;) {
- if (DequeueEvent_Mutex(queue, &event)) {
- WriterData *writer = (WriterData *)event.user.data1;
- ++data->counters[writer->index];
- } else if (SDL_GetAtomicInt(&queue->active)) {
- ++data->waits;
- SDL_Delay(0);
- } else {
- /* We drained the queue, we're done! */
- break;
- }
- }
- }
- return 0;
- }
- #ifdef TEST_SPINLOCK_FIFO
- /* This thread periodically locks the queue for no particular reason */
- static int SDLCALL FIFO_Watcher(void *_data)
- {
- SDL_EventQueue *queue = (SDL_EventQueue *)_data;
- while (SDL_GetAtomicInt(&queue->active)) {
- SDL_LockSpinlock(&queue->lock);
- SDL_AtomicIncRef(&queue->watcher);
- while (SDL_GetAtomicInt(&queue->rwcount) > 0) {
- SDL_Delay(0);
- }
- /* Do queue manipulation here... */
- (void)SDL_AtomicDecRef(&queue->watcher);
- SDL_UnlockSpinlock(&queue->lock);
- /* Wait a bit... */
- SDL_Delay(1);
- }
- return 0;
- }
- #endif /* TEST_SPINLOCK_FIFO */
- static void RunFIFOTest(bool lock_free)
- {
- SDL_EventQueue queue;
- SDL_Thread *fifo_thread = NULL;
- WriterData writerData[NUM_WRITERS];
- ReaderData readerData[NUM_READERS];
- Uint64 start, end;
- int i, j;
- int grand_total;
- char textBuffer[1024];
- size_t len;
- SDL_Log("\nFIFO test---------------------------------------\n\n");
- SDL_Log("Mode: %s\n", lock_free ? "LockFree" : "Mutex");
- SDL_memset(&queue, 0xff, sizeof(queue));
- InitEventQueue(&queue);
- if (!lock_free) {
- queue.mutex = SDL_CreateMutex();
- }
- start = SDL_GetTicksNS();
- #ifdef TEST_SPINLOCK_FIFO
- /* Start a monitoring thread */
- if (lock_free) {
- fifo_thread = SDL_CreateThread(FIFO_Watcher, "FIFOWatcher", &queue);
- }
- #endif
- /* Start the readers first */
- SDL_Log("Starting %d readers\n", NUM_READERS);
- SDL_zeroa(readerData);
- for (i = 0; i < NUM_READERS; ++i) {
- char name[64];
- (void)SDL_snprintf(name, sizeof(name), "FIFOReader%d", i);
- readerData[i].queue = &queue;
- readerData[i].lock_free = lock_free;
- readerData[i].thread = SDL_CreateThread(FIFO_Reader, name, &readerData[i]);
- }
- /* Start up the writers */
- SDL_Log("Starting %d writers\n", NUM_WRITERS);
- SDL_zeroa(writerData);
- for (i = 0; i < NUM_WRITERS; ++i) {
- char name[64];
- (void)SDL_snprintf(name, sizeof(name), "FIFOWriter%d", i);
- writerData[i].queue = &queue;
- writerData[i].index = i;
- writerData[i].lock_free = lock_free;
- writerData[i].thread = SDL_CreateThread(FIFO_Writer, name, &writerData[i]);
- }
- /* Wait for the writers */
- for (i = 0; i < NUM_WRITERS; ++i) {
- SDL_WaitThread(writerData[i].thread, NULL);
- }
- /* Shut down the queue so readers exit */
- SDL_SetAtomicInt(&queue.active, 0);
- /* Wait for the readers */
- for (i = 0; i < NUM_READERS; ++i) {
- SDL_WaitThread(readerData[i].thread, NULL);
- }
- end = SDL_GetTicksNS();
- /* Wait for the FIFO thread */
- if (fifo_thread) {
- SDL_WaitThread(fifo_thread, NULL);
- }
- if (!lock_free) {
- SDL_DestroyMutex(queue.mutex);
- }
- SDL_Log("Finished in %f sec\n", (end - start) / 1000000000.0);
- SDL_Log("\n");
- for (i = 0; i < NUM_WRITERS; ++i) {
- SDL_Log("Writer %d wrote %d events, had %d waits\n", i, EVENTS_PER_WRITER, writerData[i].waits);
- }
- SDL_Log("Writers wrote %d total events\n", NUM_WRITERS * EVENTS_PER_WRITER);
- /* Print a breakdown of which readers read messages from which writer */
- SDL_Log("\n");
- grand_total = 0;
- for (i = 0; i < NUM_READERS; ++i) {
- int total = 0;
- for (j = 0; j < NUM_WRITERS; ++j) {
- total += readerData[i].counters[j];
- }
- grand_total += total;
- SDL_Log("Reader %d read %d events, had %d waits\n", i, total, readerData[i].waits);
- (void)SDL_snprintf(textBuffer, sizeof(textBuffer), " { ");
- for (j = 0; j < NUM_WRITERS; ++j) {
- if (j > 0) {
- len = SDL_strlen(textBuffer);
- (void)SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, ", ");
- }
- len = SDL_strlen(textBuffer);
- (void)SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, "%d", readerData[i].counters[j]);
- }
- len = SDL_strlen(textBuffer);
- (void)SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, " }\n");
- SDL_Log("%s", textBuffer);
- }
- SDL_Log("Readers read %d total events\n", grand_total);
- }
- /* End FIFO test */
- /**************************************************************************/
- int main(int argc, char *argv[])
- {
- SDLTest_CommonState *state;
- int i;
- bool enable_threads = true;
- /* Initialize test framework */
- state = SDLTest_CommonCreateState(argv, 0);
- if (!state) {
- return 1;
- }
- /* Parse commandline */
- for (i = 1; i < argc;) {
- int consumed;
- consumed = SDLTest_CommonArg(state, i);
- if (consumed == 0) {
- consumed = -1;
- if (SDL_strcasecmp(argv[i], "--no-threads") == 0) {
- enable_threads = false;
- consumed = 1;
- }
- }
- if (consumed < 0) {
- static const char *options[] = {
- "[--no-threads]",
- NULL
- };
- SDLTest_CommonLogUsage(state, argv[0], options);
- return 1;
- }
- i += consumed;
- }
- RunBasicTest();
- if (SDL_GetEnvironmentVariable(SDL_GetEnvironment(), "SDL_TESTS_QUICK") != NULL) {
- SDL_Log("Not running slower tests");
- return 0;
- }
- if (enable_threads) {
- RunEpicTest();
- }
- /* This test is really slow, so don't run it by default */
- #if 0
- RunFIFOTest(false);
- #endif
- RunFIFOTest(true);
- SDL_Quit();
- SDLTest_CommonDestroyState(state);
- return 0;
- }
|