Atlas - testatomic.c
Home / ext / SDL / test Lines: 2 | Size: 22012 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 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} 765[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.