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)
 

Functions

static char * tf (SDL_bool tf)
 
static void RunBasicTest ()
 
 SDL_COMPILE_TIME_ASSERT (size, CountTo >0)
 
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 253 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 256 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 251 of file testatomic.c.

Referenced by RunFIFOTest().

◆ NUM_WRITERS

#define NUM_WRITERS   4

Definition at line 252 of file testatomic.c.

Referenced by RunFIFOTest().

◆ TEST_SPINLOCK_FIFO

#define TEST_SPINLOCK_FIFO

Definition at line 249 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)

Function Documentation

◆ adder()

static int adder ( void junk)
static

Definition at line 117 of file testatomic.c.

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

Referenced by runAdder().

118 {
119  unsigned long N=NInter;
120  SDL_Log("Thread subtracting %d %lu times\n",CountInc,N);
121  while (N--) {
123  bad-=CountInc;
124  }
127  return 0;
128 }
#define NInter
Definition: testatomic.c:103
#define SDL_SemPost
#define SDL_Log
static SDL_atomic_t good
Definition: testatomic.c:108
static SDL_sem * threadDone
Definition: testatomic.c:114
#define SDL_AtomicAdd
static SDL_atomic_t threadsRunning
Definition: testatomic.c:112
#define CountInc
Definition: testatomic.c:98
static atomicValue bad
Definition: testatomic.c:110

◆ DequeueEvent_LockFree()

static SDL_bool DequeueEvent_LockFree ( SDL_EventQueue queue,
SDL_Event event 
)
static

Definition at line 358 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().

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

◆ DequeueEvent_Mutex()

static SDL_bool DequeueEvent_Mutex ( SDL_EventQueue queue,
SDL_Event event 
)
static

Definition at line 438 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().

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

◆ EnqueueEvent_LockFree()

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

Definition at line 311 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().

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

◆ EnqueueEvent_Mutex()

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

Definition at line 405 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().

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

◆ FIFO_Reader()

static int FIFO_Reader ( void _data)
static

Definition at line 530 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().

531 {
532  ReaderData *data = (ReaderData *)_data;
533  SDL_EventQueue *queue = data->queue;
535 
536  if (data->lock_free) {
537  for ( ; ; ) {
538  if (DequeueEvent_LockFree(queue, &event)) {
539  WriterData *writer = (WriterData*)event.user.data1;
540  ++data->counters[writer->index];
541  } else if (SDL_AtomicGet(&queue->active)) {
542  ++data->waits;
543  SDL_Delay(0);
544  } else {
545  /* We drained the queue, we're done! */
546  break;
547  }
548  }
549  } else {
550  for ( ; ; ) {
551  if (DequeueEvent_Mutex(queue, &event)) {
552  WriterData *writer = (WriterData*)event.user.data1;
553  ++data->counters[writer->index];
554  } else if (SDL_AtomicGet(&queue->active)) {
555  ++data->waits;
556  SDL_Delay(0);
557  } else {
558  /* We drained the queue, we're done! */
559  break;
560  }
561  }
562  }
565  return 0;
566 }
void * data1
Definition: SDL_events.h:501
static SDL_bool DequeueEvent_Mutex(SDL_EventQueue *queue, SDL_Event *event)
Definition: testatomic.c:438
SDL_EventQueue * queue
Definition: testatomic.c:488
static SDL_sem * readersDone
Definition: testatomic.c:472
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
SDL_bool lock_free
Definition: testatomic.c:491
#define SDL_SemPost
static SDL_bool DequeueEvent_LockFree(SDL_EventQueue *queue, SDL_Event *event)
Definition: testatomic.c:358
static SDL_atomic_t readersRunning
Definition: testatomic.c:474
struct _cl_event * event
#define SDL_Delay
int counters[NUM_WRITERS]
Definition: testatomic.c:489
#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:287

◆ FIFO_Watcher()

static int FIFO_Watcher ( void _data)
static

Definition at line 570 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().

571 {
572  SDL_EventQueue *queue = (SDL_EventQueue *)_data;
573 
574  while (SDL_AtomicGet(&queue->active)) {
575  SDL_AtomicLock(&queue->lock);
576  SDL_AtomicIncRef(&queue->watcher);
577  while (SDL_AtomicGet(&queue->rwcount) > 0) {
578  SDL_Delay(0);
579  }
580  /* Do queue manipulation here... */
581  SDL_AtomicDecRef(&queue->watcher);
582  SDL_AtomicUnlock(&queue->lock);
583 
584  /* Wait a bit... */
585  SDL_Delay(1);
586  }
587  return 0;
588 }
#define SDL_AtomicLock
SDL_SpinLock lock
Definition: testatomic.c:280
#define SDL_AtomicUnlock
#define SDL_AtomicIncRef(a)
Increment an atomic variable used as a reference count.
Definition: SDL_atomic.h:225
#define SDL_Delay
SDL_atomic_t watcher
Definition: testatomic.c:282
#define SDL_AtomicDecRef(a)
Decrement an atomic variable used as a reference count.
Definition: SDL_atomic.h:235
#define SDL_AtomicGet
SDL_atomic_t rwcount
Definition: testatomic.c:281
SDL_atomic_t active
Definition: testatomic.c:287

◆ FIFO_Writer()

static int FIFO_Writer ( void _data)
static

Definition at line 495 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().

496 {
497  WriterData *data = (WriterData *)_data;
498  SDL_EventQueue *queue = data->queue;
499  int i;
501 
502  event.type = SDL_USEREVENT;
503  event.user.windowID = 0;
504  event.user.code = 0;
505  event.user.data1 = data;
506  event.user.data2 = NULL;
507 
508  if (data->lock_free) {
509  for (i = 0; i < EVENTS_PER_WRITER; ++i) {
510  event.user.code = i;
511  while (!EnqueueEvent_LockFree(queue, &event)) {
512  ++data->waits;
513  SDL_Delay(0);
514  }
515  }
516  } else {
517  for (i = 0; i < EVENTS_PER_WRITER; ++i) {
518  event.user.code = i;
519  while (!EnqueueEvent_Mutex(queue, &event)) {
520  ++data->waits;
521  SDL_Delay(0);
522  }
523  }
524  }
527  return 0;
528 }
SDL_bool lock_free
Definition: testatomic.c:482
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
static SDL_bool EnqueueEvent_LockFree(SDL_EventQueue *queue, const SDL_Event *event)
Definition: testatomic.c:311
static SDL_atomic_t writersRunning
Definition: testatomic.c:473
#define SDL_SemPost
struct _cl_event * event
SDL_EventQueue * queue
Definition: testatomic.c:478
static SDL_bool EnqueueEvent_Mutex(SDL_EventQueue *queue, const SDL_Event *event)
Definition: testatomic.c:405
#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:143
#define SDL_AtomicAdd
#define EVENTS_PER_WRITER
Definition: testatomic.c:253
static SDL_sem * writersDone
Definition: testatomic.c:471
General event structure.
Definition: SDL_events.h:525

◆ InitEventQueue()

static void InitEventQueue ( SDL_EventQueue queue)
static

Definition at line 294 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().

295 {
296  int i;
297 
298  for (i = 0; i < MAX_ENTRIES; ++i) {
299  SDL_AtomicSet(&queue->entries[i].sequence, i);
300  }
301  SDL_AtomicSet(&queue->enqueue_pos, 0);
302  SDL_AtomicSet(&queue->dequeue_pos, 0);
303 #ifdef TEST_SPINLOCK_FIFO
304  queue->lock = 0;
305  SDL_AtomicSet(&queue->rwcount, 0);
306  SDL_AtomicSet(&queue->watcher, 0);
307 #endif
308  SDL_AtomicSet(&queue->active, 1);
309 }
SDL_atomic_t dequeue_pos
Definition: testatomic.c:275
SDL_SpinLock lock
Definition: testatomic.c:280
SDL_EventQueueEntry entries[MAX_ENTRIES]
Definition: testatomic.c:267
#define MAX_ENTRIES
Definition: testatomic.c:256
SDL_atomic_t sequence
Definition: testatomic.c:261
SDL_atomic_t watcher
Definition: testatomic.c:282
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:281
SDL_atomic_t active
Definition: testatomic.c:287
SDL_atomic_t enqueue_pos
Definition: testatomic.c:271

◆ main()

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

Definition at line 709 of file testatomic.c.

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

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

◆ runAdder()

static void runAdder ( void  )
static

Definition at line 131 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().

132 {
133  Uint32 start, end;
134  int T=NThreads;
135 
136  start = SDL_GetTicks();
137 
139 
141 
142  while (T--)
143  SDL_CreateThread(adder, "Adder", NULL);
144 
145  while (SDL_AtomicGet(&threadsRunning) > 0)
147 
149 
150  end = SDL_GetTicks();
151 
152  SDL_Log("Finished in %f sec\n", (end - start) / 1000.f);
153 }
#define SDL_CreateSemaphore
GLuint GLuint end
Definition: SDL_opengl.h:1564
GLfloat f
GLuint start
Definition: SDL_opengl.h:1564
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:161
static int adder(void *junk)
Definition: testatomic.c:117
#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:114
#define NULL
Definition: begin_code.h:143
#define SDL_SemWait
#define SDL_DestroySemaphore
#define SDL_AtomicSet
static SDL_atomic_t threadsRunning
Definition: testatomic.c:112
#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 }
#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:189
#define SDL_AtomicCAS
static char * tf(SDL_bool tf)
Definition: testatomic.c:23
#define SDL_AtomicUnlock
const GLdouble * v
Definition: SDL_opengl.h:2057
#define SDL_Log
GLsizei const GLfloat * value
#define SDL_AtomicIncRef(a)
Increment an atomic variable used as a reference count.
Definition: SDL_atomic.h:225
#define SDL_AtomicAdd
SDL_bool
Definition: SDL_stdinc.h:130
SDL_mutex * lock
Definition: SDL_events.c:75
#define SDL_AtomicDecRef(a)
Decrement an atomic variable used as a reference count.
Definition: SDL_atomic.h:235
#define SDL_AtomicSet
#define SDL_AtomicGet
int SDL_SpinLock
Definition: SDL_atomic.h:89

◆ RunEpicTest()

static void RunEpicTest ( )
static

Definition at line 156 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().

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

◆ RunFIFOTest()

static void RunFIFOTest ( SDL_bool  lock_free)
static

Definition at line 591 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().

592 {
593  SDL_EventQueue queue;
594  WriterData writerData[NUM_WRITERS];
595  ReaderData readerData[NUM_READERS];
596  Uint32 start, end;
597  int i, j;
598  int grand_total;
599  char textBuffer[1024];
600  int len;
601 
602  SDL_Log("\nFIFO test---------------------------------------\n\n");
603  SDL_Log("Mode: %s\n", lock_free ? "LockFree" : "Mutex");
604 
607 
608  SDL_memset(&queue, 0xff, sizeof(queue));
609 
610  InitEventQueue(&queue);
611  if (!lock_free) {
612  queue.mutex = SDL_CreateMutex();
613  }
614 
615  start = SDL_GetTicks();
616 
617 #ifdef TEST_SPINLOCK_FIFO
618  /* Start a monitoring thread */
619  if (lock_free) {
620  SDL_CreateThread(FIFO_Watcher, "FIFOWatcher", &queue);
621  }
622 #endif
623 
624  /* Start the readers first */
625  SDL_Log("Starting %d readers\n", NUM_READERS);
626  SDL_zero(readerData);
628  for (i = 0; i < NUM_READERS; ++i) {
629  char name[64];
630  SDL_snprintf(name, sizeof (name), "FIFOReader%d", i);
631  readerData[i].queue = &queue;
632  readerData[i].lock_free = lock_free;
633  SDL_CreateThread(FIFO_Reader, name, &readerData[i]);
634  }
635 
636  /* Start up the writers */
637  SDL_Log("Starting %d writers\n", NUM_WRITERS);
638  SDL_zero(writerData);
640  for (i = 0; i < NUM_WRITERS; ++i) {
641  char name[64];
642  SDL_snprintf(name, sizeof (name), "FIFOWriter%d", i);
643  writerData[i].queue = &queue;
644  writerData[i].index = i;
645  writerData[i].lock_free = lock_free;
646  SDL_CreateThread(FIFO_Writer, name, &writerData[i]);
647  }
648 
649  /* Wait for the writers */
650  while (SDL_AtomicGet(&writersRunning) > 0) {
652  }
653 
654  /* Shut down the queue so readers exit */
655  SDL_AtomicSet(&queue.active, 0);
656 
657  /* Wait for the readers */
658  while (SDL_AtomicGet(&readersRunning) > 0) {
660  }
661 
662  end = SDL_GetTicks();
663 
666 
667  if (!lock_free) {
668  SDL_DestroyMutex(queue.mutex);
669  }
670 
671  SDL_Log("Finished in %f sec\n", (end - start) / 1000.f);
672 
673  SDL_Log("\n");
674  for (i = 0; i < NUM_WRITERS; ++i) {
675  SDL_Log("Writer %d wrote %d events, had %d waits\n", i, EVENTS_PER_WRITER, writerData[i].waits);
676  }
677  SDL_Log("Writers wrote %d total events\n", NUM_WRITERS*EVENTS_PER_WRITER);
678 
679  /* Print a breakdown of which readers read messages from which writer */
680  SDL_Log("\n");
681  grand_total = 0;
682  for (i = 0; i < NUM_READERS; ++i) {
683  int total = 0;
684  for (j = 0; j < NUM_WRITERS; ++j) {
685  total += readerData[i].counters[j];
686  }
687  grand_total += total;
688  SDL_Log("Reader %d read %d events, had %d waits\n", i, total, readerData[i].waits);
689  SDL_snprintf(textBuffer, sizeof(textBuffer), " { ");
690  for (j = 0; j < NUM_WRITERS; ++j) {
691  if (j > 0) {
692  len = SDL_strlen(textBuffer);
693  SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, ", ");
694  }
695  len = SDL_strlen(textBuffer);
696  SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, "%d", readerData[i].counters[j]);
697  }
698  len = SDL_strlen(textBuffer);
699  SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, " }\n");
700  SDL_Log("%s", textBuffer);
701  }
702  SDL_Log("Readers read %d total events\n", grand_total);
703 }
SDL_EventQueue * queue
Definition: testatomic.c:488
static SDL_sem * readersDone
Definition: testatomic.c:472
SDL_bool lock_free
Definition: testatomic.c:482
static void InitEventQueue(SDL_EventQueue *queue)
Definition: testatomic.c:294
#define SDL_CreateSemaphore
GLuint GLuint end
Definition: SDL_opengl.h:1564
#define SDL_CreateMutex
GLfloat f
static int FIFO_Writer(void *_data)
Definition: testatomic.c:495
GLuint start
Definition: SDL_opengl.h:1564
static SDL_atomic_t writersRunning
Definition: testatomic.c:473
GLuint const GLchar * name
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:161
GLenum GLsizei len
GLint GLint GLsizei GLuint * counters
SDL_bool lock_free
Definition: testatomic.c:491
#define SDL_Log
static SDL_atomic_t readersRunning
Definition: testatomic.c:474
SDL_mutex * mutex
Definition: testatomic.c:290
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:478
#define SDL_zero(x)
Definition: SDL_stdinc.h:361
#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:252
int counters[NUM_WRITERS]
Definition: testatomic.c:489
static int FIFO_Watcher(void *_data)
Definition: testatomic.c:570
#define SDL_DestroyMutex
#define EVENTS_PER_WRITER
Definition: testatomic.c:253
#define SDL_strlen
static SDL_sem * writersDone
Definition: testatomic.c:471
#define SDL_SemWait
#define SDL_DestroySemaphore
#define SDL_AtomicSet
#define SDL_AtomicGet
#define SDL_snprintf
static int FIFO_Reader(void *_data)
Definition: testatomic.c:530
SDL_atomic_t active
Definition: testatomic.c:287
#define SDL_memset
#define NUM_READERS
Definition: testatomic.c:251

◆ SDL_COMPILE_TIME_ASSERT()

SDL_COMPILE_TIME_ASSERT ( size  ,
CountTo  ,
 
)

◆ 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:2064

Variable Documentation

◆ bad

atomicValue bad = 42
static

Definition at line 110 of file testatomic.c.

Referenced by adder(), and RunEpicTest().

◆ good

SDL_atomic_t good = { 42 }
static

Definition at line 108 of file testatomic.c.

◆ readersDone

SDL_sem* readersDone
static

Definition at line 472 of file testatomic.c.

Referenced by FIFO_Reader(), and RunFIFOTest().

◆ readersRunning

SDL_atomic_t readersRunning
static

Definition at line 474 of file testatomic.c.

◆ threadDone

SDL_sem* threadDone
static

Definition at line 114 of file testatomic.c.

Referenced by adder(), and runAdder().

◆ threadsRunning

SDL_atomic_t threadsRunning
static

Definition at line 112 of file testatomic.c.

◆ writersDone

SDL_sem* writersDone
static

Definition at line 471 of file testatomic.c.

Referenced by FIFO_Writer(), and RunFIFOTest().

◆ writersRunning

SDL_atomic_t writersRunning
static

Definition at line 473 of file testatomic.c.