SDL  2.0
testatomic.c File Reference
#include <stdio.h>
#include "SDL.h"
+ Include dependency graph for testatomic.c:

Go to the source code of this file.

Data Structures

struct  SDL_EventQueueEntry
 
struct  SDL_EventQueue
 
struct  WriterData
 
struct  ReaderData
 

Macros

#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)
 
#define TEST_SPINLOCK_FIFO
 
#define NUM_READERS   4
 
#define NUM_WRITERS   4
 
#define EVENTS_PER_WRITER   1000000
 
#define MAX_ENTRIES   256
 
#define WRAP_MASK   (MAX_ENTRIES-1)
 

Enumerations

enum  
 

Functions

static char * tf (SDL_bool tf)
 
static void RunBasicTest ()
 
 SDL_COMPILE_TIME_ASSERT (size, CountTo_GreaterThanZero)
 
static int adder (void *junk)
 
static void runAdder (void)
 
static void RunEpicTest ()
 
static void InitEventQueue (SDL_EventQueue *queue)
 
static SDL_bool EnqueueEvent_LockFree (SDL_EventQueue *queue, const SDL_Event *event)
 
static SDL_bool DequeueEvent_LockFree (SDL_EventQueue *queue, SDL_Event *event)
 
static SDL_bool EnqueueEvent_Mutex (SDL_EventQueue *queue, const SDL_Event *event)
 
static SDL_bool DequeueEvent_Mutex (SDL_EventQueue *queue, SDL_Event *event)
 
static int FIFO_Writer (void *_data)
 
static int FIFO_Reader (void *_data)
 
static int FIFO_Watcher (void *_data)
 
static void RunFIFOTest (SDL_bool lock_free)
 
int main (int argc, char *argv[])
 

Variables

static SDL_atomic_t good = { 42 }
 
static atomicValue bad = 42
 
static SDL_atomic_t threadsRunning
 
static SDL_sem * threadDone
 
static SDL_sem * writersDone
 
static SDL_sem * readersDone
 
static SDL_atomic_t writersRunning
 
static SDL_atomic_t readersRunning
 

Macro Definition Documentation

◆ atomicValue

#define atomicValue   int

Definition at line 101 of file testatomic.c.

Referenced by RunEpicTest().

◆ CountInc

#define CountInc   100

Definition at line 98 of file testatomic.c.

Referenced by adder().

◆ CountTo

#define CountTo   ((atomicValue)((unsigned int)(1<<(VALBITS-1))-1))

Definition at line 102 of file testatomic.c.

Referenced by RunEpicTest().

◆ EVENTS_PER_WRITER

#define EVENTS_PER_WRITER   1000000

Definition at line 256 of file testatomic.c.

Referenced by FIFO_Writer(), and RunFIFOTest().

◆ Expect

#define Expect   (CountTo-NInter*CountInc*NThreads)

Definition at line 104 of file testatomic.c.

Referenced by RunEpicTest().

◆ MAX_ENTRIES

#define MAX_ENTRIES   256

Definition at line 259 of file testatomic.c.

Referenced by DequeueEvent_LockFree(), DequeueEvent_Mutex(), and InitEventQueue().

◆ NInter

#define NInter   (CountTo/CountInc/NThreads)

Definition at line 103 of file testatomic.c.

Referenced by adder().

◆ NThreads

#define NThreads   2

Definition at line 97 of file testatomic.c.

Referenced by runAdder().

◆ NUM_READERS

#define NUM_READERS   4

Definition at line 254 of file testatomic.c.

Referenced by RunFIFOTest().

◆ NUM_WRITERS

#define NUM_WRITERS   4

Definition at line 255 of file testatomic.c.

Referenced by RunFIFOTest().

◆ TEST_SPINLOCK_FIFO

#define TEST_SPINLOCK_FIFO

Definition at line 252 of file testatomic.c.

◆ VALBITS

#define VALBITS   (sizeof(atomicValue)*8)

Definition at line 99 of file testatomic.c.

◆ WRAP_MASK

#define WRAP_MASK   (MAX_ENTRIES-1)

Enumeration Type Documentation

◆ anonymous enum

anonymous enum

Definition at line 106 of file testatomic.c.

106  {
107  CountTo_GreaterThanZero = CountTo > 0,
108 };
#define CountTo
Definition: testatomic.c:102

Function Documentation

◆ adder()

static int adder ( void junk)
static

Definition at line 120 of file testatomic.c.

References bad, CountInc, NInter, SDL_AtomicAdd, SDL_Log, SDL_SemPost, and threadDone.

Referenced by runAdder().

121 {
122  unsigned long N=NInter;
123  SDL_Log("Thread subtracting %d %lu times\n",CountInc,N);
124  while (N--) {
126  bad-=CountInc;
127  }
130  return 0;
131 }
#define NInter
Definition: testatomic.c:103
#define SDL_SemPost
#define SDL_Log
static SDL_atomic_t good
Definition: testatomic.c:111
static SDL_sem * threadDone
Definition: testatomic.c:117
#define SDL_AtomicAdd
static SDL_atomic_t threadsRunning
Definition: testatomic.c:115
#define CountInc
Definition: testatomic.c:98
static atomicValue bad
Definition: testatomic.c:113

◆ DequeueEvent_LockFree()

static SDL_bool DequeueEvent_LockFree ( SDL_EventQueue queue,
SDL_Event event 
)
static

Definition at line 361 of file testatomic.c.

References SDL_EventQueue::dequeue_pos, SDL_EventQueue::entries, SDL_EventQueueEntry::event, SDL_EventQueue::lock, MAX_ENTRIES, SDL_EventQueue::rwcount, SDL_assert, SDL_AtomicCAS, SDL_AtomicDecRef, SDL_AtomicGet, SDL_AtomicIncRef, SDL_AtomicLock, SDL_AtomicSet, SDL_AtomicUnlock, SDL_FALSE, SDL_TRUE, SDL_EventQueueEntry::sequence, SDL_EventQueue::watcher, and WRAP_MASK.

Referenced by FIFO_Reader().

362 {
363  SDL_EventQueueEntry *entry;
364  unsigned queue_pos;
365  unsigned entry_seq;
366  int delta;
367  SDL_bool status;
368 
369 #ifdef TEST_SPINLOCK_FIFO
370  /* This is a gate so an external thread can lock the queue */
371  SDL_AtomicLock(&queue->lock);
372  SDL_assert(SDL_AtomicGet(&queue->watcher) == 0);
373  SDL_AtomicIncRef(&queue->rwcount);
374  SDL_AtomicUnlock(&queue->lock);
375 #endif
376 
377  queue_pos = (unsigned)SDL_AtomicGet(&queue->dequeue_pos);
378  for ( ; ; ) {
379  entry = &queue->entries[queue_pos & WRAP_MASK];
380  entry_seq = (unsigned)SDL_AtomicGet(&entry->sequence);
381 
382  delta = (int)(entry_seq - (queue_pos + 1));
383  if (delta == 0) {
384  /* The entry and the queue position match, try to increment the queue position */
385  if (SDL_AtomicCAS(&queue->dequeue_pos, (int)queue_pos, (int)(queue_pos+1))) {
386  /* We own the object, fill it! */
387  *event = entry->event;
388  SDL_AtomicSet(&entry->sequence, (int)(queue_pos+MAX_ENTRIES));
389  status = SDL_TRUE;
390  break;
391  }
392  } else if (delta < 0) {
393  /* We ran into an old queue entry, which means we've hit empty */
394  status = SDL_FALSE;
395  break;
396  } else {
397  /* We ran into a new queue entry, get the new queue position */
398  queue_pos = (unsigned)SDL_AtomicGet(&queue->dequeue_pos);
399  }
400  }
401 
402 #ifdef TEST_SPINLOCK_FIFO
403  SDL_AtomicDecRef(&queue->rwcount);
404 #endif
405  return status;
406 }
SDL_atomic_t dequeue_pos
Definition: testatomic.c:278
#define SDL_AtomicLock
#define SDL_AtomicCAS
SDL_SpinLock lock
Definition: testatomic.c:283
#define SDL_AtomicUnlock
SDL_EventQueueEntry entries[MAX_ENTRIES]
Definition: testatomic.c:270
#define MAX_ENTRIES
Definition: testatomic.c:259
SDL_Event event
Definition: testatomic.c:265
SDL_atomic_t sequence
Definition: testatomic.c:264
#define SDL_AtomicIncRef(a)
Increment an atomic variable used as a reference count.
Definition: SDL_atomic.h:234
SDL_atomic_t watcher
Definition: testatomic.c:285
#define SDL_assert(condition)
Definition: SDL_assert.h:169
SDL_bool
Definition: SDL_stdinc.h:139
#define SDL_AtomicDecRef(a)
Decrement an atomic variable used as a reference count.
Definition: SDL_atomic.h:244
#define SDL_AtomicSet
#define SDL_AtomicGet
SDL_atomic_t rwcount
Definition: testatomic.c:284
#define WRAP_MASK
Definition: testatomic.c:260
Definition: testatomic.c:262

◆ DequeueEvent_Mutex()

static SDL_bool DequeueEvent_Mutex ( SDL_EventQueue queue,
SDL_Event event 
)
static

Definition at line 441 of file testatomic.c.

References SDL_EventQueue::dequeue_pos, SDL_EventQueue::entries, SDL_EventQueueEntry::event, MAX_ENTRIES, SDL_EventQueue::mutex, SDL_FALSE, SDL_LockMutex, SDL_Log, SDL_TRUE, SDL_UnlockMutex, SDL_EventQueueEntry::sequence, SDL_atomic_t::value, and WRAP_MASK.

Referenced by FIFO_Reader().

442 {
443  SDL_EventQueueEntry *entry;
444  unsigned queue_pos;
445  unsigned entry_seq;
446  int delta;
447  SDL_bool status = SDL_FALSE;
448 
449  SDL_LockMutex(queue->mutex);
450 
451  queue_pos = (unsigned)queue->dequeue_pos.value;
452  entry = &queue->entries[queue_pos & WRAP_MASK];
453  entry_seq = (unsigned)entry->sequence.value;
454 
455  delta = (int)(entry_seq - (queue_pos + 1));
456  if (delta == 0) {
457  ++queue->dequeue_pos.value;
458 
459  /* We own the object, fill it! */
460  *event = entry->event;
461  entry->sequence.value = (int)(queue_pos + MAX_ENTRIES);
462  status = SDL_TRUE;
463  } else if (delta < 0) {
464  /* We ran into an old queue entry, which means we've hit empty */
465  } else {
466  SDL_Log("ERROR: mutex failed!\n");
467  }
468 
469  SDL_UnlockMutex(queue->mutex);
470 
471  return status;
472 }
#define SDL_LockMutex
SDL_atomic_t dequeue_pos
Definition: testatomic.c:278
#define SDL_Log
SDL_EventQueueEntry entries[MAX_ENTRIES]
Definition: testatomic.c:270
SDL_mutex * mutex
Definition: testatomic.c:293
#define MAX_ENTRIES
Definition: testatomic.c:259
SDL_Event event
Definition: testatomic.c:265
SDL_atomic_t sequence
Definition: testatomic.c:264
SDL_bool
Definition: SDL_stdinc.h:139
#define SDL_UnlockMutex
#define WRAP_MASK
Definition: testatomic.c:260
Definition: testatomic.c:262

◆ EnqueueEvent_LockFree()

static SDL_bool EnqueueEvent_LockFree ( SDL_EventQueue queue,
const SDL_Event event 
)
static

Definition at line 314 of file testatomic.c.

References SDL_EventQueue::enqueue_pos, SDL_EventQueue::entries, SDL_EventQueueEntry::event, SDL_EventQueue::lock, SDL_EventQueue::rwcount, SDL_assert, SDL_AtomicCAS, SDL_AtomicDecRef, SDL_AtomicGet, SDL_AtomicIncRef, SDL_AtomicLock, SDL_AtomicSet, SDL_AtomicUnlock, SDL_FALSE, SDL_TRUE, SDL_EventQueueEntry::sequence, SDL_EventQueue::watcher, and WRAP_MASK.

Referenced by FIFO_Writer().

315 {
316  SDL_EventQueueEntry *entry;
317  unsigned queue_pos;
318  unsigned entry_seq;
319  int delta;
320  SDL_bool status;
321 
322 #ifdef TEST_SPINLOCK_FIFO
323  /* This is a gate so an external thread can lock the queue */
324  SDL_AtomicLock(&queue->lock);
325  SDL_assert(SDL_AtomicGet(&queue->watcher) == 0);
326  SDL_AtomicIncRef(&queue->rwcount);
327  SDL_AtomicUnlock(&queue->lock);
328 #endif
329 
330  queue_pos = (unsigned)SDL_AtomicGet(&queue->enqueue_pos);
331  for ( ; ; ) {
332  entry = &queue->entries[queue_pos & WRAP_MASK];
333  entry_seq = (unsigned)SDL_AtomicGet(&entry->sequence);
334 
335  delta = (int)(entry_seq - queue_pos);
336  if (delta == 0) {
337  /* The entry and the queue position match, try to increment the queue position */
338  if (SDL_AtomicCAS(&queue->enqueue_pos, (int)queue_pos, (int)(queue_pos+1))) {
339  /* We own the object, fill it! */
340  entry->event = *event;
341  SDL_AtomicSet(&entry->sequence, (int)(queue_pos + 1));
342  status = SDL_TRUE;
343  break;
344  }
345  } else if (delta < 0) {
346  /* We ran into an old queue entry, which means it still needs to be dequeued */
347  status = SDL_FALSE;
348  break;
349  } else {
350  /* We ran into a new queue entry, get the new queue position */
351  queue_pos = (unsigned)SDL_AtomicGet(&queue->enqueue_pos);
352  }
353  }
354 
355 #ifdef TEST_SPINLOCK_FIFO
356  SDL_AtomicDecRef(&queue->rwcount);
357 #endif
358  return status;
359 }
#define SDL_AtomicLock
#define SDL_AtomicCAS
SDL_SpinLock lock
Definition: testatomic.c:283
#define SDL_AtomicUnlock
SDL_EventQueueEntry entries[MAX_ENTRIES]
Definition: testatomic.c:270
struct _cl_event * event
SDL_Event event
Definition: testatomic.c:265
SDL_atomic_t sequence
Definition: testatomic.c:264
#define SDL_AtomicIncRef(a)
Increment an atomic variable used as a reference count.
Definition: SDL_atomic.h:234
SDL_atomic_t watcher
Definition: testatomic.c:285
#define SDL_assert(condition)
Definition: SDL_assert.h:169
SDL_bool
Definition: SDL_stdinc.h:139
#define SDL_AtomicDecRef(a)
Decrement an atomic variable used as a reference count.
Definition: SDL_atomic.h:244
#define SDL_AtomicSet
#define SDL_AtomicGet
SDL_atomic_t rwcount
Definition: testatomic.c:284
#define WRAP_MASK
Definition: testatomic.c:260
SDL_atomic_t enqueue_pos
Definition: testatomic.c:274
Definition: testatomic.c:262

◆ EnqueueEvent_Mutex()

static SDL_bool EnqueueEvent_Mutex ( SDL_EventQueue queue,
const SDL_Event event 
)
static

Definition at line 408 of file testatomic.c.

References SDL_EventQueue::enqueue_pos, SDL_EventQueue::entries, SDL_EventQueueEntry::event, SDL_EventQueue::mutex, SDL_FALSE, SDL_LockMutex, SDL_Log, SDL_TRUE, SDL_UnlockMutex, SDL_EventQueueEntry::sequence, SDL_atomic_t::value, and WRAP_MASK.

Referenced by FIFO_Writer().

409 {
410  SDL_EventQueueEntry *entry;
411  unsigned queue_pos;
412  unsigned entry_seq;
413  int delta;
414  SDL_bool status = SDL_FALSE;
415 
416  SDL_LockMutex(queue->mutex);
417 
418  queue_pos = (unsigned)queue->enqueue_pos.value;
419  entry = &queue->entries[queue_pos & WRAP_MASK];
420  entry_seq = (unsigned)entry->sequence.value;
421 
422  delta = (int)(entry_seq - queue_pos);
423  if (delta == 0) {
424  ++queue->enqueue_pos.value;
425 
426  /* We own the object, fill it! */
427  entry->event = *event;
428  entry->sequence.value = (int)(queue_pos + 1);
429  status = SDL_TRUE;
430  } else if (delta < 0) {
431  /* We ran into an old queue entry, which means it still needs to be dequeued */
432  } else {
433  SDL_Log("ERROR: mutex failed!\n");
434  }
435 
436  SDL_UnlockMutex(queue->mutex);
437 
438  return status;
439 }
#define SDL_LockMutex
#define SDL_Log
SDL_EventQueueEntry entries[MAX_ENTRIES]
Definition: testatomic.c:270
SDL_mutex * mutex
Definition: testatomic.c:293
struct _cl_event * event
SDL_Event event
Definition: testatomic.c:265
SDL_atomic_t sequence
Definition: testatomic.c:264
SDL_bool
Definition: SDL_stdinc.h:139
#define SDL_UnlockMutex
#define WRAP_MASK
Definition: testatomic.c:260
SDL_atomic_t enqueue_pos
Definition: testatomic.c:274
Definition: testatomic.c:262

◆ FIFO_Reader()

static int FIFO_Reader ( void _data)
static

Definition at line 533 of file testatomic.c.

References SDL_EventQueue::active, ReaderData::counters, SDL_UserEvent::data1, DequeueEvent_LockFree(), DequeueEvent_Mutex(), WriterData::index, ReaderData::lock_free, ReaderData::queue, readersDone, SDL_AtomicAdd, SDL_AtomicGet, SDL_Delay, SDL_SemPost, SDL_Event::user, and ReaderData::waits.

Referenced by RunFIFOTest().

534 {
535  ReaderData *data = (ReaderData *)_data;
536  SDL_EventQueue *queue = data->queue;
538 
539  if (data->lock_free) {
540  for ( ; ; ) {
541  if (DequeueEvent_LockFree(queue, &event)) {
542  WriterData *writer = (WriterData*)event.user.data1;
543  ++data->counters[writer->index];
544  } else if (SDL_AtomicGet(&queue->active)) {
545  ++data->waits;
546  SDL_Delay(0);
547  } else {
548  /* We drained the queue, we're done! */
549  break;
550  }
551  }
552  } else {
553  for ( ; ; ) {
554  if (DequeueEvent_Mutex(queue, &event)) {
555  WriterData *writer = (WriterData*)event.user.data1;
556  ++data->counters[writer->index];
557  } else if (SDL_AtomicGet(&queue->active)) {
558  ++data->waits;
559  SDL_Delay(0);
560  } else {
561  /* We drained the queue, we're done! */
562  break;
563  }
564  }
565  }
568  return 0;
569 }
void * data1
Definition: SDL_events.h:501
static SDL_bool DequeueEvent_Mutex(SDL_EventQueue *queue, SDL_Event *event)
Definition: testatomic.c:441
SDL_EventQueue * queue
Definition: testatomic.c:491
static SDL_sem * readersDone
Definition: testatomic.c:475
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
SDL_bool lock_free
Definition: testatomic.c:494
#define SDL_SemPost
static SDL_bool DequeueEvent_LockFree(SDL_EventQueue *queue, SDL_Event *event)
Definition: testatomic.c:361
static SDL_atomic_t readersRunning
Definition: testatomic.c:477
struct _cl_event * event
#define SDL_Delay
int counters[NUM_WRITERS]
Definition: testatomic.c:492
#define SDL_AtomicAdd
#define SDL_AtomicGet
General event structure.
Definition: SDL_events.h:525
SDL_UserEvent user
Definition: SDL_events.h:546
SDL_atomic_t active
Definition: testatomic.c:290

◆ FIFO_Watcher()

static int FIFO_Watcher ( void _data)
static

Definition at line 573 of file testatomic.c.

References SDL_EventQueue::active, SDL_EventQueue::lock, SDL_EventQueue::rwcount, SDL_AtomicDecRef, SDL_AtomicGet, SDL_AtomicIncRef, SDL_AtomicLock, SDL_AtomicUnlock, SDL_Delay, and SDL_EventQueue::watcher.

Referenced by RunFIFOTest().

574 {
575  SDL_EventQueue *queue = (SDL_EventQueue *)_data;
576 
577  while (SDL_AtomicGet(&queue->active)) {
578  SDL_AtomicLock(&queue->lock);
579  SDL_AtomicIncRef(&queue->watcher);
580  while (SDL_AtomicGet(&queue->rwcount) > 0) {
581  SDL_Delay(0);
582  }
583  /* Do queue manipulation here... */
584  SDL_AtomicDecRef(&queue->watcher);
585  SDL_AtomicUnlock(&queue->lock);
586 
587  /* Wait a bit... */
588  SDL_Delay(1);
589  }
590  return 0;
591 }
#define SDL_AtomicLock
SDL_SpinLock lock
Definition: testatomic.c:283
#define SDL_AtomicUnlock
#define SDL_AtomicIncRef(a)
Increment an atomic variable used as a reference count.
Definition: SDL_atomic.h:234
#define SDL_Delay
SDL_atomic_t watcher
Definition: testatomic.c:285
#define SDL_AtomicDecRef(a)
Decrement an atomic variable used as a reference count.
Definition: SDL_atomic.h:244
#define SDL_AtomicGet
SDL_atomic_t rwcount
Definition: testatomic.c:284
SDL_atomic_t active
Definition: testatomic.c:290

◆ FIFO_Writer()

static int FIFO_Writer ( void _data)
static

Definition at line 498 of file testatomic.c.

References EnqueueEvent_LockFree(), EnqueueEvent_Mutex(), EVENTS_PER_WRITER, i, WriterData::lock_free, NULL, WriterData::queue, SDL_AtomicAdd, SDL_Delay, SDL_SemPost, SDL_USEREVENT, WriterData::waits, and writersDone.

Referenced by RunFIFOTest().

499 {
500  WriterData *data = (WriterData *)_data;
501  SDL_EventQueue *queue = data->queue;
502  int i;
504 
505  event.type = SDL_USEREVENT;
506  event.user.windowID = 0;
507  event.user.code = 0;
508  event.user.data1 = data;
509  event.user.data2 = NULL;
510 
511  if (data->lock_free) {
512  for (i = 0; i < EVENTS_PER_WRITER; ++i) {
513  event.user.code = i;
514  while (!EnqueueEvent_LockFree(queue, &event)) {
515  ++data->waits;
516  SDL_Delay(0);
517  }
518  }
519  } else {
520  for (i = 0; i < EVENTS_PER_WRITER; ++i) {
521  event.user.code = i;
522  while (!EnqueueEvent_Mutex(queue, &event)) {
523  ++data->waits;
524  SDL_Delay(0);
525  }
526  }
527  }
530  return 0;
531 }
SDL_bool lock_free
Definition: testatomic.c:485
static SDL_bool EnqueueEvent_LockFree(SDL_EventQueue *queue, const SDL_Event *event)
Definition: testatomic.c:314
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
static SDL_atomic_t writersRunning
Definition: testatomic.c:476
#define SDL_SemPost
struct _cl_event * event
SDL_EventQueue * queue
Definition: testatomic.c:481
static SDL_bool EnqueueEvent_Mutex(SDL_EventQueue *queue, const SDL_Event *event)
Definition: testatomic.c:408
#define SDL_Delay
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NULL
Definition: begin_code.h:164
#define SDL_AtomicAdd
#define EVENTS_PER_WRITER
Definition: testatomic.c:256
static SDL_sem * writersDone
Definition: testatomic.c:474
General event structure.
Definition: SDL_events.h:525

◆ InitEventQueue()

static void InitEventQueue ( SDL_EventQueue queue)
static

Definition at line 297 of file testatomic.c.

References SDL_EventQueue::active, SDL_EventQueue::dequeue_pos, SDL_EventQueue::enqueue_pos, SDL_EventQueue::entries, i, SDL_EventQueue::lock, MAX_ENTRIES, SDL_EventQueue::rwcount, SDL_AtomicSet, SDL_EventQueueEntry::sequence, and SDL_EventQueue::watcher.

Referenced by RunFIFOTest().

298 {
299  int i;
300 
301  for (i = 0; i < MAX_ENTRIES; ++i) {
302  SDL_AtomicSet(&queue->entries[i].sequence, i);
303  }
304  SDL_AtomicSet(&queue->enqueue_pos, 0);
305  SDL_AtomicSet(&queue->dequeue_pos, 0);
306 #ifdef TEST_SPINLOCK_FIFO
307  queue->lock = 0;
308  SDL_AtomicSet(&queue->rwcount, 0);
309  SDL_AtomicSet(&queue->watcher, 0);
310 #endif
311  SDL_AtomicSet(&queue->active, 1);
312 }
SDL_atomic_t dequeue_pos
Definition: testatomic.c:278
SDL_SpinLock lock
Definition: testatomic.c:283
SDL_EventQueueEntry entries[MAX_ENTRIES]
Definition: testatomic.c:270
#define MAX_ENTRIES
Definition: testatomic.c:259
SDL_atomic_t sequence
Definition: testatomic.c:264
SDL_atomic_t watcher
Definition: testatomic.c:285
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define SDL_AtomicSet
SDL_atomic_t rwcount
Definition: testatomic.c:284
SDL_atomic_t active
Definition: testatomic.c:290
SDL_atomic_t enqueue_pos
Definition: testatomic.c:274

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 712 of file testatomic.c.

References RunBasicTest(), RunEpicTest(), RunFIFOTest(), SDL_FALSE, SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, SDL_LogSetPriority, and SDL_TRUE.

713 {
714  /* Enable standard application logging */
716 
717  RunBasicTest();
718  RunEpicTest();
719 /* This test is really slow, so don't run it by default */
720 #if 0
722 #endif
724  return 0;
725 }
static void RunBasicTest()
Definition: testatomic.c:37
#define SDL_LogSetPriority
static void RunEpicTest()
Definition: testatomic.c:159
static void RunFIFOTest(SDL_bool lock_free)
Definition: testatomic.c:594

◆ runAdder()

static void runAdder ( void  )
static

Definition at line 134 of file testatomic.c.

References adder(), NThreads, NULL, SDL_AtomicGet, SDL_AtomicSet, SDL_CreateSemaphore, SDL_CreateThread, SDL_DestroySemaphore, SDL_GetTicks(), SDL_Log, SDL_SemWait, T, and threadDone.

Referenced by RunEpicTest().

135 {
136  Uint32 start, end;
137  int T=NThreads;
138 
139  start = SDL_GetTicks();
140 
142 
144 
145  while (T--)
146  SDL_CreateThread(adder, "Adder", NULL);
147 
148  while (SDL_AtomicGet(&threadsRunning) > 0)
150 
152 
153  end = SDL_GetTicks();
154 
155  SDL_Log("Finished in %f sec\n", (end - start) / 1000.f);
156 }
#define SDL_CreateSemaphore
GLuint GLuint end
Definition: SDL_opengl.h:1571
GLfloat f
GLuint start
Definition: SDL_opengl.h:1571
uint32_t Uint32
Definition: SDL_stdinc.h:181
static int adder(void *junk)
Definition: testatomic.c:120
#define NThreads
Definition: testatomic.c:97
static const double T[]
Definition: k_tan.c:53
#define SDL_Log
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
#define SDL_CreateThread
static SDL_sem * threadDone
Definition: testatomic.c:117
#define NULL
Definition: begin_code.h:164
#define SDL_SemWait
#define SDL_DestroySemaphore
#define SDL_AtomicSet
static SDL_atomic_t threadsRunning
Definition: testatomic.c:115
#define SDL_AtomicGet

◆ RunBasicTest()

static void RunBasicTest ( )
static

Definition at line 37 of file testatomic.c.

References lock, SDL_AtomicAdd, SDL_AtomicCAS, SDL_AtomicDecRef, SDL_AtomicGet, SDL_AtomicIncRef, SDL_AtomicLock, SDL_AtomicSet, SDL_AtomicUnlock, SDL_FALSE, SDL_Log, SDL_TRUE, and tf().

Referenced by main().

38 {
39  int value;
40  SDL_SpinLock lock = 0;
41 
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 }
const GLdouble * v
Definition: SDL_opengl.h:2064
#define SDL_AtomicLock
A type representing an atomic integer value. It is a struct so people don&#39;t accidentally use numeric ...
Definition: SDL_atomic.h:198
#define SDL_AtomicCAS
static char * tf(SDL_bool tf)
Definition: testatomic.c:23
#define SDL_AtomicUnlock
#define SDL_Log
GLsizei const GLfloat * value
#define SDL_AtomicIncRef(a)
Increment an atomic variable used as a reference count.
Definition: SDL_atomic.h:234
#define SDL_AtomicAdd
SDL_bool
Definition: SDL_stdinc.h:139
SDL_mutex * lock
Definition: SDL_events.c:78
#define SDL_AtomicDecRef(a)
Decrement an atomic variable used as a reference count.
Definition: SDL_atomic.h:244
#define SDL_AtomicSet
#define SDL_AtomicGet
int SDL_SpinLock
Definition: SDL_atomic.h:89

◆ RunEpicTest()

static void RunEpicTest ( )
static

Definition at line 159 of file testatomic.c.

References atomicValue, bad, CountTo, Expect, runAdder(), SDL_assert, SDL_AtomicAdd, SDL_AtomicCAS, SDL_AtomicGet, SDL_AtomicSet, and SDL_Log.

Referenced by main().

160 {
161  int b;
162  atomicValue v;
163 
164  SDL_Log("\nepic test---------------------------------------\n\n");
165 
166  SDL_Log("Size asserted to be >= 32-bit\n");
167  SDL_assert(sizeof(atomicValue)>=4);
168 
169  SDL_Log("Check static initializer\n");
170  v=SDL_AtomicGet(&good);
171  SDL_assert(v==42);
172 
173  SDL_assert(bad==42);
174 
175  SDL_Log("Test negative values\n");
176  SDL_AtomicSet(&good, -5);
177  v=SDL_AtomicGet(&good);
178  SDL_assert(v==-5);
179 
180  SDL_Log("Verify maximum value\n");
182  v=SDL_AtomicGet(&good);
183  SDL_assert(v==CountTo);
184 
185  SDL_Log("Test compare and exchange\n");
186 
187  b=SDL_AtomicCAS(&good, 500, 43);
188  SDL_assert(!b); /* no swap since CountTo!=500 */
189  v=SDL_AtomicGet(&good);
190  SDL_assert(v==CountTo); /* ensure no swap */
191 
192  b=SDL_AtomicCAS(&good, CountTo, 44);
193  SDL_assert(!!b); /* will swap */
194  v=SDL_AtomicGet(&good);
195  SDL_assert(v==44);
196 
197  SDL_Log("Test Add\n");
198 
199  v=SDL_AtomicAdd(&good, 1);
200  SDL_assert(v==44);
201  v=SDL_AtomicGet(&good);
202  SDL_assert(v==45);
203 
204  v=SDL_AtomicAdd(&good, 10);
205  SDL_assert(v==45);
206  v=SDL_AtomicGet(&good);
207  SDL_assert(v==55);
208 
209  SDL_Log("Test Add (Negative values)\n");
210 
211  v=SDL_AtomicAdd(&good, -20);
212  SDL_assert(v==55);
213  v=SDL_AtomicGet(&good);
214  SDL_assert(v==35);
215 
216  v=SDL_AtomicAdd(&good, -50); /* crossing zero down */
217  SDL_assert(v==35);
218  v=SDL_AtomicGet(&good);
219  SDL_assert(v==-15);
220 
221  v=SDL_AtomicAdd(&good, 30); /* crossing zero up */
222  SDL_assert(v==-15);
223  v=SDL_AtomicGet(&good);
224  SDL_assert(v==15);
225 
226  SDL_Log("Reset before count down test\n");
228  v=SDL_AtomicGet(&good);
229  SDL_assert(v==CountTo);
230 
231  bad=CountTo;
233 
234  SDL_Log("Counting down from %d, Expect %d remaining\n",CountTo,Expect);
235  runAdder();
236 
237  v=SDL_AtomicGet(&good);
238  SDL_Log("Atomic %d Non-Atomic %d\n",v,bad);
239  SDL_assert(v==Expect);
241 }
const GLdouble * v
Definition: SDL_opengl.h:2064
#define SDL_AtomicCAS
#define atomicValue
Definition: testatomic.c:101
#define CountTo
Definition: testatomic.c:102
#define SDL_Log
static SDL_atomic_t good
Definition: testatomic.c:111
#define SDL_assert(condition)
Definition: SDL_assert.h:169
#define SDL_AtomicAdd
static void runAdder(void)
Definition: testatomic.c:134
#define SDL_AtomicSet
#define SDL_AtomicGet
static atomicValue bad
Definition: testatomic.c:113
#define Expect
Definition: testatomic.c:104
GLboolean GLboolean GLboolean b

◆ RunFIFOTest()

static void RunFIFOTest ( SDL_bool  lock_free)
static

Definition at line 594 of file testatomic.c.

References SDL_EventQueue::active, ReaderData::counters, EVENTS_PER_WRITER, FIFO_Reader(), FIFO_Watcher(), FIFO_Writer(), i, WriterData::index, InitEventQueue(), j, WriterData::lock_free, ReaderData::lock_free, SDL_EventQueue::mutex, NUM_READERS, NUM_WRITERS, WriterData::queue, ReaderData::queue, readersDone, SDL_AtomicGet, SDL_AtomicSet, SDL_CreateMutex, SDL_CreateSemaphore, SDL_CreateThread, SDL_DestroyMutex, SDL_DestroySemaphore, SDL_GetTicks(), SDL_Log, SDL_memset, SDL_SemWait, SDL_snprintf, SDL_strlen, SDL_zero, and writersDone.

Referenced by main().

595 {
596  SDL_EventQueue queue;
597  WriterData writerData[NUM_WRITERS];
598  ReaderData readerData[NUM_READERS];
599  Uint32 start, end;
600  int i, j;
601  int grand_total;
602  char textBuffer[1024];
603  size_t len;
604 
605  SDL_Log("\nFIFO test---------------------------------------\n\n");
606  SDL_Log("Mode: %s\n", lock_free ? "LockFree" : "Mutex");
607 
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_GetTicks();
619 
620 #ifdef TEST_SPINLOCK_FIFO
621  /* Start a monitoring thread */
622  if (lock_free) {
623  SDL_CreateThread(FIFO_Watcher, "FIFOWatcher", &queue);
624  }
625 #endif
626 
627  /* Start the readers first */
628  SDL_Log("Starting %d readers\n", NUM_READERS);
629  SDL_zero(readerData);
631  for (i = 0; i < NUM_READERS; ++i) {
632  char name[64];
633  SDL_snprintf(name, sizeof (name), "FIFOReader%d", i);
634  readerData[i].queue = &queue;
635  readerData[i].lock_free = lock_free;
636  SDL_CreateThread(FIFO_Reader, name, &readerData[i]);
637  }
638 
639  /* Start up the writers */
640  SDL_Log("Starting %d writers\n", NUM_WRITERS);
641  SDL_zero(writerData);
643  for (i = 0; i < NUM_WRITERS; ++i) {
644  char name[64];
645  SDL_snprintf(name, sizeof (name), "FIFOWriter%d", i);
646  writerData[i].queue = &queue;
647  writerData[i].index = i;
648  writerData[i].lock_free = lock_free;
649  SDL_CreateThread(FIFO_Writer, name, &writerData[i]);
650  }
651 
652  /* Wait for the writers */
653  while (SDL_AtomicGet(&writersRunning) > 0) {
655  }
656 
657  /* Shut down the queue so readers exit */
658  SDL_AtomicSet(&queue.active, 0);
659 
660  /* Wait for the readers */
661  while (SDL_AtomicGet(&readersRunning) > 0) {
663  }
664 
665  end = SDL_GetTicks();
666 
669 
670  if (!lock_free) {
671  SDL_DestroyMutex(queue.mutex);
672  }
673 
674  SDL_Log("Finished in %f sec\n", (end - start) / 1000.f);
675 
676  SDL_Log("\n");
677  for (i = 0; i < NUM_WRITERS; ++i) {
678  SDL_Log("Writer %d wrote %d events, had %d waits\n", i, EVENTS_PER_WRITER, writerData[i].waits);
679  }
680  SDL_Log("Writers wrote %d total events\n", NUM_WRITERS*EVENTS_PER_WRITER);
681 
682  /* Print a breakdown of which readers read messages from which writer */
683  SDL_Log("\n");
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\n", i, total, readerData[i].waits);
692  SDL_snprintf(textBuffer, sizeof(textBuffer), " { ");
693  for (j = 0; j < NUM_WRITERS; ++j) {
694  if (j > 0) {
695  len = SDL_strlen(textBuffer);
696  SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, ", ");
697  }
698  len = SDL_strlen(textBuffer);
699  SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, "%d", readerData[i].counters[j]);
700  }
701  len = SDL_strlen(textBuffer);
702  SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, " }\n");
703  SDL_Log("%s", textBuffer);
704  }
705  SDL_Log("Readers read %d total events\n", grand_total);
706 }
SDL_EventQueue * queue
Definition: testatomic.c:491
static SDL_sem * readersDone
Definition: testatomic.c:475
SDL_bool lock_free
Definition: testatomic.c:485
static void InitEventQueue(SDL_EventQueue *queue)
Definition: testatomic.c:297
#define SDL_CreateSemaphore
GLuint GLuint end
Definition: SDL_opengl.h:1571
#define SDL_CreateMutex
GLfloat f
static int FIFO_Writer(void *_data)
Definition: testatomic.c:498
GLuint start
Definition: SDL_opengl.h:1571
static SDL_atomic_t writersRunning
Definition: testatomic.c:476
uint32_t Uint32
Definition: SDL_stdinc.h:181
GLenum GLsizei len
GLint GLint GLsizei GLuint * counters
GLuint const GLchar * name
SDL_bool lock_free
Definition: testatomic.c:494
#define SDL_Log
static SDL_atomic_t readersRunning
Definition: testatomic.c:477
SDL_mutex * mutex
Definition: testatomic.c:293
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int int in j)
Definition: SDL_x11sym.h:50
SDL_EventQueue * queue
Definition: testatomic.c:481
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
#define SDL_CreateThread
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
Definition: SDL_x11sym.h:50
#define NUM_WRITERS
Definition: testatomic.c:255
int counters[NUM_WRITERS]
Definition: testatomic.c:492
static int FIFO_Watcher(void *_data)
Definition: testatomic.c:573
#define SDL_DestroyMutex
#define EVENTS_PER_WRITER
Definition: testatomic.c:256
#define SDL_strlen
static SDL_sem * writersDone
Definition: testatomic.c:474
#define SDL_SemWait
#define SDL_DestroySemaphore
#define SDL_AtomicSet
#define SDL_AtomicGet
#define SDL_snprintf
static int FIFO_Reader(void *_data)
Definition: testatomic.c:533
SDL_atomic_t active
Definition: testatomic.c:290
#define SDL_memset
#define NUM_READERS
Definition: testatomic.c:254

◆ SDL_COMPILE_TIME_ASSERT()

SDL_COMPILE_TIME_ASSERT ( size  ,
CountTo_GreaterThanZero   
)

◆ tf()

static char* tf ( SDL_bool  tf)
static

Definition at line 23 of file testatomic.c.

Referenced by RunBasicTest().

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 }
GLfloat f
static char * tf(SDL_bool tf)
Definition: testatomic.c:23
GLdouble GLdouble t
Definition: SDL_opengl.h:2071

Variable Documentation

◆ bad

atomicValue bad = 42
static

Definition at line 113 of file testatomic.c.

Referenced by adder(), and RunEpicTest().

◆ good

SDL_atomic_t good = { 42 }
static

Definition at line 111 of file testatomic.c.

◆ readersDone

SDL_sem* readersDone
static

Definition at line 475 of file testatomic.c.

Referenced by FIFO_Reader(), and RunFIFOTest().

◆ readersRunning

SDL_atomic_t readersRunning
static

Definition at line 477 of file testatomic.c.

◆ threadDone

SDL_sem* threadDone
static

Definition at line 117 of file testatomic.c.

Referenced by adder(), and runAdder().

◆ threadsRunning

SDL_atomic_t threadsRunning
static

Definition at line 115 of file testatomic.c.

◆ writersDone

SDL_sem* writersDone
static

Definition at line 474 of file testatomic.c.

Referenced by FIFO_Writer(), and RunFIFOTest().

◆ writersRunning

SDL_atomic_t writersRunning
static

Definition at line 476 of file testatomic.c.