Commit 45d07688 authored by David Reid's avatar David Reid

Add ma_fence object in preparation for changes to async notifications.

parent cf2c9f25
...@@ -1127,6 +1127,34 @@ MA_API ma_result ma_slot_allocator_alloc(ma_slot_allocator* pAllocator, ma_uint6 ...@@ -1127,6 +1127,34 @@ MA_API ma_result ma_slot_allocator_alloc(ma_slot_allocator* pAllocator, ma_uint6
MA_API ma_result ma_slot_allocator_free(ma_slot_allocator* pAllocator, ma_uint64 slot); MA_API ma_result ma_slot_allocator_free(ma_slot_allocator* pAllocator, ma_uint64 slot);
/*
Fence
=====
This locks while the counter is larger than 0. Counter can be incremented and decremented by any
thread, but care needs to be taken when waiting. It is possible for one thread to acquire the
fence just as another thread returns from ma_fence_wait().
The idea behind a fence is to allow you to wait for a group of operations to complete. When an
operation starts, the counter is incremented which locks the fence. When the operation completes,
the fence will be released which decrements the counter. ma_fence_wait() will block until the
counter hits zero.
*/
typedef struct
{
ma_event e;
ma_uint32 counter;
} ma_fence;
MA_API ma_result ma_fence_init(ma_fence* pFence);
MA_API void ma_fence_uninit(ma_fence* pFence);
MA_API ma_result ma_fence_acquire(ma_fence* pFence); /* Increment counter. */
MA_API ma_result ma_fence_release(ma_fence* pFence); /* Decrement counter. */
MA_API ma_result ma_fence_wait(ma_fence* pFence); /* Wait for counter to reach 0. */
/* Notification codes for ma_async_notification. Used to allow some granularity for notification callbacks. */ /* Notification codes for ma_async_notification. Used to allow some granularity for notification callbacks. */
#define MA_NOTIFICATION_COMPLETE 0 /* Operation has fully completed. */ #define MA_NOTIFICATION_COMPLETE 0 /* Operation has fully completed. */
#define MA_NOTIFICATION_FAILED 1 /* Failed to initialize. */ #define MA_NOTIFICATION_FAILED 1 /* Failed to initialize. */
...@@ -5753,6 +5781,129 @@ MA_API ma_result ma_slot_allocator_free(ma_slot_allocator* pAllocator, ma_uint64 ...@@ -5753,6 +5781,129 @@ MA_API ma_result ma_slot_allocator_free(ma_slot_allocator* pAllocator, ma_uint64
#define MA_FENCE_COUNTER_MAX 0x7FFFFFFF
MA_API ma_result ma_fence_init(ma_fence* pFence)
{
ma_result result;
if (pFence == NULL) {
return MA_INVALID_ARGS;
}
MA_ZERO_OBJECT(pFence);
pFence->counter = 0;
result = ma_event_init(&pFence->e);
if (result != MA_SUCCESS) {
return result;
}
return MA_SUCCESS;
}
MA_API void ma_fence_uninit(ma_fence* pFence)
{
if (pFence == NULL) {
return;
}
ma_event_uninit(&pFence->e);
MA_ZERO_OBJECT(pFence);
}
MA_API ma_result ma_fence_acquire(ma_fence* pFence)
{
if (pFence == NULL) {
return MA_INVALID_ARGS;
}
for (;;) {
ma_uint32 oldCounter = c89atomic_load_32(&pFence->counter);
ma_uint32 newCounter = oldCounter + 1;
/* Make sure we're not about to exceed our maximum value. */
if (newCounter > MA_FENCE_COUNTER_MAX) {
return MA_OUT_OF_RANGE;
}
if (c89atomic_compare_exchange_weak_32(&pFence->counter, &oldCounter, newCounter)) {
return MA_SUCCESS;
} else {
if (oldCounter == MA_FENCE_COUNTER_MAX) {
return MA_OUT_OF_RANGE; /* The other thread took the last available slot. Abort. */
}
}
}
/* Should never get here. */
/*return MA_SUCCESS;*/
}
MA_API ma_result ma_fence_release(ma_fence* pFence)
{
if (pFence == NULL) {
return MA_INVALID_ARGS;
}
for (;;) {
ma_uint32 oldCounter = c89atomic_load_32(&pFence->counter);
ma_uint32 newCounter = oldCounter - 1;
if (oldCounter == 0) {
return MA_INVALID_OPERATION; /* Acquire/release mismatch. */
}
if (c89atomic_compare_exchange_weak_32(&pFence->counter, &oldCounter, newCounter)) {
if (newCounter == 0) {
ma_event_signal(&pFence->e); /* <-- ma_fence_wait() will be waiting on this. */
}
return MA_SUCCESS;
} else {
if (oldCounter == 0) {
return MA_INVALID_OPERATION; /* Another thread has taken the 0 slot. Acquire/release mismatch. */
}
}
}
/* Should never get here. */
/*return MA_SUCCESS;*/
}
MA_API ma_result ma_fence_wait(ma_fence* pFence)
{
if (pFence == NULL) {
return MA_INVALID_ARGS;
}
for (;;) {
ma_result result;
ma_uint32 counter;
counter = c89atomic_load_32(&pFence->counter);
if (counter == 0) {
/*
Counter has hit zero. By the time we get here some other thread may have acquired the
fence again, but that is where the caller needs to take care with how they se the fence.
*/
return MA_SUCCESS;
}
/* Getting here means the counter is > 0. We'll need to wait for something to happen. */
result = ma_event_wait(&pFence->e);
if (result != MA_SUCCESS) {
return result;
}
}
/* Should never get here. */
/*return MA_INVALID_OPERATION;*/
}
MA_API ma_result ma_async_notification_signal(ma_async_notification* pNotification, int code) MA_API ma_result ma_async_notification_signal(ma_async_notification* pNotification, int code)
{ {
ma_async_notification_callbacks* pNotificationCallbacks = (ma_async_notification_callbacks*)pNotification; ma_async_notification_callbacks* pNotificationCallbacks = (ma_async_notification_callbacks*)pNotification;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment