From 6aaedb813fa11ba0679c3051bc2eb28646b9506c Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Sat, 30 Aug 2025 16:53:58 -0700 Subject: Update to SDL3 --- src/contrib/SDL-3.2.20/test/testatomic.c | 764 +++++++++++++++++++++++++++++++ 1 file changed, 764 insertions(+) create mode 100644 src/contrib/SDL-3.2.20/test/testatomic.c (limited to 'src/contrib/SDL-3.2.20/test/testatomic.c') diff --git a/src/contrib/SDL-3.2.20/test/testatomic.c b/src/contrib/SDL-3.2.20/test/testatomic.c new file mode 100644 index 0000000..3769534 --- /dev/null +++ b/src/contrib/SDL-3.2.20/test/testatomic.c @@ -0,0 +1,764 @@ +/* + Copyright (C) 1997-2025 Sam Lantinga + + 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 +#include +#include + +/* + 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("%s", ""); + SDL_Log("spin lock---------------------------------------"); + SDL_Log("%s", ""); + + SDL_LockSpinlock(&lock); + SDL_Log("AtomicLock lock=%d", lock); + SDL_UnlockSpinlock(&lock); + SDL_Log("AtomicUnlock lock=%d", lock); + + SDL_Log("%s", ""); + SDL_Log("atomic -----------------------------------------"); + SDL_Log("%s", ""); + + SDL_SetAtomicInt(&v, 0); + tfret = SDL_SetAtomicInt(&v, 10) == 0; + SDL_Log("AtomicSet(10) tfret=%s val=%d", tf(tfret), SDL_GetAtomicInt(&v)); + tfret = SDL_AddAtomicInt(&v, 10) == 10; + SDL_Log("AtomicAdd(10) tfret=%s val=%d", tf(tfret), SDL_GetAtomicInt(&v)); + + SDL_SetAtomicInt(&v, 0); + SDL_AtomicIncRef(&v); + tfret = (SDL_GetAtomicInt(&v) == 1); + SDL_Log("AtomicIncRef() tfret=%s val=%d", tf(tfret), SDL_GetAtomicInt(&v)); + SDL_AtomicIncRef(&v); + tfret = (SDL_GetAtomicInt(&v) == 2); + SDL_Log("AtomicIncRef() tfret=%s val=%d", tf(tfret), SDL_GetAtomicInt(&v)); + tfret = (SDL_AtomicDecRef(&v) == false); + SDL_Log("AtomicDecRef() tfret=%s val=%d", tf(tfret), SDL_GetAtomicInt(&v)); + tfret = (SDL_AtomicDecRef(&v) == true); + SDL_Log("AtomicDecRef() tfret=%s val=%d", tf(tfret), SDL_GetAtomicInt(&v)); + + SDL_SetAtomicInt(&v, 10); + tfret = (SDL_CompareAndSwapAtomicInt(&v, 0, 20) == false); + SDL_Log("AtomicCAS() tfret=%s val=%d", tf(tfret), SDL_GetAtomicInt(&v)); + value = SDL_GetAtomicInt(&v); + tfret = (SDL_CompareAndSwapAtomicInt(&v, value, 20) == true); + SDL_Log("AtomicCAS() tfret=%s val=%d", 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", 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", (end - start) / 1000000000.0); +} + +static void RunEpicTest(void) +{ + int b; + atomicValue v; + + SDL_Log("%s", ""); + SDL_Log("epic test---------------------------------------"); + SDL_Log("%s", ""); + + SDL_Log("Size asserted to be >= 32-bit"); + SDL_assert(sizeof(atomicValue) >= 4); + + SDL_Log("Check static initializer"); + v = SDL_GetAtomicInt(&good); + SDL_assert(v == 42); + + SDL_assert(bad == 42); + + SDL_Log("Test negative values"); + SDL_SetAtomicInt(&good, -5); + v = SDL_GetAtomicInt(&good); + SDL_assert(v == -5); + + SDL_Log("Verify maximum value"); + SDL_SetAtomicInt(&good, CountTo); + v = SDL_GetAtomicInt(&good); + SDL_assert(v == CountTo); + + SDL_Log("Test compare and exchange"); + + 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"); + + 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)"); + + 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"); + 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", CountTo, Expect); + runAdder(); + + v = SDL_GetAtomicInt(&good); + SDL_Log("Atomic %d Non-Atomic %d", 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!"); + } + + 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!"); + } + + 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("%s", ""); + SDL_Log("FIFO test---------------------------------------"); + SDL_Log("%s", ""); + SDL_Log("Mode: %s", 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", 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", 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", (end - start) / 1000000000.0); + + SDL_Log("%s", ""); + for (i = 0; i < NUM_WRITERS; ++i) { + SDL_Log("Writer %d wrote %d events, had %d waits", i, EVENTS_PER_WRITER, writerData[i].waits); + } + SDL_Log("Writers wrote %d total events", NUM_WRITERS * EVENTS_PER_WRITER); + + /* Print a breakdown of which readers read messages from which writer */ + SDL_Log("%s", ""); + 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", 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", 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; +} -- cgit v1.2.3