Make atomic add allow amounts not just +-1

This commit is contained in:
Doyle Thai 2017-06-26 12:37:52 +10:00
parent fca8db0366
commit 866126e735
2 changed files with 32 additions and 50 deletions

80
dqn.h
View File

@ -1093,13 +1093,15 @@ typedef struct DqnLock
void Release(); void Release();
void Delete (); void Delete ();
// Create a lock guard on the lock this is invoked on.
struct DqnLockGuard LockGuard(); struct DqnLockGuard LockGuard();
#endif #endif
} DqnLock; } DqnLock;
#if defined(DQN_CPP_MODE) #if defined(DQN_CPP_MODE)
// Lock guard automatically acquires a lock on construction and releases a lock // Lock guard automatically acquires a lock on construction and releases the associated lock on
// on destruction. // destruction. If the lock is unable to be acquired, the program blocks at construction until it
// can.
struct DqnLockGuard struct DqnLockGuard
{ {
// lock: Takes a pointer to a pre-existing and already initialised lock // lock: Takes a pointer to a pre-existing and already initialised lock
@ -1153,8 +1155,8 @@ typedef struct DqnJobQueue
u32 size; u32 size;
// NOTE(doyle): Modified by main+worker threads // NOTE(doyle): Modified by main+worker threads
u32 volatile jobToExecuteIndex; i32 volatile jobToExecuteIndex;
u32 volatile numJobsToComplete; i32 volatile numJobsToComplete;
#if defined(DQN_WIN32_PLATFORM) #if defined(DQN_WIN32_PLATFORM)
void *semaphore; void *semaphore;
@ -1167,9 +1169,8 @@ typedef struct DqnJobQueue
#endif #endif
// NOTE: Modified by main thread ONLY // NOTE: Modified by main thread ONLY
u32 volatile jobInsertIndex; i32 volatile jobInsertIndex;
#if defined(DQN_CPP_MODE) #if defined(DQN_CPP_MODE)
bool Init (const DqnJob *const jobList_, const u32 jobListSize, const u32 numThreads); bool Init (const DqnJob *const jobList_, const u32 jobListSize, const u32 numThreads);
@ -1217,15 +1218,11 @@ DQN_FILE_SCOPE bool DqnJobQueue_AllJobsComplete (DqnJobQueue *const queue);
// swapVal: The value to put into "dest", IF at point of read, "dest" has the value of "compareVal" // swapVal: The value to put into "dest", IF at point of read, "dest" has the value of "compareVal"
// compareVal: The value to check in "dest" // compareVal: The value to check in "dest"
// return: Return the original value that was in "dest" // return: Return the original value that was in "dest"
DQN_FILE_SCOPE u32 DqnAtomic_CompareSwap32(u32 volatile *const dest, const u32 swapVal, const u32 compareVal); DQN_FILE_SCOPE i32 DqnAtomic_CompareSwap32(i32 volatile *const dest, const i32 swapVal, const i32 compareVal);
// Increment the value at src by 1 // Add "value" to src
// return: The incremented value // return: The new value at src
DQN_FILE_SCOPE u32 DqnAtomic_Add32(u32 volatile *const src); DQN_FILE_SCOPE i32 DqnAtomic_Add32(i32 volatile *const src, const i32 value);
// Decrement the value at src by 1
// return: The decremented value
DQN_FILE_SCOPE u32 DqnAtomic_Sub32(u32 volatile *const src);
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// XPlatform > #DqnPlatform Public API - Common Platform API Helpers // XPlatform > #DqnPlatform Public API - Common Platform API Helpers
@ -6426,12 +6423,12 @@ DQN_FILE_SCOPE bool DqnJobQueue_Init(DqnJobQueue *const queue, DqnJob *const job
DQN_FILE_SCOPE bool DqnJobQueue_AddJob(DqnJobQueue *const queue, const DqnJob job) DQN_FILE_SCOPE bool DqnJobQueue_AddJob(DqnJobQueue *const queue, const DqnJob job)
{ {
u32 newJobInsertIndex = (queue->jobInsertIndex + 1) % queue->size; i32 newJobInsertIndex = (queue->jobInsertIndex + 1) % queue->size;
if (newJobInsertIndex == queue->jobToExecuteIndex) return false; if (newJobInsertIndex == queue->jobToExecuteIndex) return false;
queue->jobList[queue->jobInsertIndex] = job; queue->jobList[queue->jobInsertIndex] = job;
DqnAtomic_Add32(&queue->numJobsToComplete); DqnAtomic_Add32(&queue->numJobsToComplete, 1);
DQN_ASSERT(DqnJobQueueInternal_ReleaseSemaphore(queue)); DQN_ASSERT(DqnJobQueueInternal_ReleaseSemaphore(queue));
queue->jobInsertIndex = newJobInsertIndex; queue->jobInsertIndex = newJobInsertIndex;
@ -6448,11 +6445,11 @@ DQN_FILE_SCOPE bool DqnJobQueue_TryExecuteNextJob(DqnJobQueue *const queue)
{ {
if (!queue) return false; if (!queue) return false;
u32 originalJobToExecute = queue->jobToExecuteIndex; i32 originalJobToExecute = queue->jobToExecuteIndex;
if (originalJobToExecute != queue->jobInsertIndex) if (originalJobToExecute != queue->jobInsertIndex)
{ {
u32 newJobIndexForNextThread = (originalJobToExecute + 1) % queue->size; i32 newJobIndexForNextThread = (originalJobToExecute + 1) % queue->size;
u32 index = DqnAtomic_CompareSwap32(&queue->jobToExecuteIndex, newJobIndexForNextThread, i32 index = DqnAtomic_CompareSwap32(&queue->jobToExecuteIndex, newJobIndexForNextThread,
originalJobToExecute); originalJobToExecute);
// NOTE: If we weren't successful at the interlock, another thread has // NOTE: If we weren't successful at the interlock, another thread has
@ -6463,7 +6460,7 @@ DQN_FILE_SCOPE bool DqnJobQueue_TryExecuteNextJob(DqnJobQueue *const queue)
{ {
DqnJob job = queue->jobList[index]; DqnJob job = queue->jobList[index];
job.callback(queue, job.userData); job.callback(queue, job.userData);
DqnAtomic_Sub32(&queue->numJobsToComplete); DqnAtomic_Add32(&queue->numJobsToComplete, -1);
} }
return true; return true;
@ -6497,13 +6494,17 @@ bool DqnJobQueue::AllJobsComplete () { return DqnJobQueue_AllJo
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// XPlatform > #DqnAtomic Implementation // XPlatform > #DqnAtomic Implementation
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
DQN_FILE_SCOPE u32 DqnAtomic_CompareSwap32(u32 volatile *const dest, const u32 swapVal,
const u32 compareVal)
{
u32 result = 0;
#if defined(DQN_WIN32_PLATFORM) #if defined(DQN_WIN32_PLATFORM)
DQN_ASSERT(sizeof(LONG) == sizeof(u32)); DQN_COMPILE_ASSERT(sizeof(LONG) == sizeof(i32));
result = (u32)InterlockedCompareExchange((LONG volatile *)dest, (LONG)swapVal, (LONG)compareVal); #endif
DQN_FILE_SCOPE i32 DqnAtomic_CompareSwap32(i32 volatile *const dest, const i32 swapVal,
const i32 compareVal)
{
i32 result = 0;
#if defined(DQN_WIN32_PLATFORM)
result = (i32)InterlockedCompareExchange((LONG volatile *)dest, (LONG)swapVal, (LONG)compareVal);
#elif defined(DQN_UNIX_PLATFORM) #elif defined(DQN_UNIX_PLATFORM)
result = __sync_val_compare_and_swap(dest, compareVal, swapVal); result = __sync_val_compare_and_swap(dest, compareVal, swapVal);
@ -6515,33 +6516,14 @@ DQN_FILE_SCOPE u32 DqnAtomic_CompareSwap32(u32 volatile *const dest, const u32 s
return result; return result;
} }
DQN_FILE_SCOPE u32 DqnAtomic_Add32(u32 volatile *const src) DQN_FILE_SCOPE i32 DqnAtomic_Add32(i32 volatile *const src, const i32 value)
{ {
u32 result = 0; i32 result = 0;
#if defined(DQN_WIN32_PLATFORM) #if defined(DQN_WIN32_PLATFORM)
DQN_ASSERT(sizeof(LONG) == sizeof(u32)); result = (i32)InterlockedAdd((LONG volatile *)src, value);
result = (u32)InterlockedIncrement((LONG volatile *)src);
#elif defined(DQN_UNIX_PLATFORM) #elif defined(DQN_UNIX_PLATFORM)
result = __sync_add_and_fetch(src, 1); result = __sync_add_and_fetch(src, value);
#else
#error Unsupported platform
#endif
return result;
}
DQN_FILE_SCOPE u32 DqnAtomic_Sub32(u32 volatile *const src)
{
u32 result = 0;
#if defined(DQN_WIN32_PLATFORM)
DQN_ASSERT(sizeof(LONG) == sizeof(u32));
result = (u32)InterlockedDecrement((LONG volatile *)src);
#elif defined(DQN_UNIX_PLATFORM)
result = __sync_sub_and_fetch(src, 1);
#else #else
#error Unsupported platform #error Unsupported platform

View File

@ -21,7 +21,7 @@ Global
Release|x86 = Release|x86 Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{87785192-6F49-4F85-AA0D-F0AFA5CCCDDA}.Release|x86.ActiveCfg = Release|x86 {87785192-6F49-4F85-AA0D-F0AFA5CCCDDA}.Release|x86.ActiveCfg = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE