testatomic.c
Go to the documentation of this file.
/*
Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely.
*/
#include <stdio.h>
#include "SDL.h"
/*
Absolutely basic tests just to see if we get the expected value
after calling each function.
*/
static
char *
tf(SDL_bool tf)
{
static char *t = "TRUE";
static char *f = "FALSE";
if (tf)
{
return t;
}
return f;
}
static
void RunBasicTest()
{
int value;
SDL_SpinLock lock = 0;
SDL_atomic_t v;
SDL_bool tfret = SDL_FALSE;
SDL_Log("\nspin lock---------------------------------------\n\n");
SDL_AtomicLock(&lock);
SDL_Log("AtomicLock lock=%d\n", lock);
SDL_AtomicUnlock(&lock);
SDL_Log("AtomicUnlock lock=%d\n", lock);
SDL_Log("\natomic -----------------------------------------\n\n");
SDL_AtomicSet(&v, 0);
tfret = SDL_AtomicSet(&v, 10) == 0 ? SDL_TRUE : SDL_FALSE;
SDL_Log("AtomicSet(10) tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
tfret = SDL_AtomicAdd(&v, 10) == 10 ? SDL_TRUE : SDL_FALSE;
SDL_Log("AtomicAdd(10) tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
SDL_AtomicSet(&v, 0);
SDL_AtomicIncRef(&v);
tfret = (SDL_AtomicGet(&v) == 1) ? SDL_TRUE : SDL_FALSE;
SDL_Log("AtomicIncRef() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
SDL_AtomicIncRef(&v);
tfret = (SDL_AtomicGet(&v) == 2) ? SDL_TRUE : SDL_FALSE;
SDL_Log("AtomicIncRef() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
tfret = (SDL_AtomicDecRef(&v) == SDL_FALSE) ? SDL_TRUE : SDL_FALSE;
SDL_Log("AtomicDecRef() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
tfret = (SDL_AtomicDecRef(&v) == SDL_TRUE) ? SDL_TRUE : SDL_FALSE;
SDL_Log("AtomicDecRef() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
SDL_AtomicSet(&v, 10);
tfret = (SDL_AtomicCAS(&v, 0, 20) == SDL_FALSE) ? SDL_TRUE : SDL_FALSE;
SDL_Log("AtomicCAS() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
value = SDL_AtomicGet(&v);
tfret = (SDL_AtomicCAS(&v, value, 20) == SDL_TRUE) ? SDL_TRUE : SDL_FALSE;
SDL_Log("AtomicCAS() tfret=%s val=%d\n", tf(tfret), SDL_AtomicGet(&v));
}
/**************************************************************************/
/* Atomic operation test
* Adapted with permission from code by Michael Davidsaver at:
* http://bazaar.launchpad.net/~mdavidsaver/epics-base/atomic/revision/12105#src/libCom/test/epicsAtomicTest.c
* Original copyright 2010 Brookhaven Science Associates as operator of Brookhaven National Lab
* http://www.aps.anl.gov/epics/license/open.php
*/
/* Tests semantics of atomic operations. Also a stress test
* to see if they are really atomic.
*
* Several threads adding to the same variable.
* at the end the value is compared with the expected
* and with a non-atomic counter.
*/
/* Number of concurrent incrementers */
#define NThreads 2
#define CountInc 100
#define VALBITS (sizeof(atomicValue)*8)
#define atomicValue int
#define CountTo ((atomicValue)((unsigned int)(1<<(VALBITS-1))-1))
#define NInter (CountTo/CountInc/NThreads)
#define Expect (CountTo-NInter*CountInc*NThreads)
enum {
CountTo_GreaterThanZero = CountTo > 0,
};
SDL_COMPILE_TIME_ASSERT(size, CountTo_GreaterThanZero); /* check for rollover */
static SDL_atomic_t good = { 42 };
static atomicValue bad = 42;
static SDL_atomic_t threadsRunning;
static SDL_sem *threadDone;
static
int SDLCALL adder(void* junk)
{
unsigned long N=NInter;
SDL_Log("Thread subtracting %d %lu times\n",CountInc,N);
while (N--) {
SDL_AtomicAdd(&good, -CountInc);
bad-=CountInc;
}
SDL_AtomicAdd(&threadsRunning, -1);
SDL_SemPost(threadDone);
return 0;
}
static
void runAdder(void)
{
Uint32 start, end;
int T=NThreads;
start = SDL_GetTicks();
threadDone = SDL_CreateSemaphore(0);
SDL_AtomicSet(&threadsRunning, NThreads);
while (T--)
SDL_CreateThread(adder, "Adder", NULL);
while (SDL_AtomicGet(&threadsRunning) > 0)
SDL_SemWait(threadDone);
SDL_DestroySemaphore(threadDone);
end = SDL_GetTicks();
SDL_Log("Finished in %f sec\n", (end - start) / 1000.f);
}
static
void RunEpicTest()
{
int b;
atomicValue v;
SDL_Log("\nepic test---------------------------------------\n\n");
SDL_Log("Size asserted to be >= 32-bit\n");
SDL_assert(sizeof(atomicValue)>=4);
SDL_Log("Check static initializer\n");
v=SDL_AtomicGet(&good);
SDL_assert(v==42);
SDL_assert(bad==42);
SDL_Log("Test negative values\n");
SDL_AtomicSet(&good, -5);
v=SDL_AtomicGet(&good);
SDL_assert(v==-5);
SDL_Log("Verify maximum value\n");
SDL_AtomicSet(&good, CountTo);
v=SDL_AtomicGet(&good);
SDL_assert(v==CountTo);
SDL_Log("Test compare and exchange\n");
b=SDL_AtomicCAS(&good, 500, 43);
SDL_assert(!b); /* no swap since CountTo!=500 */
v=SDL_AtomicGet(&good);
SDL_assert(v==CountTo); /* ensure no swap */
b=SDL_AtomicCAS(&good, CountTo, 44);
SDL_assert(!!b); /* will swap */
v=SDL_AtomicGet(&good);
SDL_assert(v==44);
SDL_Log("Test Add\n");
v=SDL_AtomicAdd(&good, 1);
SDL_assert(v==44);
v=SDL_AtomicGet(&good);
SDL_assert(v==45);
v=SDL_AtomicAdd(&good, 10);
SDL_assert(v==45);
v=SDL_AtomicGet(&good);
SDL_assert(v==55);
SDL_Log("Test Add (Negative values)\n");
v=SDL_AtomicAdd(&good, -20);
SDL_assert(v==55);
v=SDL_AtomicGet(&good);
SDL_assert(v==35);
v=SDL_AtomicAdd(&good, -50); /* crossing zero down */
SDL_assert(v==35);
v=SDL_AtomicGet(&good);
SDL_assert(v==-15);
v=SDL_AtomicAdd(&good, 30); /* crossing zero up */
SDL_assert(v==-15);
v=SDL_AtomicGet(&good);
SDL_assert(v==15);
SDL_Log("Reset before count down test\n");
SDL_AtomicSet(&good, CountTo);
v=SDL_AtomicGet(&good);
SDL_assert(v==CountTo);
bad=CountTo;
SDL_assert(bad==CountTo);
SDL_Log("Counting down from %d, Expect %d remaining\n",CountTo,Expect);
runAdder();
v=SDL_AtomicGet(&good);
SDL_Log("Atomic %d Non-Atomic %d\n",v,bad);
SDL_assert(v==Expect);
SDL_assert(bad!=Expect);
}
/* End atomic operation test */
/**************************************************************************/
/**************************************************************************/
/* Lock-free FIFO test */
/* This is useful to test the impact of another thread locking the queue
entirely for heavy-weight manipulation.
*/
#define TEST_SPINLOCK_FIFO
#define NUM_READERS 4
#define NUM_WRITERS 4
#define EVENTS_PER_WRITER 1000000
/* The number of entries must be a power of 2 */
#define MAX_ENTRIES 256
#define WRAP_MASK (MAX_ENTRIES-1)
typedef struct
{
SDL_atomic_t sequence;
SDL_Event event;
} SDL_EventQueueEntry;
typedef struct
{
SDL_EventQueueEntry entries[MAX_ENTRIES];
char cache_pad1[SDL_CACHELINE_SIZE-((sizeof(SDL_EventQueueEntry)*MAX_ENTRIES)%SDL_CACHELINE_SIZE)];
SDL_atomic_t enqueue_pos;
char cache_pad2[SDL_CACHELINE_SIZE-sizeof(SDL_atomic_t)];
SDL_atomic_t dequeue_pos;
char cache_pad3[SDL_CACHELINE_SIZE-sizeof(SDL_atomic_t)];
#ifdef TEST_SPINLOCK_FIFO
SDL_SpinLock lock;
SDL_atomic_t rwcount;
SDL_atomic_t watcher;
char cache_pad4[SDL_CACHELINE_SIZE-sizeof(SDL_SpinLock)-2*sizeof(SDL_atomic_t)];
#endif
SDL_atomic_t active;
/* Only needed for the mutex test */
SDL_mutex *mutex;
} SDL_EventQueue;
static void InitEventQueue(SDL_EventQueue *queue)
{
int i;
for (i = 0; i < MAX_ENTRIES; ++i) {
SDL_AtomicSet(&queue->entries[i].sequence, i);
}
SDL_AtomicSet(&queue->enqueue_pos, 0);
SDL_AtomicSet(&queue->dequeue_pos, 0);
#ifdef TEST_SPINLOCK_FIFO
queue->lock = 0;
SDL_AtomicSet(&queue->rwcount, 0);
SDL_AtomicSet(&queue->watcher, 0);
#endif
SDL_AtomicSet(&queue->active, 1);
}
static SDL_bool EnqueueEvent_LockFree(SDL_EventQueue *queue, const SDL_Event *event)
{
SDL_EventQueueEntry *entry;
unsigned queue_pos;
unsigned entry_seq;
int delta;
SDL_bool status;
#ifdef TEST_SPINLOCK_FIFO
/* This is a gate so an external thread can lock the queue */
SDL_AtomicLock(&queue->lock);
SDL_assert(SDL_AtomicGet(&queue->watcher) == 0);
SDL_AtomicIncRef(&queue->rwcount);
SDL_AtomicUnlock(&queue->lock);
#endif
queue_pos = (unsigned)SDL_AtomicGet(&queue->enqueue_pos);
for ( ; ; ) {
entry = &queue->entries[queue_pos & WRAP_MASK];
entry_seq = (unsigned)SDL_AtomicGet(&entry->sequence);
delta = (int)(entry_seq - queue_pos);
if (delta == 0) {
/* The entry and the queue position match, try to increment the queue position */
if (SDL_AtomicCAS(&queue->enqueue_pos, (int)queue_pos, (int)(queue_pos+1))) {
/* We own the object, fill it! */
entry->event = *event;
SDL_AtomicSet(&entry->sequence, (int)(queue_pos + 1));
status = SDL_TRUE;
break;
}
} else if (delta < 0) {
/* We ran into an old queue entry, which means it still needs to be dequeued */
status = SDL_FALSE;
break;
} else {
/* We ran into a new queue entry, get the new queue position */
queue_pos = (unsigned)SDL_AtomicGet(&queue->enqueue_pos);
}
}
#ifdef TEST_SPINLOCK_FIFO
SDL_AtomicDecRef(&queue->rwcount);
#endif
return status;
}
static SDL_bool DequeueEvent_LockFree(SDL_EventQueue *queue, SDL_Event *event)
{
SDL_EventQueueEntry *entry;
unsigned queue_pos;
unsigned entry_seq;
int delta;
SDL_bool status;
#ifdef TEST_SPINLOCK_FIFO
/* This is a gate so an external thread can lock the queue */
SDL_AtomicLock(&queue->lock);
SDL_assert(SDL_AtomicGet(&queue->watcher) == 0);
SDL_AtomicIncRef(&queue->rwcount);
SDL_AtomicUnlock(&queue->lock);
#endif
queue_pos = (unsigned)SDL_AtomicGet(&queue->dequeue_pos);
for ( ; ; ) {
entry = &queue->entries[queue_pos & WRAP_MASK];
entry_seq = (unsigned)SDL_AtomicGet(&entry->sequence);
delta = (int)(entry_seq - (queue_pos + 1));
if (delta == 0) {
/* The entry and the queue position match, try to increment the queue position */
if (SDL_AtomicCAS(&queue->dequeue_pos, (int)queue_pos, (int)(queue_pos+1))) {
/* We own the object, fill it! */
*event = entry->event;
SDL_AtomicSet(&entry->sequence, (int)(queue_pos+MAX_ENTRIES));
status = SDL_TRUE;
break;
}
} else if (delta < 0) {
/* We ran into an old queue entry, which means we've hit empty */
status = SDL_FALSE;
break;
} else {
/* We ran into a new queue entry, get the new queue position */
queue_pos = (unsigned)SDL_AtomicGet(&queue->dequeue_pos);
}
}
#ifdef TEST_SPINLOCK_FIFO
SDL_AtomicDecRef(&queue->rwcount);
#endif
return status;
}
static SDL_bool EnqueueEvent_Mutex(SDL_EventQueue *queue, const SDL_Event *event)
{
SDL_EventQueueEntry *entry;
unsigned queue_pos;
unsigned entry_seq;
int delta;
SDL_bool status = SDL_FALSE;
SDL_LockMutex(queue->mutex);
queue_pos = (unsigned)queue->enqueue_pos.value;
entry = &queue->entries[queue_pos & WRAP_MASK];
entry_seq = (unsigned)entry->sequence.value;
delta = (int)(entry_seq - queue_pos);
if (delta == 0) {
++queue->enqueue_pos.value;
/* We own the object, fill it! */
entry->event = *event;
entry->sequence.value = (int)(queue_pos + 1);
status = SDL_TRUE;
} else if (delta < 0) {
/* We ran into an old queue entry, which means it still needs to be dequeued */
} else {
SDL_Log("ERROR: mutex failed!\n");
}
SDL_UnlockMutex(queue->mutex);
return status;
}
static SDL_bool DequeueEvent_Mutex(SDL_EventQueue *queue, SDL_Event *event)
{
SDL_EventQueueEntry *entry;
unsigned queue_pos;
unsigned entry_seq;
int delta;
SDL_bool status = SDL_FALSE;
SDL_LockMutex(queue->mutex);
queue_pos = (unsigned)queue->dequeue_pos.value;
entry = &queue->entries[queue_pos & WRAP_MASK];
entry_seq = (unsigned)entry->sequence.value;
delta = (int)(entry_seq - (queue_pos + 1));
if (delta == 0) {
++queue->dequeue_pos.value;
/* We own the object, fill it! */
*event = entry->event;
entry->sequence.value = (int)(queue_pos + MAX_ENTRIES);
status = SDL_TRUE;
} else if (delta < 0) {
/* We ran into an old queue entry, which means we've hit empty */
} else {
SDL_Log("ERROR: mutex failed!\n");
}
SDL_UnlockMutex(queue->mutex);
return status;
}
static SDL_sem *writersDone;
static SDL_sem *readersDone;
static SDL_atomic_t writersRunning;
static SDL_atomic_t readersRunning;
typedef struct
{
SDL_EventQueue *queue;
int index;
char padding1[SDL_CACHELINE_SIZE-(sizeof(SDL_EventQueue*)+sizeof(int))%SDL_CACHELINE_SIZE];
int waits;
SDL_bool lock_free;
char padding2[SDL_CACHELINE_SIZE-sizeof(int)-sizeof(SDL_bool)];
} WriterData;
typedef struct
{
SDL_EventQueue *queue;
int counters[NUM_WRITERS];
int waits;
SDL_bool lock_free;
char padding[SDL_CACHELINE_SIZE-(sizeof(SDL_EventQueue*)+sizeof(int)*NUM_WRITERS+sizeof(int)+sizeof(SDL_bool))%SDL_CACHELINE_SIZE];
} ReaderData;
static int SDLCALL FIFO_Writer(void* _data)
{
WriterData *data = (WriterData *)_data;
SDL_EventQueue *queue = data->queue;
int i;
SDL_Event event;
event.type = SDL_USEREVENT;
event.user.windowID = 0;
event.user.code = 0;
event.user.data1 = data;
event.user.data2 = NULL;
if (data->lock_free) {
for (i = 0; i < EVENTS_PER_WRITER; ++i) {
event.user.code = i;
while (!EnqueueEvent_LockFree(queue, &event)) {
++data->waits;
SDL_Delay(0);
}
}
} else {
for (i = 0; i < EVENTS_PER_WRITER; ++i) {
event.user.code = i;
while (!EnqueueEvent_Mutex(queue, &event)) {
++data->waits;
SDL_Delay(0);
}
}
}
SDL_AtomicAdd(&writersRunning, -1);
SDL_SemPost(writersDone);
return 0;
}
static int SDLCALL FIFO_Reader(void* _data)
{
ReaderData *data = (ReaderData *)_data;
SDL_EventQueue *queue = data->queue;
SDL_Event event;
if (data->lock_free) {
for ( ; ; ) {
if (DequeueEvent_LockFree(queue, &event)) {
WriterData *writer = (WriterData*)event.user.data1;
++data->counters[writer->index];
} else if (SDL_AtomicGet(&queue->active)) {
++data->waits;
SDL_Delay(0);
} else {
/* We drained the queue, we're done! */
break;
}
}
} else {
for ( ; ; ) {
if (DequeueEvent_Mutex(queue, &event)) {
WriterData *writer = (WriterData*)event.user.data1;
++data->counters[writer->index];
} else if (SDL_AtomicGet(&queue->active)) {
++data->waits;
SDL_Delay(0);
} else {
/* We drained the queue, we're done! */
break;
}
}
}
SDL_AtomicAdd(&readersRunning, -1);
SDL_SemPost(readersDone);
return 0;
}
#ifdef TEST_SPINLOCK_FIFO
/* This thread periodically locks the queue for no particular reason */
static int SDLCALL FIFO_Watcher(void* _data)
{
SDL_EventQueue *queue = (SDL_EventQueue *)_data;
while (SDL_AtomicGet(&queue->active)) {
SDL_AtomicLock(&queue->lock);
SDL_AtomicIncRef(&queue->watcher);
while (SDL_AtomicGet(&queue->rwcount) > 0) {
SDL_Delay(0);
}
/* Do queue manipulation here... */
SDL_AtomicDecRef(&queue->watcher);
SDL_AtomicUnlock(&queue->lock);
/* Wait a bit... */
SDL_Delay(1);
}
return 0;
}
#endif /* TEST_SPINLOCK_FIFO */
static void RunFIFOTest(SDL_bool lock_free)
{
SDL_EventQueue queue;
WriterData writerData[NUM_WRITERS];
ReaderData readerData[NUM_READERS];
Uint32 start, end;
int i, j;
int grand_total;
char textBuffer[1024];
size_t len;
SDL_Log("\nFIFO test---------------------------------------\n\n");
SDL_Log("Mode: %s\n", lock_free ? "LockFree" : "Mutex");
readersDone = SDL_CreateSemaphore(0);
writersDone = SDL_CreateSemaphore(0);
SDL_memset(&queue, 0xff, sizeof(queue));
InitEventQueue(&queue);
if (!lock_free) {
queue.mutex = SDL_CreateMutex();
}
start = SDL_GetTicks();
#ifdef TEST_SPINLOCK_FIFO
/* Start a monitoring thread */
if (lock_free) {
SDL_CreateThread(FIFO_Watcher, "FIFOWatcher", &queue);
}
#endif
/* Start the readers first */
SDL_Log("Starting %d readers\n", NUM_READERS);
SDL_zero(readerData);
SDL_AtomicSet(&readersRunning, NUM_READERS);
for (i = 0; i < NUM_READERS; ++i) {
char name[64];
SDL_snprintf(name, sizeof (name), "FIFOReader%d", i);
readerData[i].queue = &queue;
readerData[i].lock_free = lock_free;
SDL_CreateThread(FIFO_Reader, name, &readerData[i]);
}
/* Start up the writers */
SDL_Log("Starting %d writers\n", NUM_WRITERS);
SDL_zero(writerData);
SDL_AtomicSet(&writersRunning, NUM_WRITERS);
for (i = 0; i < NUM_WRITERS; ++i) {
char name[64];
SDL_snprintf(name, sizeof (name), "FIFOWriter%d", i);
writerData[i].queue = &queue;
writerData[i].index = i;
writerData[i].lock_free = lock_free;
SDL_CreateThread(FIFO_Writer, name, &writerData[i]);
}
/* Wait for the writers */
while (SDL_AtomicGet(&writersRunning) > 0) {
SDL_SemWait(writersDone);
}
/* Shut down the queue so readers exit */
SDL_AtomicSet(&queue.active, 0);
/* Wait for the readers */
while (SDL_AtomicGet(&readersRunning) > 0) {
SDL_SemWait(readersDone);
}
end = SDL_GetTicks();
SDL_DestroySemaphore(readersDone);
SDL_DestroySemaphore(writersDone);
if (!lock_free) {
SDL_DestroyMutex(queue.mutex);
}
SDL_Log("Finished in %f sec\n", (end - start) / 1000.f);
SDL_Log("\n");
for (i = 0; i < NUM_WRITERS; ++i) {
SDL_Log("Writer %d wrote %d events, had %d waits\n", i, EVENTS_PER_WRITER, writerData[i].waits);
}
SDL_Log("Writers wrote %d total events\n", NUM_WRITERS*EVENTS_PER_WRITER);
/* Print a breakdown of which readers read messages from which writer */
SDL_Log("\n");
grand_total = 0;
for (i = 0; i < NUM_READERS; ++i) {
int total = 0;
for (j = 0; j < NUM_WRITERS; ++j) {
total += readerData[i].counters[j];
}
grand_total += total;
SDL_Log("Reader %d read %d events, had %d waits\n", i, total, readerData[i].waits);
SDL_snprintf(textBuffer, sizeof(textBuffer), " { ");
for (j = 0; j < NUM_WRITERS; ++j) {
if (j > 0) {
len = SDL_strlen(textBuffer);
SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, ", ");
}
len = SDL_strlen(textBuffer);
SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, "%d", readerData[i].counters[j]);
}
len = SDL_strlen(textBuffer);
SDL_snprintf(textBuffer + len, sizeof(textBuffer) - len, " }\n");
SDL_Log("%s", textBuffer);
}
SDL_Log("Readers read %d total events\n", grand_total);
}
/* End FIFO test */
/**************************************************************************/
int
main(int argc, char *argv[])
{
/* Enable standard application logging */
SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO);
RunBasicTest();
RunEpicTest();
/* This test is really slow, so don't run it by default */
#if 0
RunFIFOTest(SDL_FALSE);
#endif
RunFIFOTest(SDL_TRUE);
return 0;
}
/* vi: set ts=4 sw=4 expandtab: */
SDL_UserEvent::data1
void * data1
Definition: SDL_events.h:501
DequeueEvent_Mutex
static SDL_bool DequeueEvent_Mutex(SDL_EventQueue *queue, SDL_Event *event)
Definition: testatomic.c:441
SDL_LockMutex
#define SDL_LockMutex
Definition: SDL_dynapi_overrides.h:260
ReaderData::queue
SDL_EventQueue * queue
Definition: testatomic.c:491
SDL_TRUE
Definition: SDL_stdinc.h:142
readersDone
static SDL_sem * readersDone
Definition: testatomic.c:475
WriterData::lock_free
SDL_bool lock_free
Definition: testatomic.c:485
SDL_EventQueue::dequeue_pos
SDL_atomic_t dequeue_pos
Definition: testatomic.c:278
v
const GLdouble * v
Definition: SDL_opengl.h:2064
SDL_AtomicLock
#define SDL_AtomicLock
Definition: SDL_dynapi_overrides.h:64
SDL_atomic_t
A type representing an atomic integer value. It is a struct so people don&#39;t accidentally use numeric ...
Definition: SDL_atomic.h:198
SDL_AtomicCAS
#define SDL_AtomicCAS
Definition: SDL_dynapi_overrides.h:66
InitEventQueue
static void InitEventQueue(SDL_EventQueue *queue)
Definition: testatomic.c:297
SDL_CreateSemaphore
#define SDL_CreateSemaphore
Definition: SDL_dynapi_overrides.h:264
atomicValue
#define atomicValue
Definition: testatomic.c:101
SDL_EventQueue::lock
SDL_SpinLock lock
Definition: testatomic.c:283
SDL_FALSE
Definition: SDL_stdinc.h:141
end
GLuint GLuint end
Definition: SDL_opengl.h:1571
SDL_CreateMutex
#define SDL_CreateMutex
Definition: SDL_dynapi_overrides.h:259
ReaderData::waits
int waits
Definition: testatomic.c:493
SDL_USEREVENT
Definition: SDL_events.h:154
EnqueueEvent_LockFree
static SDL_bool EnqueueEvent_LockFree(SDL_EventQueue *queue, const SDL_Event *event)
Definition: testatomic.c:314
main
int main(int argc, char *argv[])
Definition: testatomic.c:712
f
GLfloat f
Definition: SDL_opengl_glext.h:1870
FIFO_Writer
static int FIFO_Writer(void *_data)
Definition: testatomic.c:498
data
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
start
GLuint start
Definition: SDL_opengl.h:1571
writersRunning
static SDL_atomic_t writersRunning
Definition: testatomic.c:476
tf
static char * tf(SDL_bool tf)
Definition: testatomic.c:23
Uint32
uint32_t Uint32
Definition: SDL_stdinc.h:181
adder
static int adder(void *junk)
Definition: testatomic.c:120
WriterData::waits
int waits
Definition: testatomic.c:484
NInter
#define NInter
Definition: testatomic.c:103
CountTo
#define CountTo
Definition: testatomic.c:102
NThreads
#define NThreads
Definition: testatomic.c:97
len
GLenum GLsizei len
Definition: SDL_opengl_glext.h:2926
counters
GLint GLint GLsizei GLuint * counters
Definition: SDL_opengl_glext.h:4990
name
GLuint const GLchar * name
Definition: SDL_opengl_glext.h:660
WriterData
Definition: testatomic.c:479
T
static const double T[]
Definition: k_tan.c:53
ReaderData::lock_free
SDL_bool lock_free
Definition: testatomic.c:494
SDL_SemPost
#define SDL_SemPost
Definition: SDL_dynapi_overrides.h:269
SDL_mutex
Definition: SDL_sysmutex.c:29
SDL_AtomicUnlock
#define SDL_AtomicUnlock
Definition: SDL_dynapi_overrides.h:65
SDL_Log
#define SDL_Log
Definition: SDL_dynapi_overrides.h:31
SDL_EventQueue::entries
SDL_EventQueueEntry entries[MAX_ENTRIES]
Definition: testatomic.c:270
RunBasicTest
static void RunBasicTest()
Definition: testatomic.c:37
DequeueEvent_LockFree
static SDL_bool DequeueEvent_LockFree(SDL_EventQueue *queue, SDL_Event *event)
Definition: testatomic.c:361
readersRunning
static SDL_atomic_t readersRunning
Definition: testatomic.c:477
SDL_EventQueue::mutex
SDL_mutex * mutex
Definition: testatomic.c:293
SDL_GetTicks
Uint32 SDL_GetTicks(void)
Get the number of milliseconds since the SDL library initialization.
MAX_ENTRIES
#define MAX_ENTRIES
Definition: testatomic.c:259
event
struct _cl_event * event
Definition: SDL_opengl_glext.h:2649
j
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_CACHELINE_SIZE
#define SDL_CACHELINE_SIZE
Definition: SDL_cpuinfo.h:92
value
GLsizei const GLfloat * value
Definition: SDL_opengl_glext.h:698
WriterData::queue
SDL_EventQueue * queue
Definition: testatomic.c:481
SDL_atomic_t::value
int value
Definition: SDL_atomic.h:198
SDL_zero
#define SDL_zero(x)
Definition: SDL_stdinc.h:416
SDL_EventQueueEntry::event
SDL_Event event
Definition: testatomic.c:265
SDL_COMPILE_TIME_ASSERT
SDL_COMPILE_TIME_ASSERT(size, CountTo_GreaterThanZero)
SDL_LOG_PRIORITY_INFO
Definition: SDL_log.h:106
SDL_EventQueueEntry::sequence
SDL_atomic_t sequence
Definition: testatomic.c:264
EnqueueEvent_Mutex
static SDL_bool EnqueueEvent_Mutex(SDL_EventQueue *queue, const SDL_Event *event)
Definition: testatomic.c:408
SDL_AtomicIncRef
#define SDL_AtomicIncRef(a)
Increment an atomic variable used as a reference count.
Definition: SDL_atomic.h:234
good
static SDL_atomic_t good
Definition: testatomic.c:111
size
GLsizeiptr size
Definition: SDL_opengl_glext.h:537
SDL_CreateThread
#define SDL_CreateThread
Definition: SDL_dynapi_overrides.h:41
SDL_Delay
#define SDL_Delay
Definition: SDL_dynapi_overrides.h:486
SDL_EventQueue::watcher
SDL_atomic_t watcher
Definition: testatomic.c:285
i
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
NUM_WRITERS
#define NUM_WRITERS
Definition: testatomic.c:255
SDL_assert
#define SDL_assert(condition)
Definition: SDL_assert.h:169
threadDone
static SDL_sem * threadDone
Definition: testatomic.c:117
SDL_LogSetPriority
#define SDL_LogSetPriority
Definition: SDL_dynapi_overrides.h:236
ReaderData::counters
int counters[NUM_WRITERS]
Definition: testatomic.c:492
NULL
#define NULL
Definition: begin_code.h:164
SDL_AtomicAdd
#define SDL_AtomicAdd
Definition: SDL_dynapi_overrides.h:69
SDL_bool
SDL_bool
Definition: SDL_stdinc.h:139
FIFO_Watcher
static int FIFO_Watcher(void *_data)
Definition: testatomic.c:573
runAdder
static void runAdder(void)
Definition: testatomic.c:134
SDL_DestroyMutex
#define SDL_DestroyMutex
Definition: SDL_dynapi_overrides.h:263
EVENTS_PER_WRITER
#define EVENTS_PER_WRITER
Definition: testatomic.c:256
lock
SDL_mutex * lock
Definition: SDL_events.c:78
SDL_strlen
#define SDL_strlen
Definition: SDL_dynapi_overrides.h:393
writersDone
static SDL_sem * writersDone
Definition: testatomic.c:474
SDL_SemWait
#define SDL_SemWait
Definition: SDL_dynapi_overrides.h:266
SDL_AtomicDecRef
#define SDL_AtomicDecRef(a)
Decrement an atomic variable used as a reference count.
Definition: SDL_atomic.h:244
SDL_DestroySemaphore
#define SDL_DestroySemaphore
Definition: SDL_dynapi_overrides.h:265
SDL_AtomicSet
#define SDL_AtomicSet
Definition: SDL_dynapi_overrides.h:67
threadsRunning
static SDL_atomic_t threadsRunning
Definition: testatomic.c:115
SDL_AtomicGet
#define SDL_AtomicGet
Definition: SDL_dynapi_overrides.h:68
CountInc
#define CountInc
Definition: testatomic.c:98
SDL_snprintf
#define SDL_snprintf
Definition: SDL_dynapi_overrides.h:40
SDL_EventQueue::rwcount
SDL_atomic_t rwcount
Definition: testatomic.c:284
SDL_UnlockMutex
#define SDL_UnlockMutex
Definition: SDL_dynapi_overrides.h:262
SDL_Event
General event structure.
Definition: SDL_events.h:525
SDL_Event::user
SDL_UserEvent user
Definition: SDL_events.h:546
SDL_SpinLock
int SDL_SpinLock
Definition: SDL_atomic.h:89
WriterData::index
int index
Definition: testatomic.c:482
RunEpicTest
static void RunEpicTest()
Definition: testatomic.c:159
bad
static atomicValue bad
Definition: testatomic.c:113
ReaderData
Definition: testatomic.c:489
SDL.h
FIFO_Reader
static int FIFO_Reader(void *_data)
Definition: testatomic.c:533
Expect
#define Expect
Definition: testatomic.c:104
SDL_EventQueue::active
SDL_atomic_t active
Definition: testatomic.c:290
SDLCALL
#define SDLCALL
Definition: SDL_internal.h:45
b
GLboolean GLboolean GLboolean b
Definition: SDL_opengl_glext.h:1109
SDL_LOG_CATEGORY_APPLICATION
Definition: SDL_log.h:66
WRAP_MASK
#define WRAP_MASK
Definition: testatomic.c:260
SDL_EventQueue::enqueue_pos
SDL_atomic_t enqueue_pos
Definition: testatomic.c:274
RunFIFOTest
static void RunFIFOTest(SDL_bool lock_free)
Definition: testatomic.c:594
t
GLdouble GLdouble t
Definition: SDL_opengl.h:2071
SDL_memset
#define SDL_memset
Definition: SDL_dynapi_overrides.h:386
NUM_READERS
#define NUM_READERS
Definition: testatomic.c:254
SDL_EventQueue
Definition: testatomic.c:268
SDL_EventQueueEntry
Definition: testatomic.c:262