More cleanup

This commit is contained in:
doylet 2026-03-08 12:18:23 +11:00
parent 0f9af50a6d
commit dbbaa5fbf7
12 changed files with 432 additions and 415 deletions

View File

@ -1473,7 +1473,7 @@ DN_API bool DN_ErrSinkEndLogError_(DN_ErrSink *err, DN_CallSite call_site, DN_St
// NOTE: Log the error
DN_Str8 log = DN_Str8BuilderBuild(&builder, err->arena);
DN_LogEmitFromType(DN_LogMakeU32LogTypeParam(DN_LogType_Error), call_site, "%.*s", DN_Str8PrintFmt(log));
DN_LogPrint(DN_LogMakeU32LogTypeParam(DN_LogType_Error), call_site, "%.*s", DN_Str8PrintFmt(log));
if (node->mode == DN_ErrSinkMode_DebugBreakOnErrorLog)
DN_DebugBreak;
@ -1552,6 +1552,7 @@ DN_API void DN_TCInit(DN_TCCore *tc, DN_U64 thread_id, DN_Arena *main_arena, DN_
tc->temp_a_arena = temp_a_arena;
tc->temp_b_arena = temp_b_arena;
tc->err_sink.arena = err_sink_arena;
tc->lane.count = 1;
}
DN_API void DN_TCInitFromMemFuncs(DN_TCCore *tc, DN_U64 thread_id, DN_TCInitArgs *args, DN_ArenaMemFuncs mem_funcs)
@ -1671,6 +1672,21 @@ DN_API DN_ErrSink *DN_TCErrSink()
return result;
}
DN_API DN_TCLane *DN_TCLaneGet()
{
DN_TCCore *tc = DN_TCGet();
DN_TCLane *result = &tc->lane;
return result;
}
DN_API DN_TCLane DN_TCLaneEquip(DN_TCLane lane)
{
DN_TCLane *curr = DN_TCLaneGet();
DN_TCLane result = *curr;
*curr = lane;
return result;
}
DN_API void *DN_PoolCopy(DN_Pool *pool, void const *data, DN_U64 size, uint8_t align)
{
if (!pool || !data || size == 0)
@ -4063,8 +4079,6 @@ DN_API DN_U32 DN_MurmurHash3HashU32FromBytesX64(void const *bytes, int len, DN_U
return result;
}
static DN_LogEmitFromTypeFVFunc *g_dn_base_log_emit_from_type_fv_func_;
static void *g_dn_base_log_emit_from_type_fv_user_context_;
DN_API DN_Str8 DN_LogColourEscapeCodeStr8FromRGB(DN_LogColourType colour, DN_U8 r, DN_U8 g, DN_U8 b)
{
DN_THREAD_LOCAL char buffer[32];
@ -4161,20 +4175,19 @@ DN_API DN_LogPrefixSize DN_LogMakePrefix(DN_LogStyle style, DN_LogTypeParam type
return result;
}
DN_API void DN_LogSetEmitFromTypeFVFunc(DN_LogEmitFromTypeFVFunc *print_func, void *user_data)
DN_API void DN_LogSetPrintFunc(DN_LogPrintFunc *print_func, void *user_data)
{
g_dn_base_log_emit_from_type_fv_func_ = print_func;
g_dn_base_log_emit_from_type_fv_user_context_ = user_data;
g_dn_->print_func = print_func;
g_dn_->print_func_context = user_data;
}
DN_API void DN_LogEmitFromType(DN_LogTypeParam type, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...)
DN_API void DN_LogPrint(DN_LogTypeParam type, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...)
{
DN_LogEmitFromTypeFVFunc *func = g_dn_base_log_emit_from_type_fv_func_;
void *user_context = g_dn_base_log_emit_from_type_fv_user_context_;
DN_LogPrintFunc *func = g_dn_->print_func;
if (func) {
va_list args;
va_start(args, fmt);
func(type, user_context, call_site, fmt, args);
func(type, g_dn_->print_func_context, call_site, fmt, args);
va_end(args);
}
}

View File

@ -1041,6 +1041,14 @@ struct DN_ErrSink
DN_USize stack_size;
};
struct DN_TCLane
{
DN_USize index;
DN_USize count;
DN_U64 barrier_handle;
void* shared_mem;
};
struct DN_TCScratch
{
DN_Arena* arena;
@ -1072,6 +1080,7 @@ struct DN_TCCore // (T)hread (C)ontext sitting in thread-local storage
DN_Str8x64 name;
DN_U64 thread_id;
DN_CallSite call_site;
DN_TCLane lane;
DN_Arena main_arena_;
DN_Arena temp_a_arena_;
@ -1174,7 +1183,7 @@ struct DN_StackTraceWalkResultIterator
DN_U16 index;
};
typedef void DN_LogEmitFromTypeFVFunc(DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args);
typedef void DN_LogPrintFunc(DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args);
#if !defined(DN_STB_SPRINTF_HEADER_ONLY)
#define STB_SPRINTF_IMPLEMENTATION
@ -1189,8 +1198,6 @@ DN_GCC_WARNING_DISABLE(-Wunused-function)
DN_GCC_WARNING_POP
DN_MSVC_WARNING_POP
DN_API void DN_BeginFrame ();
#define DN_SPrintF(...) STB_SPRINTF_DECORATE(sprintf)(__VA_ARGS__)
#define DN_SNPrintF(...) STB_SPRINTF_DECORATE(snprintf)(__VA_ARGS__)
#define DN_VSPrintF(...) STB_SPRINTF_DECORATE(vsprintf)(__VA_ARGS__)
@ -1367,6 +1374,7 @@ DN_API DN_Arena* DN_TCFrameArena
DN_API DN_ErrSink* DN_TCErrSink ();
#define DN_TCErrSinkBegin(mode) DN_ErrSinkBegin(DN_TCErrSink(), mode)
#define DN_TCErrSinkBeginDefault() DN_ErrSinkBeginDefault(DN_TCErrSink())
DN_API DN_TCLane DN_TCLaneEquip (DN_TCLane lane);
DN_API bool DN_CharIsAlphabet (char ch);
DN_API bool DN_CharIsDigit (char ch);
@ -1602,13 +1610,13 @@ DN_API DN_U32 DN_MurmurHash3HashU32FromBytesX64
DN_API DN_Str8 DN_LogColourEscapeCodeStr8FromRGB (DN_LogColourType colour, DN_U8 r, DN_U8 g, DN_U8 b);
DN_API DN_Str8 DN_LogColourEscapeCodeStr8FromU32 (DN_LogColourType colour, DN_U32 value);
DN_API DN_LogPrefixSize DN_LogMakePrefix (DN_LogStyle style, DN_LogTypeParam type, DN_CallSite call_site, DN_LogDate date, char *dest, DN_USize dest_size);
DN_API void DN_LogSetEmitFromTypeFVFunc (DN_LogEmitFromTypeFVFunc *print_func, void *user_data);
DN_API void DN_LogEmitFromType (DN_LogTypeParam type, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...);
DN_API void DN_LogSetPrintFunc (DN_LogPrintFunc *print_func, void *user_data);
DN_API void DN_LogPrint (DN_LogTypeParam type, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, ...);
DN_API DN_LogTypeParam DN_LogMakeU32LogTypeParam (DN_LogType type);
#define DN_LogDebugF(fmt, ...) DN_LogEmitFromType(DN_LogMakeU32LogTypeParam(DN_LogType_Debug), DN_CALL_SITE, fmt, ##__VA_ARGS__)
#define DN_LogInfoF(fmt, ...) DN_LogEmitFromType(DN_LogMakeU32LogTypeParam(DN_LogType_Info), DN_CALL_SITE, fmt, ##__VA_ARGS__)
#define DN_LogWarningF(fmt, ...) DN_LogEmitFromType(DN_LogMakeU32LogTypeParam(DN_LogType_Warning), DN_CALL_SITE, fmt, ##__VA_ARGS__)
#define DN_LogErrorF(fmt, ...) DN_LogEmitFromType(DN_LogMakeU32LogTypeParam(DN_LogType_Error), DN_CALL_SITE, fmt, ##__VA_ARGS__)
#define DN_LogDebugF(fmt, ...) DN_LogPrint(DN_LogMakeU32LogTypeParam(DN_LogType_Debug), DN_CALL_SITE, fmt, ##__VA_ARGS__)
#define DN_LogInfoF(fmt, ...) DN_LogPrint(DN_LogMakeU32LogTypeParam(DN_LogType_Info), DN_CALL_SITE, fmt, ##__VA_ARGS__)
#define DN_LogWarningF(fmt, ...) DN_LogPrint(DN_LogMakeU32LogTypeParam(DN_LogType_Warning), DN_CALL_SITE, fmt, ##__VA_ARGS__)
#define DN_LogErrorF(fmt, ...) DN_LogPrint(DN_LogMakeU32LogTypeParam(DN_LogType_Error), DN_CALL_SITE, fmt, ##__VA_ARGS__)
// NOTE: OS primitives that the OS layer can provide for the base layer but is optional.
#if defined(DN_FREESTANDING)

View File

@ -64,7 +64,7 @@ DN_API void DN_ASYNC_Deinit(DN_ASYNCCore *async)
DN_AtomicSetValue32(&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);
DN_OS_ThreadJoin(it.data);
}
static bool DN_ASYNC_QueueTask_(DN_ASYNCCore *async, DN_ASYNCTask const *task, DN_U64 wait_time_ms) {

View File

@ -413,7 +413,7 @@ void DN_NET_CurlDeinit(DN_NETCore *net)
DN_NETCurlCore *curl = DN_Cast(DN_NETCurlCore *) net->context;
curl->kill_thread = true;
curl_multi_wakeup(curl->thread_curlm);
DN_OS_ThreadDeinit(&curl->thread);
DN_OS_ThreadJoin(&curl->thread);
}
static DN_NETRequestHandle DN_NET_CurlDoRequest_(DN_NETCore *net, DN_Str8 url, DN_Str8 method, DN_NETDoHTTPArgs const *args, DN_NETRequestType type)

View File

@ -1,9 +1,9 @@
#define DN_OS_CPP
#if defined(_CLANGD)
#include "../Base/dn_base.h"
#include "../dn_os.h"
#include "../dn_os_w32.h"
#define DN_H_WITH_OS 1
#define DN_H_WITH_CORE 1
#include "../dn.h"
#endif
#if defined(DN_PLATFORM_POSIX)
@ -20,7 +20,7 @@ static void *DN_ArenaBasicAllocFromOSHeap(DN_USize size)
DN_API DN_ArenaMemFuncs DN_ArenaMemFuncsGet(DN_ArenaMemFuncType type)
{
DN_ArenaMemFuncs result = {};
result.type = type;
result.type = type;
switch (type) {
case DN_ArenaMemFuncType_Nil: break;
case DN_ArenaMemFuncType_Basic: {
@ -30,6 +30,7 @@ DN_API DN_ArenaMemFuncs DN_ArenaMemFuncsGet(DN_ArenaMemFuncType type)
};
case DN_ArenaMemFuncType_VMem: {
DN_Assert(g_dn_->init_flags & DN_InitFlags_OS);
result.type = DN_ArenaMemFuncType_VMem;
result.vmem_page_size = g_dn_->os.page_size;
result.vmem_reserve = DN_OS_MemReserve;
@ -42,12 +43,13 @@ DN_API DN_ArenaMemFuncs DN_ArenaMemFuncsGet(DN_ArenaMemFuncType type)
DN_API DN_ArenaMemFuncs DN_ArenaMemFuncsGetDefaults()
{
DN_ArenaMemFuncs result = {};
#if defined(DN_PLATFORM_EMSCRIPTEN)
result = DN_ArenaMemFuncsGet(DN_ArenaMemFuncType_Basic);
#else
result = DN_ArenaMemFuncsGet(DN_ArenaMemFuncType_VMem);
#endif
DN_ArenaMemFuncType type = DN_ArenaMemFuncType_Basic;
if (g_dn_->os_init) {
#if !defined(DN_PLATFORM_EMSCRIPTEN)
type = DN_ArenaMemFuncType_VMem;
#endif
}
DN_ArenaMemFuncs result = DN_ArenaMemFuncsGet(type);
return result;
}
@ -133,24 +135,24 @@ DN_API DN_Str8 DN_Str8BuilderBuildFromHeap(DN_Str8Builder const *builder)
return result;
}
static void DN_OS_LOGEmitFromTypeTypeFV_(DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args)
DN_API void DN_OS_LogPrint(DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args)
{
DN_Assert(user_data);
DN_OSCore *core = DN_Cast(DN_OSCore *)user_data;
DN_OSCore *os = DN_Cast(DN_OSCore *)user_data;
// NOTE: Open log file for appending if requested
DN_TicketMutex_Begin(&core->log_file_mutex);
if (core->log_to_file && !core->log_file.handle && !core->log_file.error) {
DN_TicketMutex_Begin(&os->log_file_mutex);
if (os->log_to_file && !os->log_file.handle && !os->log_file.error) {
DN_TCScratch scratch = DN_TCScratchBegin(nullptr, 0);
DN_Str8 exe_dir = DN_OS_EXEDir(scratch.arena);
DN_Str8 log_path = DN_OS_PathF(scratch.arena, "%.*s/dn.log", DN_Str8PrintFmt(exe_dir));
core->log_file = DN_OS_FileOpen(log_path, DN_OSFileOpen_CreateAlways, DN_OSFileAccess_AppendOnly, nullptr);
os->log_file = DN_OS_FileOpen(log_path, DN_OSFileOpen_CreateAlways, DN_OSFileAccess_AppendOnly, nullptr);
DN_TCScratchEnd(&scratch);
}
DN_TicketMutex_End(&core->log_file_mutex);
DN_TicketMutex_End(&os->log_file_mutex);
DN_LogStyle style = {};
if (!core->log_no_colour) {
if (!os->log_no_colour) {
style.colour = true;
style.bold = DN_LogBold_Yes;
if (type.is_u32_enum) {
@ -191,14 +193,14 @@ static void DN_OS_LOGEmitFromTypeTypeFV_(DN_LogTypeParam type, void *user_data,
va_list args_copy;
va_copy(args_copy, args);
DN_TicketMutex_Begin(&core->log_file_mutex);
DN_TicketMutex_Begin(&os->log_file_mutex);
{
DN_OS_FileWrite(&core->log_file, DN_Str8FromPtr(prefix_buffer, prefix_size.size), nullptr);
DN_OS_FileWriteF(&core->log_file, nullptr, "%*s ", DN_Cast(int)prefix_size.padding, "");
DN_OS_FileWriteFV(&core->log_file, nullptr, fmt, args_copy);
DN_OS_FileWrite(&core->log_file, DN_Str8Lit("\n"), nullptr);
DN_OS_FileWrite(&os->log_file, DN_Str8FromPtr(prefix_buffer, prefix_size.size), nullptr);
DN_OS_FileWriteF(&os->log_file, nullptr, "%*s ", DN_Cast(int)prefix_size.padding, "");
DN_OS_FileWriteFV(&os->log_file, nullptr, fmt, args_copy);
DN_OS_FileWrite(&os->log_file, DN_Str8Lit("\n"), nullptr);
}
DN_TicketMutex_End(&core->log_file_mutex);
DN_TicketMutex_End(&os->log_file_mutex);
va_end(args_copy);
DN_OSPrintDest dest = (type.is_u32_enum && type.u32 == DN_LogType_Error) ? DN_OSPrintDest_Err : DN_OSPrintDest_Out;
@ -207,76 +209,9 @@ static void DN_OS_LOGEmitFromTypeTypeFV_(DN_LogTypeParam type, void *user_data,
DN_OS_PrintLnFV(dest, fmt, args);
}
DN_API void DN_OS_EmitLogsWithOSPrintFunctions(DN_OSCore *os)
DN_API void DN_OS_SetLogPrintFuncToOS()
{
DN_Assert(os);
DN_LogSetEmitFromTypeFVFunc(DN_OS_LOGEmitFromTypeTypeFV_, os);
}
DN_API void DN_OS_DumpThreadContextArenaStat(DN_Str8 file_path)
{
#if defined(DN_DEBUG_THREAD_CONTEXT)
// NOTE: Open a file to write the arena stats to
FILE *file = nullptr;
fopen_s(&file, file_path.data, "a+b");
if (file) {
DN_LogErrorF("Failed to dump thread context arenas [file=%.*s]", DN_Str8PrintFmt(file_path));
return;
}
// NOTE: Copy the stats from library book-keeping
// NOTE: Extremely short critical section, copy the stats then do our
// work on it.
DN_ArenaStat stats[DN_ArrayCountU(g_dn_core->thread_context_arena_stats)];
int stats_size = 0;
DN_TicketMutex_Begin(&g_dn_core->thread_context_mutex);
stats_size = g_dn_core->thread_context_arena_stats_count;
DN_Memcpy(stats, g_dn_core->thread_context_arena_stats, sizeof(stats[0]) * stats_size);
DN_TicketMutex_End(&g_dn_core->thread_context_mutex);
// NOTE: Print the cumulative stat
DN_DateHMSTimeStr now = DN_Date_HMSLocalTimeStrNow();
fprintf(file,
"Time=%.*s %.*s | Thread Context Arenas | Count=%d\n",
now.date_size,
now.date,
now.hms_size,
now.hms,
g_dn_core->thread_context_arena_stats_count);
// NOTE: Write the cumulative thread arena data
{
DN_ArenaStat stat = {};
for (DN_USize index = 0; index < stats_size; index++) {
DN_ArenaStat const *current = stats + index;
stat.capacity += current->capacity;
stat.used += current->used;
stat.wasted += current->wasted;
stat.blocks += current->blocks;
stat.capacity_hwm = DN_Max(stat.capacity_hwm, current->capacity_hwm);
stat.used_hwm = DN_Max(stat.used_hwm, current->used_hwm);
stat.wasted_hwm = DN_Max(stat.wasted_hwm, current->wasted_hwm);
stat.blocks_hwm = DN_Max(stat.blocks_hwm, current->blocks_hwm);
}
DN_ArenaStatStr stats_string = DN_ArenaStatStr(&stat);
fprintf(file, " [ALL] CURR %.*s\n", stats_string.size, stats_string.data);
}
// NOTE: Print individual thread arena data
for (DN_USize index = 0; index < stats_size; index++) {
DN_ArenaStat const *current = stats + index;
DN_ArenaStatStr current_string = DN_ArenaStatStr(current);
fprintf(file, " [%03d] CURR %.*s\n", DN_Cast(int) index, current_string.size, current_string.data);
}
fclose(file);
DN_LogInfoF("Dumped thread context arenas [file=%.*s]", DN_Str8PrintFmt(file_path));
#else
(void)file_path;
#endif // #if defined(DN_DEBUG_THREAD_CONTEXT)
DN_LogSetPrintFunc(DN_OS_LogPrint, &g_dn_->os);
}
// NOTE: Date
@ -759,14 +694,21 @@ static void DN_OS_ThreadExecute_(void *user_context)
DN_ArenaMemFuncs mem_funcs = DN_ArenaMemFuncsGetDefaults();
DN_TCInitFromMemFuncs(&thread->context, thread->thread_id, /*args=*/nullptr, mem_funcs);
DN_TCEquip(&thread->context);
if (thread->is_lane_set)
DN_TCLaneEquip(thread->lane);
DN_OS_SemaphoreWait(&thread->init_semaphore, DN_OS_SEMAPHORE_INFINITE_TIMEOUT);
thread->func(thread);
}
DN_API void DN_OS_ThreadSetName(DN_Str8 name)
DN_API void DN_OS_ThreadSetNameFmt(char const *fmt, ...)
{
DN_TCCore *tls = DN_TCGet();
tls->name = DN_Str8x64FromFmt("%.*s", DN_Str8PrintFmt(name));
va_list args;
va_start(args, fmt);
tls->name = DN_Str8x64FromFmtV(fmt, args);
va_end(args);
DN_Str8 name = DN_Str8FromPtr(tls->name.data, tls->name.size);
#if defined(DN_PLATFORM_WIN32)
DN_OS_W32ThreadSetName(name);
#else

View File

@ -203,6 +203,8 @@ struct DN_OSThread
{
DN_Str8x64 name;
DN_TCCore context;
DN_TCLane lane;
bool is_lane_set;
void *handle;
DN_U64 thread_id;
void *user_context;
@ -248,32 +250,30 @@ struct DN_OSHttpResponse
struct DN_OSCore
{
DN_CPUReport cpu_report;
DN_CPUReport cpu_report;
// NOTE: Logging
DN_LogEmitFromTypeFVFunc * log_callback; // Set this pointer to override the logging routine
void * log_user_data; // User pointer passed into 'log_callback'
bool log_to_file; // Output logs to file as well as standard out
DN_OSFile log_file; // TODO(dn): Hmmm, how should we do this... ?
DN_TicketMutex log_file_mutex; // Is locked when instantiating the log_file for the first time
bool log_no_colour; // Disable colours in the logging output
bool log_to_file; // Output logs to file as well as standard out
DN_OSFile log_file; // TODO(dn): Hmmm, how should we do this... ?
DN_TicketMutex log_file_mutex; // Is locked when instantiating the log_file for the first time
bool log_no_colour; // Disable colours in the logging output
// NOTE: OS
DN_U32 logical_processor_count;
DN_U32 page_size;
DN_U32 alloc_granularity;
DN_U32 logical_processor_count;
DN_U32 page_size;
DN_U32 alloc_granularity;
// NOTE: Memory
// Total OS mem allocs in lifetime of program (e.g. malloc, VirtualAlloc, HeapAlloc ...). This
// only includes allocations routed through the library such as the growing nature of arenas or
// using the memory allocation routines in the library like DN_OS_MemCommit and so forth.
DN_U64 vmem_allocs_total;
DN_U64 vmem_allocs_frame; // Total OS virtual memory allocs since the last 'DN_Core_FrameBegin' was invoked
DN_U64 mem_allocs_total;
DN_U64 mem_allocs_frame; // Total OS heap allocs since the last 'DN_Core_FrameBegin' was invoked
DN_U64 vmem_allocs_total;
DN_U64 vmem_allocs_frame; // Total OS virtual memory allocs since the last 'DN_Core_FrameBegin' was invoked
DN_U64 mem_allocs_total;
DN_U64 mem_allocs_frame; // Total OS heap allocs since the last 'DN_Core_FrameBegin' was invoked
DN_Arena arena;
void *platform_context;
DN_Arena arena;
void *platform_context;
};
struct DN_OSDiskSpace
@ -293,7 +293,8 @@ DN_API DN_Str8 DN_Str8FromHeapF (D
DN_API DN_Str8 DN_Str8FromHeap (DN_USize size, DN_ZMem z_mem);
DN_API DN_Str8 DN_Str8BuilderBuildFromHeap (DN_Str8Builder const *builder);
DN_API void DN_OS_EmitLogsWithOSPrintFunctions (DN_OSCore *os);
DN_API void DN_OS_LogPrint (DN_LogTypeParam type, void *user_data, DN_CallSite call_site, DN_FMT_ATTRIB char const *fmt, va_list args);
DN_API void DN_OS_SetLogPrintFuncToOS ();
DN_API void DN_OS_DumpThreadContextArenaStat (DN_Str8 file_path);
DN_API void * DN_OS_MemReserve (DN_USize size, DN_MemCommit commit, DN_MemPage page_flags);
@ -410,10 +411,10 @@ DN_API bool DN_OS_ConditionVariableWaitUntil (D
DN_API void DN_OS_ConditionVariableSignal (DN_OSConditionVariable *cv);
DN_API void DN_OS_ConditionVariableBroadcast (DN_OSConditionVariable *cv);
DN_API bool DN_OS_ThreadInit (DN_OSThread *thread, DN_OSThreadFunc *func, void *user_context);
DN_API void DN_OS_ThreadDeinit (DN_OSThread *thread);
DN_API bool DN_OS_ThreadInit (DN_OSThread *thread, DN_OSThreadFunc *func, DN_TCLane *lane, void *user_context);
DN_API bool DN_OS_ThreadJoin (DN_OSThread *thread);
DN_API DN_U32 DN_OS_ThreadID ();
DN_API void DN_OS_ThreadSetName (DN_Str8 name);
DN_API void DN_OS_ThreadSetNameFmt (char const *fmt, ...);
DN_API void DN_OS_HttpRequestAsync (DN_OSHttpResponse *response, DN_Arena *arena, DN_Str8 host, DN_Str8 path, DN_OSHttpRequestSecure secure, DN_Str8 method, DN_Str8 body, DN_Str8 headers);
DN_API void DN_OS_HttpRequestWait (DN_OSHttpResponse *response);

View File

@ -1289,7 +1289,7 @@ static void *DN_OS_ThreadFunc_(void *user_context)
return nullptr;
}
DN_API bool DN_OS_ThreadInit(DN_OSThread *thread, DN_OSThreadFunc *func, void *user_context)
DN_API bool DN_OS_ThreadInit(DN_OSThread *thread, DN_OSThreadFunc *func, DN_TCLane *lane, void *user_context)
{
bool result = false;
if (!thread)
@ -1298,6 +1298,7 @@ DN_API bool DN_OS_ThreadInit(DN_OSThread *thread, DN_OSThreadFunc *func, void *u
thread->func = func;
thread->user_context = user_context;
thread->init_semaphore = DN_OS_SemaphoreInit(0 /*initial_count*/);
thread->lane = lane;
// TODO(doyle): Check if semaphore is valid
// NOTE: pthread_t is essentially the thread ID. In Windows, the handle and
@ -1331,18 +1332,19 @@ DN_API bool DN_OS_ThreadInit(DN_OSThread *thread, DN_OSThreadFunc *func, void *u
return result;
}
DN_API void DN_OS_ThreadDeinit(DN_OSThread *thread)
DN_API bool DN_OS_ThreadJoin(DN_OSThread *thread)
{
if (!thread || !thread->handle)
return;
bool result = false;
if (thread && thread->handle) {
pthread_t thread_id = {};
DN_Memcpy(&thread_id, &thread->thread_id, sizeof(thread_id));
pthread_t thread_id = {};
DN_Memcpy(&thread_id, &thread->thread_id, sizeof(thread_id));
void *return_val = nullptr;
pthread_join(thread_id, &return_val);
thread->handle = {};
thread->thread_id = {};
void *return_val = nullptr;
result = pthread_join(thread_id, &return_val) == 0;
thread->handle = {};
thread->thread_id = {};
}
return result;
}
DN_API DN_U32 DN_OS_ThreadID()

View File

@ -2,6 +2,7 @@
#if defined(_CLANGD)
#define DN_H_WITH_CORE 1
#define DN_H_WITH_OS 1
#include "../dn.h"
#include "dn_os_w32.h"
#endif
@ -1235,14 +1236,14 @@ DN_API void DN_OS_ConditionVariableBroadcast(DN_OSConditionVariable *cv)
}
}
// NOTE: DN_OSThread ///////////////////////////////////////////////////////////////////////////////
// NOTE: DN_OSThread
static DWORD __stdcall DN_OS_ThreadFunc_(void *user_context)
{
DN_OS_ThreadExecute_(user_context);
return 0;
}
DN_API bool DN_OS_ThreadInit(DN_OSThread *thread, DN_OSThreadFunc *func, void *user_context)
DN_API bool DN_OS_ThreadInit(DN_OSThread *thread, DN_OSThreadFunc *func, DN_TCLane *lane, void *user_context)
{
bool result = false;
if (!thread)
@ -1251,6 +1252,10 @@ DN_API bool DN_OS_ThreadInit(DN_OSThread *thread, DN_OSThreadFunc *func, void *u
thread->func = func;
thread->user_context = user_context;
thread->init_semaphore = DN_OS_SemaphoreInit(0 /*initial_count*/);
if (lane) {
thread->is_lane_set = true;
thread->lane = *lane;
}
// TODO(doyle): Check if semaphore is valid
DWORD thread_id = 0;
@ -1277,16 +1282,18 @@ DN_API bool DN_OS_ThreadInit(DN_OSThread *thread, DN_OSThreadFunc *func, void *u
return result;
}
DN_API void DN_OS_ThreadDeinit(DN_OSThread *thread)
DN_API bool DN_OS_ThreadJoin(DN_OSThread *thread)
{
if (!thread || !thread->handle)
return;
WaitForSingleObject(thread->handle, INFINITE);
CloseHandle(thread->handle);
thread->handle = INVALID_HANDLE_VALUE;
thread->thread_id = {};
DN_TCDeinit(&thread->context);
bool result = false;
if (thread && thread->handle) {
DWORD wait_result = WaitForSingleObject(thread->handle, INFINITE);
result = wait_result == WAIT_OBJECT_0;
CloseHandle(thread->handle);
thread->handle = INVALID_HANDLE_VALUE;
thread->thread_id = {};
DN_TCDeinit(&thread->context);
}
return result;
}
DN_API DN_U32 DN_OS_ThreadID()

View File

@ -1,3 +1,8 @@
#if (_CLANGD)
#define DN_H_WITH_OS 1
#include "dn.h"
#endif
#include "Base/dn_base.cpp"
#include "Base/dn_base_containers.cpp"
#include "Base/dn_base_leak.cpp"
@ -13,9 +18,210 @@
#endif
#endif
#if DN_H_WITH_CORE
#include "dn_core.cpp"
#endif
DN_Core *g_dn_;
DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_InitArgs *args)
{
g_dn_ = dn;
dn->init_flags = flags;
if (DN_BitIsSet(flags, DN_InitFlags_OS)) {
#if DN_H_WITH_OS
DN_OSCore *os = &dn->os;
dn->os_init = true;
DN_OS_SetLogPrintFuncToOS(os);
// NOTE: Query OS information
{
#if defined(DN_PLATFORM_WIN32)
SYSTEM_INFO system_info = {};
GetSystemInfo(&system_info);
os->logical_processor_count = system_info.dwNumberOfProcessors;
os->page_size = system_info.dwPageSize;
os->alloc_granularity = system_info.dwAllocationGranularity;
#else
#if defined(DN_PLATFORM_EMSCRIPTEN)
os->logical_processor_count = 1;
#else
os->logical_processor_count = get_nprocs();
#endif
os->page_size = getpagesize();
os->alloc_granularity = os->page_size;
#endif
}
{
#if defined(DN_PLATFORM_EMSCRIPTEN)
os->arena = DN_ArenaFromHeap(DN_Megabytes(1), DN_ArenaFlags_NoAllocTrack);
#else
os->arena = DN_ArenaFromVMem(DN_Megabytes(1), DN_Kilobytes(4), DN_ArenaFlags_NoAllocTrack);
#endif
#if defined(DN_PLATFORM_WIN32)
os->platform_context = DN_ArenaNew(&os->arena, DN_OSW32Core, DN_ZMem_Yes);
#elif defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_EMSCRIPTEN)
os->platform_context = DN_ArenaNew(&os->arena, DN_OSPOSIXCore, DN_ZMem_Yes);
#endif
#if defined(DN_PLATFORM_WIN32)
DN_OSW32Core *w32 = DN_Cast(DN_OSW32Core *) os->platform_context;
InitializeCriticalSection(&w32->sync_primitive_free_list_mutex);
QueryPerformanceFrequency(&w32->qpc_frequency);
HMODULE module = LoadLibraryA("kernel32.dll");
if (module) {
w32->set_thread_description = DN_Cast(DN_OSW32SetThreadDescriptionFunc *) GetProcAddress(module, "SetThreadDescription");
FreeLibrary(module);
}
// NOTE: win32 bcrypt
wchar_t const BCRYPT_ALGORITHM[] = L"RNG";
long /*NTSTATUS*/ init_status = BCryptOpenAlgorithmProvider(&w32->bcrypt_rng_handle, BCRYPT_ALGORITHM, nullptr /*implementation*/, 0 /*flags*/);
if (w32->bcrypt_rng_handle && init_status == 0)
w32->bcrypt_init_success = true;
else
DN_LogErrorF("Failed to initialise Windows secure random number generator, error: %d", init_status);
#else
DN_OS_PosixInit(DN_Cast(DN_OSPosixCore *)os->platform_context);
#endif
}
os->cpu_report = DN_CPUGetReport();
#define DN_CPU_FEAT_XENTRY(label) g_dn_cpu_feature_decl[DN_CPUFeature_##label] = {DN_CPUFeature_##label, DN_Str8Lit(#label)};
DN_CPU_FEAT_XMACRO
#undef DN_CPU_FEAT_XENTRY
DN_Assert(g_dn_);
#endif
}
if (DN_BitIsSet(flags, DN_InitFlags_LeakTracker)) {
DN_Assert(dn->os_init);
#if DN_H_WITH_OS
// NOTE: Setup the allocation table with allocation tracking turned off on
// the arena we're using to initialise the table.
dn->leak.alloc_table_arena = DN_ArenaFromVMem(DN_Megabytes(1), DN_Kilobytes(512), DN_ArenaFlags_NoAllocTrack | DN_ArenaFlags_AllocCanLeak);
dn->leak.alloc_table = DN_DSMapInit<DN_LeakAlloc>(&dn->leak.alloc_table_arena, 4096, DN_DSMapFlags_Nil);
#endif
}
if (DN_BitIsSet(flags, DN_InitFlags_ThreadContext)) {
DN_Assert(dn->os_init);
#if DN_H_WITH_OS
DN_TCInitArgs *tc_init_args = args ? &args->thread_context_init_args : nullptr;
DN_TCInitFromMemFuncs(&dn->main_tc, DN_OS_ThreadID(), tc_init_args, DN_ArenaMemFuncsGetDefaults());
DN_TCEquip(&dn->main_tc);
#endif
}
// NOTE: Print out init features
char buf[4096];
DN_USize buf_size = 0;
if (DN_BitIsSet(flags, DN_InitFlags_LogLibFeatures)) {
DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), "DN initialised:\n");
#if DN_H_WITH_OS
DN_F32 page_size_kib = dn->os.page_size / 1024.0f;
DN_F32 alloc_granularity_kib = dn->os.alloc_granularity / 1024.0f;
DN_FmtAppendTruncate(buf,
&buf_size,
sizeof(buf),
DN_Str8Lit("..."),
" OS Page/Granularity/Cores: %.0fKiB/%.0fKiB/%u\n",
page_size_kib,
alloc_granularity_kib,
dn->os.logical_processor_count);
#endif
DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " Thread Context: ");
if (DN_BitIsSet(flags, DN_InitFlags_ThreadContext)) {
DN_Arena *arena = dn->main_tc.main_arena;
DN_Str8 mem_funcs = DN_Str8Lit("");
switch (arena->mem_funcs.type) {
case DN_ArenaMemFuncType_Nil: break;
case DN_ArenaMemFuncType_Basic: mem_funcs = DN_Str8Lit("Basic"); break;
case DN_ArenaMemFuncType_VMem: mem_funcs = DN_Str8Lit("VMem"); break;
}
DN_Str8x32 main_commit = DN_ByteCountStr8x32(dn->main_tc.main_arena->curr->commit);
DN_Str8x32 main_reserve = DN_ByteCountStr8x32(dn->main_tc.main_arena->curr->reserve);
DN_Str8x32 temp_commit = DN_ByteCountStr8x32(dn->main_tc.temp_a_arena->curr->commit);
DN_Str8x32 temp_reserve = DN_ByteCountStr8x32(dn->main_tc.temp_a_arena->curr->reserve);
DN_Str8x32 err_commit = DN_ByteCountStr8x32(dn->main_tc.err_sink.arena->curr->commit);
DN_Str8x32 err_reserve = DN_ByteCountStr8x32(dn->main_tc.err_sink.arena->curr->reserve);
DN_FmtAppendTruncate(buf,
&buf_size,
sizeof(buf),
DN_Str8Lit("..."),
"M %.*s/%.*s S(x2) %.*s/%.*s E %.*s/%.*s (%.*s)\n",
DN_Str8PrintFmt(main_commit),
DN_Str8PrintFmt(main_reserve),
DN_Str8PrintFmt(temp_commit),
DN_Str8PrintFmt(temp_reserve),
DN_Str8PrintFmt(err_commit),
DN_Str8PrintFmt(err_reserve),
DN_Str8PrintFmt(mem_funcs));
} else {
DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), "N/A\n");
}
#if DN_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
if (DN_ASAN_POISON) {
DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " ASAN manual poisoning%s\n", DN_ASAN_VET_POISON ? " (+vet sanity checks)" : "");
DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " ASAN poison guard size: %u\n", DN_ASAN_POISON_GUARD_SIZE);
}
#endif
#if defined(DN_LEAK_TRACKING)
DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " Allocation leak tracing\n");
#endif
#if defined(DN_PLATFORM_EMSCRIPTEN) || defined(DN_PLATFORM_POSIX)
DN_OSPosixCore *posix = DN_Cast(DN_OSPosixCore *)g_dn_->os.platform_context;
DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " Clock GetTime: %S\n", posix->clock_monotonic_raw ? DN_Str8Lit("CLOCK_MONOTONIC_RAW") : DN_Str8Lit("CLOCK_MONOTONIC"));
#endif
// TODO(doyle): Add stacktrace feature log
}
if (DN_BitIsSet(flags, DN_InitFlags_LogCPUFeatures)) {
DN_Assert(dn->os_init);
#if DN_H_WITH_OS
DN_CPUReport const *report = &dn->os.cpu_report;
DN_Str8 brand = DN_Str8TrimWhitespaceAround(DN_Str8FromPtr(report->brand, sizeof(report->brand) - 1));
DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " CPU '%.*s' from '%s' detected:\n", DN_Str8PrintFmt(brand), report->vendor);
DN_USize longest_feature_name = 0;
for (DN_ForIndexU(feature_index, DN_CPUFeature_Count)) {
DN_CPUFeatureDecl feature_decl = g_dn_cpu_feature_decl[feature_index];
longest_feature_name = DN_Max(longest_feature_name, feature_decl.label.size);
}
for (DN_ForIndexU(feature_index, DN_CPUFeature_Count)) {
DN_CPUFeatureDecl feature_decl = g_dn_cpu_feature_decl[feature_index];
bool has_feature = DN_CPUHasFeature(report, feature_decl.value);
DN_FmtAppendTruncate(buf,
&buf_size,
sizeof(buf),
DN_Str8Lit("..."),
" %.*s:%*s%s\n",
DN_Str8PrintFmt(feature_decl.label),
DN_Cast(int)(longest_feature_name - feature_decl.label.size),
"",
has_feature ? "available" : "not available");
}
#endif
}
if (buf_size)
DN_LogDebugF("%.*s", DN_Cast(int)buf_size, buf);
}
DN_API void DN_BeginFrame()
{
#if DN_H_WITH_OS
DN_AtomicSetValue64(&g_dn_->os.mem_allocs_frame, 0);
#endif
}
#if DN_H_WITH_MATH
#include "Extra/dn_math.cpp"

View File

@ -1,10 +1,16 @@
#if !defined(DN_H)
#define DN_H
// NOTE: DN configuration
// Enabling DN modules
// By including this mega header 'dn.h' you must define the following symbols to 0 or 1 in order
// to include the module's implementation into the library as follows
// NOTE: DN
// Getting Started
// Include this mega header `dn.h` and define the following symbols to `1` to conditionally
// enable the interfaces for those features. Additionally in the same or different translation
// unit, include `dn.cpp` with the same symbols defined to enable the implementation of these
// features.
//
// See the configuration section for more information on other symbols that can be defined.
//
// The following is a single translation unit example:
/*
#define DN_H_WITH_OS 1
#define DN_H_WITH_CORE 1
@ -18,52 +24,65 @@
#define DN_CPP_WITH_DEMO 1
#include "dn.cpp"
*/
// Platform Target
// Define one of the following directives to configure this library to compile for that platform.
// By default, the library will auto-detect the current host platform and select that as the
// target platform.
// Then initialise the library at runtime by calling DN_Init(...). The library is laid out as:
//
// DN_PLATFORM_EMSCRIPTEN
// DN_PLATFORM_POSIX
// DN_PLATFORM_WIN32
// - The base layer (dn_base.h) which provides primitives that do not require a host operating
// system (e.g. freestanding) such as string manipulation, compiler intrinsics and containers.
// This layer is unconditionallly always available by compiling with this library.
//
// For example
// - The OS layer (dn_os.h) which provides primitives that use the OS such as file IO, threading
// synchronisation, memory allocation. This layer is OPTIONAL.
//
// #define DN_PLATFORM_WIN32
// - Extra layer provides helper utilities that are opt-in. These layers are OPTIONAL.
//
// Will ensure that <Windows.h> is included and the OS layer is implemented using Win32
// primitives.
// Configuration
// Platform Target
// Define one of the following directives to configure this library to compile for that
// platform. By default, the library will auto-detect the current host platform and select that
// as the target platform.
//
// Static functions
// All public functions in the DN library are prefixed with the macro '#define DN_API'. By
// default 'DN_API' is not defined to anything. Define
// DN_PLATFORM_EMSCRIPTEN
// DN_PLATFORM_POSIX
// DN_PLATFORM_WIN32
//
// DN_STATIC_API
// For example
//
// To replace all the prefixed with 'static' ensuring that the functions in the library do not
// export an entry into the linking table and thereby optimise compilation times as the linker
// will not try to resolve symbols from other translation units from the the unit including the
// DN library.
// #define DN_PLATFORM_WIN32
//
// Using the in-built replacement header for <Windows.h> (requires dn_os_inc.h)
// If you are building DN for the Windows platform, <Windows.h> is a large legacy header that
// applications have to link to use Windows syscalls. By default DN library uses a replacement
// header for all the Windows functions that it uses in the OS layer removing the need to include
// <Windows.h> to improve compilation times. This can be disabled by defining:
// Will ensure that <Windows.h> is included and the OS layer is implemented using Win32
// primitives.
//
// DN_NO_WINDOWS_H_REPLACEMENT_HEADER
// Static functions
// All public functions in the DN library are prefixed with the macro '#define DN_API'. By
// default 'DN_API' is not defined to anything. Define
//
// To instead use <Windows.h>. DN automatically detects if <Windows.h> is included in an earlier
// translation unit and will automatically disable the in-built replacement header in which case
// this does not need to be defined.
// DN_STATIC_API
//
// Freestanding
// The base layer can be used without an OS implementation by defining DN_FREESTANDING like:
// To replace all the functions prefixed with DN_API to be prefixed with 'static' ensuring that
// the functions in the library do not export an entry into the linking table.
// translation units.
//
// #define DN_FREESTANDING
// Disabling the in-built <Windows.h> (if #define DN_H_WITH_OS 1)
// If you are building DN for the Windows platform, <Windows.h> is a large legacy header that
// applications have to include to use Windows APIs. By default this library uses a replacement
// header for all the Windows functions that it uses in the OS layer removing the need to
// include <Windows.h> to improve compilation times. This mini header will conflict with
// <Windows.h> if it needs to be included in your project. The mini header can be disabled by
// defining:
//
// This means functionality that relies on the OS like printing, memory allocation, stack traces
// and so forth are disabled.
// DN_NO_WINDOWS_H_REPLACEMENT_HEADER
//
// To instead use <Windows.h>. DN automatically detects if <Windows.h> is included in an earlier
// translation unit and will automatically disable the in-built replacement header in which case
// this does not need to be defined.
//
// Freestanding
// The base layer can be used without an OS implementation by defining DN_FREESTANDING like:
//
// #define DN_FREESTANDING
//
// This means functionality that relies on the OS like printing, memory allocation, stack traces
// and so forth are disabled.
#include "Base/dn_base.h"
#include "Base/dn_base_assert.h"
@ -83,9 +102,43 @@
#include "OS/dn_os.h"
#endif
#if DN_H_WITH_CORE
#include "dn_core.h"
#endif
struct DN_InitArgs
{
DN_TCInitArgs thread_context_init_args;
};
typedef DN_USize DN_InitFlags;
enum DN_InitFlags_
{
DN_InitFlags_Nil = 0,
DN_InitFlags_OS = (1 << 0),
DN_InitFlags_LeakTracker = (1 << 1) | DN_InitFlags_OS,
DN_InitFlags_LogLibFeatures = (1 << 2),
DN_InitFlags_LogCPUFeatures = (1 << 3) | DN_InitFlags_OS,
DN_InitFlags_ThreadContext = (1 << 4) | DN_InitFlags_OS,
DN_InitFlags_LogAllFeatures = DN_InitFlags_LogLibFeatures | DN_InitFlags_LogCPUFeatures,
};
struct DN_Core
{
DN_InitFlags init_flags;
DN_TCCore main_tc;
DN_USize mem_allocs_frame;
DN_LeakTracker leak;
DN_LogPrintFunc* print_func;
void* print_func_context;
bool os_init;
#if defined(DN_OS_H)
DN_OSCore os;
#endif
};
extern DN_Core *g_dn_;
DN_API void DN_Init (DN_Core *dn, DN_InitFlags flags, DN_InitArgs *args);
DN_API void DN_BeginFrame();
#if DN_H_WITH_MATH
#include "Extra/dn_math.h"

View File

@ -1,171 +0,0 @@
#define DN_INC_CPP
#if defined(_CLANGD)
#include "../Base/dn_base.h"
#include "../OS/dn_os.h"
#endif
DN_Core *g_dn_;
static void DN_InitOS_(DN_OSCore *os)
{
#if defined(DN_OS_H) && defined(DN_OS_CPP)
// NOTE: OS
{
#if defined(DN_PLATFORM_WIN32)
SYSTEM_INFO system_info = {};
GetSystemInfo(&system_info);
os->logical_processor_count = system_info.dwNumberOfProcessors;
os->page_size = system_info.dwPageSize;
os->alloc_granularity = system_info.dwAllocationGranularity;
#else
#if defined(DN_PLATFORM_EMSCRIPTEN)
os->logical_processor_count = 1;
#else
os->logical_processor_count = get_nprocs();
#endif
os->page_size = getpagesize();
os->alloc_granularity = os->page_size;
#endif
}
// NOTE: Setup logging
DN_OS_EmitLogsWithOSPrintFunctions(os);
{
#if defined(DN_PLATFORM_EMSCRIPTEN)
os->arena = DN_ArenaFromHeap(DN_Megabytes(1), DN_ArenaFlags_NoAllocTrack);
#else
os->arena = DN_ArenaFromVMem(DN_Megabytes(1), DN_Kilobytes(4), DN_ArenaFlags_NoAllocTrack);
#endif
#if defined(DN_PLATFORM_WIN32)
os->platform_context = DN_ArenaNew(&os->arena, DN_OSW32Core, DN_ZMem_Yes);
#elif defined(DN_PLATFORM_POSIX) || defined(DN_PLATFORM_EMSCRIPTEN)
os->platform_context = DN_ArenaNew(&os->arena, DN_OSPOSIXCore, DN_ZMem_Yes);
#endif
#if defined(DN_PLATFORM_WIN32)
DN_OSW32Core *w32 = DN_Cast(DN_OSW32Core *) os->platform_context;
InitializeCriticalSection(&w32->sync_primitive_free_list_mutex);
QueryPerformanceFrequency(&w32->qpc_frequency);
HMODULE module = LoadLibraryA("kernel32.dll");
if (module) {
w32->set_thread_description = DN_Cast(DN_OSW32SetThreadDescriptionFunc *) GetProcAddress(module, "SetThreadDescription");
FreeLibrary(module);
}
// NOTE: win32 bcrypt
wchar_t const BCRYPT_ALGORITHM[] = L"RNG";
long /*NTSTATUS*/ init_status = BCryptOpenAlgorithmProvider(&w32->bcrypt_rng_handle, BCRYPT_ALGORITHM, nullptr /*implementation*/, 0 /*flags*/);
if (w32->bcrypt_rng_handle && init_status == 0)
w32->bcrypt_init_success = true;
else
DN_LogErrorF("Failed to initialise Windows secure random number generator, error: %d", init_status);
#else
DN_OS_PosixInit(DN_Cast(DN_OSPosixCore *)os->platform_context);
#endif
}
os->cpu_report = DN_CPUGetReport();
#define DN_CPU_FEAT_XENTRY(label) g_dn_cpu_feature_decl[DN_CPUFeature_##label] = {DN_CPUFeature_##label, DN_Str8Lit(#label)};
DN_CPU_FEAT_XMACRO
#undef DN_CPU_FEAT_XENTRY
DN_Assert(g_dn_);
#endif // defined(DN_OS_H) && defined(DN_OS_CPP)
}
DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags)
{
g_dn_ = dn;
dn->init_flags = flags;
if (flags & DN_InitFlags_OS) {
#if defined(DN_OS_H) && defined(DN_OS_CPP)
DN_InitOS_(&dn->os);
if (flags & DN_InitFlags_OSLeakTracker) {
// NOTE: Setup the allocation table with allocation tracking turned off on
// the arena we're using to initialise the table.
dn->leak.alloc_table_arena = DN_ArenaFromVMem(DN_Megabytes(1), DN_Kilobytes(512), DN_ArenaFlags_NoAllocTrack | DN_ArenaFlags_AllocCanLeak);
dn->leak.alloc_table = DN_DSMapInit<DN_LeakAlloc>(&dn->leak.alloc_table_arena, 4096, DN_DSMapFlags_Nil);
}
#endif
}
// NOTE: Print out init features
char buf[4096];
DN_USize buf_size = 0;
if (flags & DN_InitFlags_LogLibFeatures) {
DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), "DN initialised:\n");
#if defined(DN_OS_CPP)
DN_F32 page_size_kib = dn->os.page_size / 1024.0f;
DN_F32 alloc_granularity_kib = dn->os.alloc_granularity / 1024.0f;
DN_FmtAppendTruncate(buf,
&buf_size,
sizeof(buf),
DN_Str8Lit("..."),
" OS Page Size/Alloc Granularity: %.1f/%.1fKiB\n"
" Logical Processor Count: %u\n",
page_size_kib,
alloc_granularity_kib,
dn->os.logical_processor_count);
#endif
#if DN_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__)
if (DN_ASAN_POISON) {
DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " ASAN manual poisoning%s\n", DN_ASAN_VET_POISON ? " (+vet sanity checks)" : "");
DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " ASAN poison guard size: %u\n", DN_ASAN_POISON_GUARD_SIZE);
}
#endif
#if defined(DN_LEAK_TRACKING)
DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " Allocation leak tracing\n");
#endif
#if defined(DN_PLATFORM_EMSCRIPTEN) || defined(DN_PLATFORM_POSIX)
DN_OSPosixCore *posix = DN_Cast(DN_OSPosixCore *)g_dn_->os.platform_context;
DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " Clock GetTime: %S\n", posix->clock_monotonic_raw ? DN_Str8Lit("CLOCK_MONOTONIC_RAW") : DN_Str8Lit("CLOCK_MONOTONIC"));
#endif
// TODO(doyle): Add stacktrace feature log
}
if (flags & DN_InitFlags_LogCPUFeatures) {
DN_CPUReport const *report = &dn->os.cpu_report;
DN_Str8 brand = DN_Str8TrimWhitespaceAround(DN_Str8FromPtr(report->brand, sizeof(report->brand) - 1));
DN_MSVC_WARNING_PUSH
DN_MSVC_WARNING_DISABLE(6284) // Object passed as _Param_(3) when a string is required in call to 'DN_Str8BuilderAppendF' Actual type: 'struct DN_Str8'.
DN_FmtAppendTruncate(buf, &buf_size, sizeof(buf), DN_Str8Lit("..."), " CPU '%S' from '%s' detected:\n", brand, report->vendor);
DN_MSVC_WARNING_POP
DN_USize longest_feature_name = 0;
for (DN_ForIndexU(feature_index, DN_CPUFeature_Count)) {
DN_CPUFeatureDecl feature_decl = g_dn_cpu_feature_decl[feature_index];
longest_feature_name = DN_Max(longest_feature_name, feature_decl.label.size);
}
for (DN_ForIndexU(feature_index, DN_CPUFeature_Count)) {
DN_CPUFeatureDecl feature_decl = g_dn_cpu_feature_decl[feature_index];
bool has_feature = DN_CPUHasFeature(report, feature_decl.value);
DN_FmtAppendTruncate(buf,
&buf_size,
sizeof(buf),
DN_Str8Lit("..."),
" %.*s:%*s%s\n",
DN_Str8PrintFmt(feature_decl.label),
DN_Cast(int)(longest_feature_name - feature_decl.label.size),
"",
has_feature ? "available" : "not available");
}
}
if (buf_size)
DN_LogDebugF("%.*s", DN_Cast(int)buf_size, buf);
}
DN_API void DN_BeginFrame()
{
DN_AtomicSetValue64(&g_dn_->os.mem_allocs_frame, 0);
}

View File

@ -1,44 +0,0 @@
#if !defined(DN_INC_H)
#define DN_INC_H
#if defined(_CLANGD)
#define DN_H_WITH_OS 1
#include "dn.h"
#endif
struct DN_InitArgs
{
DN_U64 os_tls_reserve;
DN_U64 os_tls_commit;
DN_U64 os_tls_err_sink_reserve;
DN_U64 os_tls_err_sink_commit;
};
typedef DN_USize DN_InitFlags;
enum DN_InitFlags_
{
DN_InitFlags_Nil = 0,
DN_InitFlags_OS = 1 << 0,
DN_InitFlags_OSLeakTracker = 1 << 1,
DN_InitFlags_LogLibFeatures = 1 << 2,
DN_InitFlags_LogCPUFeatures = 1 << 3,
DN_InitFlags_LogAllFeatures = DN_InitFlags_LogLibFeatures | DN_InitFlags_LogCPUFeatures,
};
struct DN_Core
{
DN_InitFlags init_flags;
DN_USize mem_allocs_frame;
DN_LeakTracker leak;
#if defined(DN_OS_H)
DN_OSCore os;
#endif
};
extern DN_Core *g_dn_;
DN_API void DN_Init(DN_Core *dn, DN_InitFlags flags, DN_InitArgs *args);
DN_API void DN_ThreadContextInit();
DN_API void DN_BeginFrame();
#endif // !defined(DN_INC_H)