Get latest changes from LPP bot
This commit is contained in:
@@ -0,0 +1,114 @@
|
||||
#define DN_ASYNC_CPP
|
||||
|
||||
#include "../dn_base_inc.h"
|
||||
#include "../dn_os_inc.h"
|
||||
#include "dn_async.h"
|
||||
|
||||
static DN_I32 DN_ASYNC_ThreadEntryPoint_(DN_OSThread *thread)
|
||||
{
|
||||
DN_OS_ThreadSetName(DN_FStr8_ToStr8(&thread->name));
|
||||
DN_ASYNCCore *async = DN_CAST(DN_ASYNCCore *) thread->user_context;
|
||||
DN_Ring *ring = &async->ring;
|
||||
for (;;) {
|
||||
DN_OS_SemaphoreWait(&async->worker_sem, UINT32_MAX);
|
||||
if (async->join_threads)
|
||||
break;
|
||||
|
||||
DN_ASYNCJob job = {};
|
||||
for (DN_OS_MutexScope(&async->ring_mutex)) {
|
||||
if (DN_Ring_HasData(ring, sizeof(job))) {
|
||||
DN_Ring_Read(ring, &job, sizeof(job));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (job.work.func) {
|
||||
DN_OS_ConditionVariableBroadcast(&async->ring_write_cv); // Resume any blocked ring write(s)
|
||||
|
||||
DN_Atomic_AddU32(&async->busy_threads, 1);
|
||||
job.work.func(job.work.input);
|
||||
DN_Atomic_SubU32(&async->busy_threads, 1);
|
||||
|
||||
if (job.completion_sem.handle != 0)
|
||||
DN_OS_SemaphoreIncrement(&job.completion_sem, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DN_API void DN_ASYNC_Init(DN_ASYNCCore *async, char *base, DN_USize base_size, DN_OSThread *threads, DN_U32 threads_size)
|
||||
{
|
||||
DN_Assert(async);
|
||||
async->ring.size = base_size;
|
||||
async->ring.base = base;
|
||||
async->ring_mutex = DN_OS_MutexInit();
|
||||
async->ring_write_cv = DN_OS_ConditionVariableInit();
|
||||
async->worker_sem = DN_OS_SemaphoreInit(0);
|
||||
async->thread_count = threads_size;
|
||||
async->threads = threads;
|
||||
for (DN_ForIndexU(index, async->thread_count)) {
|
||||
DN_OSThread *thread = async->threads + index;
|
||||
thread->name = DN_FStr8_InitF<64>("ASYNC W%zu", index);
|
||||
DN_OS_ThreadInit(thread, DN_ASYNC_ThreadEntryPoint_, async);
|
||||
}
|
||||
}
|
||||
|
||||
DN_API void DN_ASYNC_Deinit(DN_ASYNCCore *async)
|
||||
{
|
||||
DN_Assert(async);
|
||||
DN_Atomic_SetValue32(&async->join_threads, true);
|
||||
DN_OS_SemaphoreIncrement(&async->worker_sem, async->thread_count);
|
||||
for (DN_ForItSize(it, DN_OSThread, async->threads, async->thread_count))
|
||||
DN_OS_ThreadDeinit(it.data);
|
||||
}
|
||||
|
||||
|
||||
static bool DN_ASYNC_QueueJob_(DN_ASYNCCore *async, DN_ASYNCJob const *job, DN_U64 wait_time_ms) {
|
||||
DN_U64 end_time_ms = DN_OS_DateUnixTimeMs() + wait_time_ms;
|
||||
bool result = false;
|
||||
for (DN_OS_MutexScope(&async->ring_mutex)) {
|
||||
for (;;) {
|
||||
if (DN_Ring_HasSpace(&async->ring, sizeof(*job))) {
|
||||
DN_Ring_WriteStruct(&async->ring, job);
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
DN_OS_ConditionVariableWaitUntil(&async->ring_write_cv, &async->ring_mutex, end_time_ms);
|
||||
if (DN_OS_DateUnixTimeMs() >= end_time_ms)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
DN_OS_SemaphoreIncrement(&async->worker_sem, 1); // Flag that a job is available
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API bool DN_ASYNC_QueueWork(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms)
|
||||
{
|
||||
DN_ASYNCJob job = {};
|
||||
job.work.func = func;
|
||||
job.work.input = input;
|
||||
bool result = DN_ASYNC_QueueJob_(async, &job, wait_time_ms);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API DN_OSSemaphore DN_ASYNC_QueueTask(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms)
|
||||
{
|
||||
DN_OSSemaphore result = DN_OS_SemaphoreInit(0);
|
||||
DN_ASYNCJob job = {};
|
||||
job.work.func = func;
|
||||
job.work.input = input;
|
||||
job.completion_sem = result;
|
||||
DN_ASYNC_QueueJob_(async, &job, wait_time_ms);
|
||||
return result;
|
||||
}
|
||||
|
||||
DN_API void DN_ASYNC_WaitTask(DN_OSSemaphore *sem, DN_U32 timeout_ms)
|
||||
{
|
||||
DN_OS_SemaphoreWait(sem, timeout_ms);
|
||||
DN_OS_SemaphoreDeinit(sem);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#if !defined(DN_ASYNC_H)
|
||||
#define DN_ASYNC_H
|
||||
|
||||
#include "../dn_base_inc.h"
|
||||
#include "../dn_os_inc.h"
|
||||
|
||||
enum DN_ASYNCPriority
|
||||
{
|
||||
DN_ASYNCPriority_Low,
|
||||
DN_ASYNCPriority_High,
|
||||
DN_ASYNCPriority_Count,
|
||||
};
|
||||
|
||||
struct DN_ASYNCCore
|
||||
{
|
||||
DN_OSMutex ring_mutex;
|
||||
DN_OSConditionVariable ring_write_cv;
|
||||
DN_OSSemaphore worker_sem;
|
||||
DN_Ring ring;
|
||||
DN_OSThread *threads;
|
||||
DN_U32 thread_count;
|
||||
DN_U32 busy_threads;
|
||||
DN_U32 join_threads;
|
||||
};
|
||||
|
||||
typedef void(DN_ASYNCWorkFunc)(void *input);
|
||||
|
||||
struct DN_ASYNCWork
|
||||
{
|
||||
DN_ASYNCWorkFunc *func;
|
||||
void *input;
|
||||
void *output;
|
||||
};
|
||||
|
||||
struct DN_ASYNCJob
|
||||
{
|
||||
DN_ASYNCWork work;
|
||||
DN_OSSemaphore completion_sem;
|
||||
};
|
||||
|
||||
struct DN_ASYNCTask
|
||||
{
|
||||
DN_ASYNCWork work;
|
||||
};
|
||||
|
||||
DN_API void DN_ASYNC_Init (DN_ASYNCCore *async, char *base, DN_USize base_size, DN_OSThread *threads, DN_U32 threads_size);
|
||||
DN_API void DN_ASYNC_Deinit (DN_ASYNCCore *async);
|
||||
DN_API bool DN_ASYNC_QueueWork(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms);
|
||||
DN_API DN_OSSemaphore DN_ASYNC_QueueTask(DN_ASYNCCore *async, DN_ASYNCWorkFunc *func, void *input, DN_U64 wait_time_ms);
|
||||
DN_API void DN_ASYNC_WaitTask (DN_OSSemaphore *sem, DN_U32 timeout_ms);
|
||||
|
||||
#endif // DN_ASYNC_H
|
||||
+12
-13
@@ -142,22 +142,21 @@ DN_API void DN_PCG32_Advance (DN_PCG32 *rng
|
||||
|
||||
#if !defined(DN_NO_JSON_BUILDER)
|
||||
// NOTE: DN_JSONBuilder ////////////////////////////////////////////////////////////////////////////
|
||||
#define DN_JSONBuilder_Object(builder) \
|
||||
DN_DEFER_LOOP(DN_JSONBuilder_ObjectBegin(builder), \
|
||||
DN_JSONBuilder_ObjectEnd(builder))
|
||||
#define DN_JSONBuilder_Object(builder) \
|
||||
DN_DeferLoop(DN_JSONBuilder_ObjectBegin(builder), \
|
||||
DN_JSONBuilder_ObjectEnd(builder))
|
||||
|
||||
#define DN_JSONBuilder_ObjectNamed(builder, name) \
|
||||
DN_DEFER_LOOP(DN_JSONBuilder_ObjectBeginNamed(builder, name), \
|
||||
DN_JSONBuilder_ObjectEnd(builder))
|
||||
#define DN_JSONBuilder_ObjectNamed(builder, name) \
|
||||
DN_DeferLoop(DN_JSONBuilder_ObjectBeginNamed(builder, name), \
|
||||
DN_JSONBuilder_ObjectEnd(builder))
|
||||
|
||||
#define DN_JSONBuilder_Array(builder) \
|
||||
DN_DEFER_LOOP(DN_JSONBuilder_ArrayBegin(builder), \
|
||||
DN_JSONBuilder_ArrayEnd(builder))
|
||||
|
||||
#define DN_JSONBuilder_ArrayNamed(builder, name) \
|
||||
DN_DEFER_LOOP(DN_JSONBuilder_ArrayBeginNamed(builder, name), \
|
||||
DN_JSONBuilder_ArrayEnd(builder))
|
||||
#define DN_JSONBuilder_Array(builder) \
|
||||
DN_DeferLoop(DN_JSONBuilder_ArrayBegin(builder), \
|
||||
DN_JSONBuilder_ArrayEnd(builder))
|
||||
|
||||
#define DN_JSONBuilder_ArrayNamed(builder, name) \
|
||||
DN_DeferLoop(DN_JSONBuilder_ArrayBeginNamed(builder, name), \
|
||||
DN_JSONBuilder_ArrayEnd(builder))
|
||||
|
||||
DN_API DN_JSONBuilder DN_JSONBuilder_Init (DN_Arena *arena, int spaces_per_indent);
|
||||
DN_API DN_Str8 DN_JSONBuilder_Build (DN_JSONBuilder const *builder, DN_Arena *arena);
|
||||
|
||||
+16
-16
@@ -407,22 +407,22 @@ void DN_JSON_ItErrorUnknownKeyValue_(DN_JSONIt *it, DN_CallSite call_site)
|
||||
json_string_s const *key = curr->name;
|
||||
if (it->flags & json_parse_flags_allow_location_information) {
|
||||
json_string_ex_s const *info = DN_CAST(json_string_ex_s const *)key;
|
||||
DN_Log_TypeFCallSite(DN_LogType_Warning,
|
||||
call_site,
|
||||
"Unknown key-value pair in object [loc=%zu:%zu, key=%.*s, value=%.*s]",
|
||||
info->line_no,
|
||||
info->row_no,
|
||||
DN_CAST(int)key->string_size,
|
||||
key->string,
|
||||
DN_CAST(int)value_type_size,
|
||||
value_type);
|
||||
DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Warning),
|
||||
call_site,
|
||||
"Unknown key-value pair in object [loc=%zu:%zu, key=%.*s, value=%.*s]",
|
||||
info->line_no,
|
||||
info->row_no,
|
||||
DN_CAST(int) key->string_size,
|
||||
key->string,
|
||||
DN_CAST(int) value_type_size,
|
||||
value_type);
|
||||
} else {
|
||||
DN_Log_TypeFCallSite(DN_LogType_Warning,
|
||||
call_site,
|
||||
"Unknown key-value pair in object [key=%.*s, value=%.*s]",
|
||||
DN_CAST(int)key->string_size,
|
||||
key->string,
|
||||
DN_CAST(int)value_type_size,
|
||||
value_type);
|
||||
DN_LOG_EmitFromType(DN_LOG_MakeU32LogTypeParam(DN_LOGType_Warning),
|
||||
call_site,
|
||||
"Unknown key-value pair in object [key=%.*s, value=%.*s]",
|
||||
DN_CAST(int) key->string_size,
|
||||
key->string,
|
||||
DN_CAST(int) value_type_size,
|
||||
value_type);
|
||||
}
|
||||
}
|
||||
|
||||
+62
-8
@@ -1151,8 +1151,8 @@ static DN_UTCore DN_Tests_Intrinsics()
|
||||
|
||||
DN_UT_Test(&result, "DN_Atomic_SetValue32")
|
||||
{
|
||||
long a = 0;
|
||||
long b = 111;
|
||||
DN_U32 a = 0;
|
||||
DN_U32 b = 111;
|
||||
DN_Atomic_SetValue32(&a, b);
|
||||
DN_UT_AssertF(&result, a == b, "a: %ld, b: %ld", a, b);
|
||||
}
|
||||
@@ -1574,6 +1574,8 @@ static DN_UTCore DN_Tests_M4()
|
||||
static DN_UTCore DN_Tests_OS()
|
||||
{
|
||||
DN_UTCore result = DN_UT_Init();
|
||||
|
||||
#if defined(DN_OS_INC_CPP) || 1
|
||||
DN_UT_LogF(&result, "DN_OS\n");
|
||||
{
|
||||
DN_UT_Test(&result, "Generate secure RNG bytes with nullptr")
|
||||
@@ -1690,6 +1692,58 @@ static DN_UTCore DN_Tests_OS()
|
||||
}
|
||||
}
|
||||
|
||||
DN_UT_LogF(&result, "\nSemaphore\n");
|
||||
{
|
||||
DN_OSSemaphore sem = DN_OS_SemaphoreInit(0);
|
||||
|
||||
DN_UT_Test(&result, "Wait timeout")
|
||||
{
|
||||
DN_U64 begin = DN_OS_PerfCounterNow();
|
||||
DN_OSSemaphoreWaitResult wait_result = DN_OS_SemaphoreWait(&sem, 100 /*timeout_ms*/);
|
||||
DN_U64 end = DN_OS_PerfCounterNow();
|
||||
DN_UT_AssertF(&result, wait_result == DN_OSSemaphoreWaitResult_Timeout, "Received wait result %zu", wait_result);
|
||||
DN_F64 elapsed_ms = DN_OS_PerfCounterMs(begin, end);
|
||||
DN_UT_AssertF(&result, elapsed_ms >= 100, "Expected to sleep for >= 100ms, slept %f ms", elapsed_ms);
|
||||
}
|
||||
|
||||
DN_UT_Test(&result, "Wait success")
|
||||
{
|
||||
DN_OS_SemaphoreIncrement(&sem, 1);
|
||||
DN_OSSemaphoreWaitResult wait_result = DN_OS_SemaphoreWait(&sem, 0 /*timeout_ms*/);
|
||||
DN_UT_AssertF(&result, wait_result == DN_OSSemaphoreWaitResult_Success, "Received wait result %zu", wait_result);
|
||||
}
|
||||
|
||||
DN_OS_SemaphoreDeinit(&sem);
|
||||
}
|
||||
|
||||
DN_UT_LogF(&result, "\nMutex\n");
|
||||
{
|
||||
DN_OSMutex mutex = DN_OS_MutexInit();
|
||||
DN_UT_Test(&result, "Lock")
|
||||
{
|
||||
DN_OS_MutexLock(&mutex);
|
||||
DN_OS_MutexUnlock(&mutex);
|
||||
}
|
||||
DN_OS_MutexDeinit(&mutex);
|
||||
}
|
||||
|
||||
DN_UT_LogF(&result, "\nCondition Variable\n");
|
||||
{
|
||||
DN_OSMutex mutex = DN_OS_MutexInit();
|
||||
DN_OSConditionVariable cv = DN_OS_ConditionVariableInit();
|
||||
DN_UT_Test(&result, "Lock and timeout")
|
||||
{
|
||||
DN_U64 begin = DN_OS_PerfCounterNow();
|
||||
DN_OS_ConditionVariableWait(&cv, &mutex, 100 /*sleep_ms*/);
|
||||
DN_U64 end = DN_OS_PerfCounterNow();
|
||||
DN_F64 elapsed_ms = DN_OS_PerfCounterMs(begin, end);
|
||||
DN_UT_AssertF(&result, elapsed_ms >= 100, "Expected to sleep for >= 100ms, slept %f ms", elapsed_ms);
|
||||
}
|
||||
DN_OS_MutexDeinit(&mutex);
|
||||
DN_OS_ConditionVariableDeinit(&cv);
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2372,25 +2426,25 @@ static DN_UTCore DN_Tests_Win()
|
||||
|
||||
DN_UT_Test(&result, "Str8 to Str16")
|
||||
{
|
||||
DN_Str16 str_result = DN_Win_Str8ToStr16(tmem.arena, input8);
|
||||
DN_Str16 str_result = DN_W32_Str8ToStr16(tmem.arena, input8);
|
||||
DN_UT_Assert(&result, str_result == input16);
|
||||
}
|
||||
|
||||
DN_UT_Test(&result, "Str16 to Str8")
|
||||
{
|
||||
DN_Str8 str_result = DN_Win_Str16ToStr8(tmem.arena, input16);
|
||||
DN_Str8 str_result = DN_W32_Str16ToStr8(tmem.arena, input16);
|
||||
DN_UT_Assert(&result, str_result == input8);
|
||||
}
|
||||
|
||||
DN_UT_Test(&result, "Str16 to Str8: Null terminates string")
|
||||
{
|
||||
int size_required = DN_Win_Str16ToStr8Buffer(input16, nullptr, 0);
|
||||
int size_required = DN_W32_Str16ToStr8Buffer(input16, nullptr, 0);
|
||||
char *string = DN_Arena_NewArray(tmem.arena, char, size_required + 1, DN_ZeroMem_No);
|
||||
|
||||
// Fill the string with error sentinels
|
||||
DN_Memset(string, 'Z', size_required + 1);
|
||||
|
||||
int size_returned = DN_Win_Str16ToStr8Buffer(input16, string, size_required + 1);
|
||||
int size_returned = DN_W32_Str16ToStr8Buffer(input16, string, size_required + 1);
|
||||
char const EXPECTED[] = {'S', 't', 'r', 'i', 'n', 'g', 0};
|
||||
|
||||
DN_UT_AssertF(&result, size_required == size_returned, "string_size: %d, result: %d", size_required, size_returned);
|
||||
@@ -2400,8 +2454,8 @@ static DN_UTCore DN_Tests_Win()
|
||||
|
||||
DN_UT_Test(&result, "Str16 to Str8: Arena null terminates string")
|
||||
{
|
||||
DN_Str8 string8 = DN_Win_Str16ToStr8(tmem.arena, input16);
|
||||
int size_returned = DN_Win_Str16ToStr8Buffer(input16, nullptr, 0);
|
||||
DN_Str8 string8 = DN_W32_Str16ToStr8(tmem.arena, input16);
|
||||
int size_returned = DN_W32_Str16ToStr8Buffer(input16, nullptr, 0);
|
||||
char const EXPECTED[] = {'S', 't', 'r', 'i', 'n', 'g', 0};
|
||||
|
||||
DN_UT_AssertF(&result, DN_CAST(int) string8.size == size_returned, "string_size: %d, result: %d", DN_CAST(int) string8.size, size_returned);
|
||||
|
||||
Reference in New Issue
Block a user