From dbbaa5fbf7f6b07faa812600e054c25dc7e919bc Mon Sep 17 00:00:00 2001 From: doylet Date: Sun, 8 Mar 2026 12:18:23 +1100 Subject: [PATCH] More cleanup --- Source/Base/dn_base.cpp | 33 ++++-- Source/Base/dn_base.h | 26 +++-- Source/Extra/dn_async.cpp | 2 +- Source/Extra/dn_net_curl.cpp | 2 +- Source/OS/dn_os.cpp | 130 ++++++--------------- Source/OS/dn_os.h | 41 +++---- Source/OS/dn_os_posix.cpp | 24 ++-- Source/OS/dn_os_w32.cpp | 29 +++-- Source/dn.cpp | 212 ++++++++++++++++++++++++++++++++++- Source/dn.h | 133 +++++++++++++++------- Source/dn_core.cpp | 171 ---------------------------- Source/dn_core.h | 44 -------- 12 files changed, 432 insertions(+), 415 deletions(-) delete mode 100644 Source/dn_core.cpp delete mode 100644 Source/dn_core.h diff --git a/Source/Base/dn_base.cpp b/Source/Base/dn_base.cpp index eb14d1b..280b7d0 100644 --- a/Source/Base/dn_base.cpp +++ b/Source/Base/dn_base.cpp @@ -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); } } diff --git a/Source/Base/dn_base.h b/Source/Base/dn_base.h index bbfa83c..2b26742 100644 --- a/Source/Base/dn_base.h +++ b/Source/Base/dn_base.h @@ -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) diff --git a/Source/Extra/dn_async.cpp b/Source/Extra/dn_async.cpp index c85098a..7a8c0e0 100644 --- a/Source/Extra/dn_async.cpp +++ b/Source/Extra/dn_async.cpp @@ -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) { diff --git a/Source/Extra/dn_net_curl.cpp b/Source/Extra/dn_net_curl.cpp index e94db2d..ecfff85 100644 --- a/Source/Extra/dn_net_curl.cpp +++ b/Source/Extra/dn_net_curl.cpp @@ -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) diff --git a/Source/OS/dn_os.cpp b/Source/OS/dn_os.cpp index 00f72c5..3ee385c 100644 --- a/Source/OS/dn_os.cpp +++ b/Source/OS/dn_os.cpp @@ -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 diff --git a/Source/OS/dn_os.h b/Source/OS/dn_os.h index 9957ded..fd197f1 100644 --- a/Source/OS/dn_os.h +++ b/Source/OS/dn_os.h @@ -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); diff --git a/Source/OS/dn_os_posix.cpp b/Source/OS/dn_os_posix.cpp index 3a44846..b9011cc 100644 --- a/Source/OS/dn_os_posix.cpp +++ b/Source/OS/dn_os_posix.cpp @@ -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() diff --git a/Source/OS/dn_os_w32.cpp b/Source/OS/dn_os_w32.cpp index 7611538..d9e8bdd 100644 --- a/Source/OS/dn_os_w32.cpp +++ b/Source/OS/dn_os_w32.cpp @@ -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() diff --git a/Source/dn.cpp b/Source/dn.cpp index b1c57b6..00cc26d 100644 --- a/Source/dn.cpp +++ b/Source/dn.cpp @@ -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->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" diff --git a/Source/dn.h b/Source/dn.h index d14742a..a3a2a39 100644 --- a/Source/dn.h +++ b/Source/dn.h @@ -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 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 (requires dn_os_inc.h) -// If you are building DN for the Windows platform, 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 -// to improve compilation times. This can be disabled by defining: +// Will ensure that 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 . DN automatically detects if 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 (if #define DN_H_WITH_OS 1) +// If you are building DN for the Windows platform, 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 to improve compilation times. This mini header will conflict with +// 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 . DN automatically detects if 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" diff --git a/Source/dn_core.cpp b/Source/dn_core.cpp deleted file mode 100644 index c88a6c0..0000000 --- a/Source/dn_core.cpp +++ /dev/null @@ -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->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); -} diff --git a/Source/dn_core.h b/Source/dn_core.h deleted file mode 100644 index c2f62d0..0000000 --- a/Source/dn_core.h +++ /dev/null @@ -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)