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