diff --git a/Misc/dqn_unit_tests.cpp b/Misc/dqn_unit_tests.cpp index bd60470..6d05782 100644 --- a/Misc/dqn_unit_tests.cpp +++ b/Misc/dqn_unit_tests.cpp @@ -15,7 +15,7 @@ #endif #define DQN_ASAN_POISON 1 - #define DQN_ASAN_VET_POISON + #define DQN_ASAN_VET_POISON 1 #define DQN_NO_CHECK_BREAK #define DQN_IMPLEMENTATION #include "dqn.h" diff --git a/build.bat b/build.bat index e43b7cc..0f9e9ab 100644 --- a/build.bat +++ b/build.bat @@ -16,7 +16,10 @@ pushd Build set common_flags=-D DQN_TEST_WITH_MAIN -I %script_dir% %script_dir%\Misc\dqn_unit_tests.cpp set msvc_driver_flags=%common_flags% -MT -EHa -GR- -Od -Oi -Z7 -wd4201 -W4 -WX -nologo - set msvc_compile_flags=%msvc_driver_flags% -fsanitize=address -analyze /Fe:dqn_unit_tests_msvc + + REM Optionally pass `-analyze` to `msvc_compile_flags` for more checks, but, + REM it slows down compilation by around 5s on my old laptop. + set msvc_compile_flags=%msvc_driver_flags% -fsanitize=address /Fe:dqn_unit_tests_msvc set clang_compile_flags=%msvc_driver_flags% -fsanitize=address -fsanitize=undefined /Fe:dqn_unit_tests_clang set zig_compile_flags=%common_flags% -fsanitize=address -fsanitize=undefined -o dqn_unit_tests_zig diff --git a/dqn.h b/dqn.h index fac8b1d..d204306 100644 --- a/dqn.h +++ b/dqn.h @@ -116,6 +116,7 @@ // [$TYPE] Types | | Basic types and typedefs // [$INTR] Intrinsics | | Atomics, cpuid, ticket mutex // [$TMUT] Dqn_TicketMutex | | Userland mutex via spinlocking atomics +// [$PRIN] Dqn_Print | | Console printing // NOTE: Additional Configuration // - Override the default heap-allocation routine that is called when the @@ -191,10 +192,6 @@ // [$ACAT] Dqn_ArenaCatalog | | Collate, create & manage arenas in a catalog #include "dqn_memory.h" -// NOTE: Dqn_Platform Print ======================================================================== -// [$PRIN] Dqn_Print | | Console printing -#include "dqn_platform_print.h" - // NOTE: Dqn_Debug ================================================================================= // [$DEBM] Debug Macros | | // [$CALL] Dqn_CallSite | | Source code location/tracing @@ -219,8 +216,10 @@ // // DQN_DUMP_STACK_TRACE // -// - Enable memory leak tracking when requesting memory from the OS via this -// library. For example calls to Dqn_VMem_Reserve or DQN_ALLOC are recorded. +// - Define this macro to enable emory leak tracking when requesting memory +// from the OS via this library. For example calls to Dqn_VMem_Reserve or +// DQN_ALLOC are recorded to the leak table. +// // Allocations are stored in a global hash-table and their respective stack // traces for the allocation location. Memory leaks can be dumped at the end // of the program or some epoch by calling Dqn_Library_DumpLeaks() @@ -239,13 +238,13 @@ // // DQN_ASAN_POISON 1 // -// - Define this macro to enable sanity checks for manually poisoned memory in +// - Define this macro 1 to enable sanity checks for manually poisoned memory in // this library when ASAN `-fsanitize=address` is enabled. These sanity checks // ensure that memory from arenas are correctly un/poisoned when pointers are // allocated and returned to the memory arena's. This is a no-op if we are not // compiled with ASAN or `DQN_ASAN_POISON` is not set to `1`. // -// DQN_ASAN_VET_POISON +// DQN_ASAN_VET_POISON 1 // // NOTE: Dqn_Strings =============================================================================== @@ -280,12 +279,6 @@ // and padded to atleast DQN_ASAN_POISON_ALIGNMENT (e.g. 8 bytes). // // DQN_ASAN_POISON 1 -// -// - Define this macro to record allocation stats for arenas used in the -// thread context. The thread context arena stats can be printed by using -// Dqn_Library_DumpThreadContextArenaStat. -// -// DQN_DEBUG_THREAD_CONTEXT #include "dqn_platform.h" @@ -319,7 +312,6 @@ #include "dqn_base.cpp" #include "dqn_external.cpp" #include "dqn_memory.cpp" -#include "dqn_platform_print.cpp" #include "dqn_debug.cpp" #include "dqn_strings.cpp" #include "dqn_containers.cpp" diff --git a/dqn_base.cpp b/dqn_base.cpp index 6d45c75..b6d4c4a 100644 --- a/dqn_base.cpp +++ b/dqn_base.cpp @@ -60,3 +60,195 @@ DQN_API bool Dqn_TicketMutex_CanLock(Dqn_TicketMutex const *mutex, Dqn_uint tick #undef _CRT_SECURE_NO_WARNINGS #endif #endif + +// NOTE: [$PRIN] Dqn_Print ========================================================================= +DQN_API Dqn_PrintStyle Dqn_Print_StyleColour(uint8_t r, uint8_t g, uint8_t b, Dqn_PrintBold bold) +{ + Dqn_PrintStyle result = {}; + result.bold = bold; + result.colour = true; + result.r = r; + result.g = g; + result.b = b; + return result; +} + +DQN_API Dqn_PrintStyle Dqn_Print_StyleColourU32(uint32_t rgb, Dqn_PrintBold bold) +{ + uint8_t r = (rgb >> 24) & 0xFF; + uint8_t g = (rgb >> 16) & 0xFF; + uint8_t b = (rgb >> 8) & 0xFF; + Dqn_PrintStyle result = Dqn_Print_StyleColour(r, g, b, bold); + return result; +} + +DQN_API Dqn_PrintStyle Dqn_Print_StyleBold() +{ + Dqn_PrintStyle result = {}; + result.bold = Dqn_PrintBold_Yes; + return result; +} + +DQN_API void Dqn_Print_Std(Dqn_PrintStd std_handle, Dqn_String8 string) +{ + DQN_ASSERT(std_handle == Dqn_PrintStd_Out || std_handle == Dqn_PrintStd_Err); + + #if defined(DQN_OS_WIN32) + // NOTE: Get the output handles from kernel ==================================================== + DQN_THREAD_LOCAL void *std_out_print_handle = nullptr; + DQN_THREAD_LOCAL void *std_err_print_handle = nullptr; + DQN_THREAD_LOCAL bool std_out_print_to_console = false; + DQN_THREAD_LOCAL bool std_err_print_to_console = false; + + if (!std_out_print_handle) { + unsigned long mode = 0; (void)mode; + std_out_print_handle = GetStdHandle(STD_OUTPUT_HANDLE); + std_out_print_to_console = GetConsoleMode(std_out_print_handle, &mode) != 0; + + std_err_print_handle = GetStdHandle(STD_ERROR_HANDLE); + std_err_print_to_console = GetConsoleMode(std_err_print_handle, &mode) != 0; + } + + // NOTE: Select the output handle ============================================================== + void *print_handle = std_out_print_handle; + bool print_to_console = std_out_print_to_console; + if (std_handle == Dqn_PrintStd_Err) { + print_handle = std_err_print_handle; + print_to_console = std_err_print_to_console; + } + + // NOTE: Write the string ====================================================================== + DQN_ASSERT(string.size < DQN_CAST(unsigned long)-1); + unsigned long bytes_written = 0; (void)bytes_written; + if (print_to_console) { + WriteConsoleA(print_handle, string.data, DQN_CAST(unsigned long)string.size, &bytes_written, nullptr); + } else { + WriteFile(print_handle, string.data, DQN_CAST(unsigned long)string.size, &bytes_written, nullptr); + } + #else + fprintf(std_handle == Dqn_PrintStd_Out ? stdout : stderr, "%.*s", DQN_STRING_FMT(string)); + #endif +} + +DQN_API void Dqn_Print_StdStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string) +{ + if (string.data && string.size) { + if (style.colour) + Dqn_Print_Std(std_handle, Dqn_Print_ESCColourFgString(style.r, style.g, style.b)); + if (style.bold == Dqn_PrintBold_Yes) + Dqn_Print_Std(std_handle, Dqn_Print_ESCBoldString); + Dqn_Print_Std(std_handle, string); + if (style.colour || style.bold == Dqn_PrintBold_Yes) + Dqn_Print_Std(std_handle, Dqn_Print_ESCResetString); + } +} + +DQN_FILE_SCOPE char *Dqn_Print_VSPrintfChunker_(const char *buf, void *user, int len) +{ + Dqn_String8 string = {}; + string.data = DQN_CAST(char *)buf; + string.size = len; + + Dqn_PrintStd std_handle = DQN_CAST(Dqn_PrintStd)DQN_CAST(uintptr_t)user; + Dqn_Print_Std(std_handle, string); + return (char *)buf; +} + +DQN_API void Dqn_Print_StdF(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + Dqn_Print_StdFV(std_handle, fmt, args); + va_end(args); +} + +DQN_API void Dqn_Print_StdFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + Dqn_Print_StdFVStyle(std_handle, style, fmt, args); + va_end(args); +} + +DQN_API void Dqn_Print_StdFV(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args) +{ + char buffer[STB_SPRINTF_MIN]; + STB_SPRINTF_DECORATE(vsprintfcb)(Dqn_Print_VSPrintfChunker_, DQN_CAST(void *)DQN_CAST(uintptr_t)std_handle, buffer, fmt, args); +} + +DQN_API void Dqn_Print_StdFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args) +{ + if (fmt) { + if (style.colour) + Dqn_Print_Std(std_handle, Dqn_Print_ESCColourFgString(style.r, style.g, style.b)); + if (style.bold == Dqn_PrintBold_Yes) + Dqn_Print_Std(std_handle, Dqn_Print_ESCBoldString); + Dqn_Print_StdFV(std_handle, fmt, args); + if (style.colour || style.bold == Dqn_PrintBold_Yes) + Dqn_Print_Std(std_handle, Dqn_Print_ESCResetString); + } +} + +DQN_API void Dqn_Print_StdLn(Dqn_PrintStd std_handle, Dqn_String8 string) +{ + Dqn_Print_Std(std_handle, string); + Dqn_Print_Std(std_handle, DQN_STRING8("\n")); +} + +DQN_API void Dqn_Print_StdLnF(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + Dqn_Print_StdLnFV(std_handle, fmt, args); + va_end(args); +} + +DQN_API void Dqn_Print_StdLnFV(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args) +{ + Dqn_Print_StdFV(std_handle, fmt, args); + Dqn_Print_Std(std_handle, DQN_STRING8("\n")); +} + +DQN_API void Dqn_Print_StdLnStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string) +{ + Dqn_Print_StdStyle(std_handle, style, string); + Dqn_Print_Std(std_handle, DQN_STRING8("\n")); +} + +DQN_API void Dqn_Print_StdLnFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + Dqn_Print_StdLnFVStyle(std_handle, style, fmt, args); + va_end(args); +} + +DQN_API void Dqn_Print_StdLnFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args) +{ + Dqn_Print_StdFVStyle(std_handle, style, fmt, args); + Dqn_Print_Std(std_handle, DQN_STRING8("\n")); +} + +DQN_API Dqn_String8 Dqn_Print_ESCColourString(Dqn_PrintESCColour colour, uint8_t r, uint8_t g, uint8_t b) +{ + DQN_THREAD_LOCAL char buffer[32]; + buffer[0] = 0; + Dqn_String8 result = {}; + result.size = STB_SPRINTF_DECORATE(snprintf)(buffer, + DQN_ARRAY_UCOUNT(buffer), + "\x1b[%d;2;%u;%u;%um", + colour == Dqn_PrintESCColour_Fg ? 38 : 48, + r, g, b); + result.data = buffer; + return result; +} + +DQN_API Dqn_String8 Dqn_Print_ESCColourU32String(Dqn_PrintESCColour colour, uint32_t value) +{ + uint8_t r = DQN_CAST(uint8_t)(value >> 24); + uint8_t g = DQN_CAST(uint8_t)(value >> 16); + uint8_t b = DQN_CAST(uint8_t)(value >> 8); + Dqn_String8 result = Dqn_Print_ESCColourString(colour, r, g, b); + return result; +} + diff --git a/dqn_base.h b/dqn_base.h index e12a7f8..51db4a5 100644 --- a/dqn_base.h +++ b/dqn_base.h @@ -290,24 +290,21 @@ typedef int32_t Dqn_b32; #define DQN_ISIZE_MAX INTPTR_MAX #define DQN_ISIZE_MIN INTPTR_MIN -typedef enum Dqn_ZeroMem +enum Dqn_ZeroMem { Dqn_ZeroMem_No, // Memory can be handed out without zero-ing it out Dqn_ZeroMem_Yes, // Memory should be zero-ed out before giving to the callee -} -Dqn_ZeroMem; +}; struct Dqn_String8 { - char *data; // The bytes of the string + char *data; // The bytes of the string Dqn_usize size; // The number of bytes in the string - #if defined(__cplusplus) char const *begin() const { return data; } char const *end () const { return data + size; } char *begin() { return data; } char *end () { return data + size; } - #endif }; // NOTE: [$INTR] Intrinsics ======================================================================== @@ -439,8 +436,8 @@ Dqn_CPUIDRegisters Dqn_CPUID(int function_id); struct Dqn_TicketMutex { - unsigned int volatile ticket; ///< The next ticket to give out to the thread taking the mutex - unsigned int volatile serving; ///< The ticket ID to block the mutex on until it is returned + unsigned int volatile ticket; // The next ticket to give out to the thread taking the mutex + unsigned int volatile serving; // The ticket ID to block the mutex on until it is returned }; void Dqn_TicketMutex_Begin (Dqn_TicketMutex *mutex); @@ -448,3 +445,105 @@ void Dqn_TicketMutex_End (Dqn_TicketMutex *mutex); Dqn_uint Dqn_TicketMutex_MakeTicket (Dqn_TicketMutex *mutex); void Dqn_TicketMutex_BeginTicket(Dqn_TicketMutex const *mutex, Dqn_uint ticket); bool Dqn_TicketMutex_CanLock (Dqn_TicketMutex const *mutex, Dqn_uint ticket); + +// NOTE: [$PRIN] Dqn_Print ========================================================================= +enum Dqn_PrintStd +{ + Dqn_PrintStd_Out, + Dqn_PrintStd_Err, +}; + +enum Dqn_PrintBold +{ + Dqn_PrintBold_No, + Dqn_PrintBold_Yes, +}; + +struct Dqn_PrintStyle +{ + Dqn_PrintBold bold; + bool colour; + uint8_t r, g, b; +}; + +enum Dqn_PrintESCColour +{ + Dqn_PrintESCColour_Fg, + Dqn_PrintESCColour_Bg, +}; + +// NOTE: Print Style =============================================================================== +DQN_API Dqn_PrintStyle Dqn_Print_StyleColour (uint8_t r, uint8_t g, uint8_t b, Dqn_PrintBold bold); +DQN_API Dqn_PrintStyle Dqn_Print_StyleColourU32 (uint32_t rgb, Dqn_PrintBold bold); +DQN_API Dqn_PrintStyle Dqn_Print_StyleBold (); + +// NOTE: Print Standard Out ======================================================================== +#define Dqn_Print(string) Dqn_Print_Std(Dqn_PrintStd_Out, string) +#define Dqn_Print_F(fmt, ...) Dqn_Print_StdF(Dqn_PrintStd_Out, fmt, ## __VA_ARGS__) +#define Dqn_Print_FV(fmt, args) Dqn_Print_StdFV(Dqn_PrintStd_Out, fmt, args) + +#define Dqn_Print_Style(style, string) Dqn_Print_StdStyle(Dqn_PrintStd_Out, style, string) +#define Dqn_Print_FStyle(style, fmt, ...) Dqn_Print_StdFStyle(Dqn_PrintStd_Out, style, fmt, ## __VA_ARGS__) +#define Dqn_Print_FVStyle(style, fmt, args, ...) Dqn_Print_StdFVStyle(Dqn_PrintStd_Out, style, fmt, args) + +#define Dqn_Print_Ln(string) Dqn_Print_StdLn(Dqn_PrintStd_Out, string) +#define Dqn_Print_LnF(fmt, ...) Dqn_Print_StdLnF(Dqn_PrintStd_Out, fmt, ## __VA_ARGS__) +#define Dqn_Print_LnFV(fmt, args) Dqn_Print_StdLnFV(Dqn_PrintStd_Out, fmt, args) + +#define Dqn_Print_LnStyle(style, string) Dqn_Print_StdLnStyle(Dqn_PrintStd_Out, style, string); +#define Dqn_Print_LnFStyle(style, fmt, ...) Dqn_Print_StdLnFStyle(Dqn_PrintStd_Out, style, fmt, ## __VA_ARGS__); +#define Dqn_Print_LnFVStyle(style, fmt, args) Dqn_Print_StdLnFVStyle(Dqn_PrintStd_Out, style, fmt, args); + +#define Dqn_Print_Err(string) Dqn_Print_Std(Dqn_PrintStd_Err, string) +#define Dqn_Print_ErrF(fmt, ...) Dqn_Print_StdF(Dqn_PrintStd_Err, fmt, ## __VA_ARGS__) +#define Dqn_Print_ErrFV(fmt, args) Dqn_Print_StdFV(Dqn_PrintStd_Err, fmt, args) + +#define Dqn_Print_ErrStyle(style, string) Dqn_Print_StdStyle(Dqn_PrintStd_Err, style, string) +#define Dqn_Print_ErrFStyle(style, fmt, ...) Dqn_Print_StdFStyle(Dqn_PrintStd_Err, style, fmt, ## __VA_ARGS__) +#define Dqn_Print_ErrFVStyle(style, fmt, args, ...) Dqn_Print_StdFVStyle(Dqn_PrintStd_Err, style, fmt, args) + +#define Dqn_Print_ErrLn(string) Dqn_Print_StdLn(Dqn_PrintStd_Err, string) +#define Dqn_Print_ErrLnF(fmt, ...) Dqn_Print_StdLnF(Dqn_PrintStd_Err, fmt, ## __VA_ARGS__) +#define Dqn_Print_ErrLnFV(fmt, args) Dqn_Print_StdLnFV(Dqn_PrintStd_Err, fmt, args) + +#define Dqn_Print_ErrLnStyle(style, string) Dqn_Print_StdLnStyle(Dqn_PrintStd_Err, style, string); +#define Dqn_Print_ErrLnFStyle(style, fmt, ...) Dqn_Print_StdLnFStyle(Dqn_PrintStd_Err, style, fmt, ## __VA_ARGS__); +#define Dqn_Print_ErrLnFVStyle(style, fmt, args) Dqn_Print_StdLnFVStyle(Dqn_PrintStd_Err, style, fmt, args); + + +// NOTE: Print ===================================================================================== +DQN_API void Dqn_Print_Std (Dqn_PrintStd std_handle, Dqn_String8 string); +DQN_API void Dqn_Print_StdF (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...); +DQN_API void Dqn_Print_StdFV (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args); + +DQN_API void Dqn_Print_StdStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string); +DQN_API void Dqn_Print_StdFStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...); +DQN_API void Dqn_Print_StdFVStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args); + +DQN_API void Dqn_Print_StdLn (Dqn_PrintStd std_handle, Dqn_String8 string); +DQN_API void Dqn_Print_StdLnF (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...); +DQN_API void Dqn_Print_StdLnFV (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args); + +DQN_API void Dqn_Print_StdLnStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string); +DQN_API void Dqn_Print_StdLnFStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...); +DQN_API void Dqn_Print_StdLnFVStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args); + +// NOTE: ANSI Formatting Codes ===================================================================== +Dqn_String8 Dqn_Print_ESCColourString (Dqn_PrintESCColour colour, uint8_t r, uint8_t g, uint8_t b); +Dqn_String8 Dqn_Print_ESCColourU32String(Dqn_PrintESCColour colour, uint32_t value); + +#define Dqn_Print_ESCColourFgString(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Fg, r, g, b) +#define Dqn_Print_ESCColourBgString(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Bg, r, g, b) +#define Dqn_Print_ESCColourFg(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Fg, r, g, b).data +#define Dqn_Print_ESCColourBg(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Bg, r, g, b).data + +#define Dqn_Print_ESCColourFgU32String(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Fg, value) +#define Dqn_Print_ESCColourBgU32String(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Bg, value) +#define Dqn_Print_ESCColourFgU32(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Fg, value).data +#define Dqn_Print_ESCColourBgU32(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Bg, value).data + +#define Dqn_Print_ESCReset "\x1b[0m" +#define Dqn_Print_ESCBold "\x1b[1m" +#define Dqn_Print_ESCResetString DQN_STRING8(Dqn_Print_ESCReset) +#define Dqn_Print_ESCBoldString DQN_STRING8(Dqn_Print_ESCBold) + diff --git a/dqn_debug.cpp b/dqn_debug.cpp index 792e4d6..88ab58b 100644 --- a/dqn_debug.cpp +++ b/dqn_debug.cpp @@ -1,3 +1,30 @@ +// NOTE: [$ASAN] Dqn_Asan ========================================================================== === +void Dqn_ASAN_PoisonMemoryRegion(void const volatile *ptr, Dqn_usize size) +{ + #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) + __asan_poison_memory_region(ptr, size); + if (DQN_ASAN_VET_POISON) { + DQN_HARD_ASSERT(__asan_address_is_poisoned(ptr)); + DQN_HARD_ASSERT(__asan_address_is_poisoned((char *)ptr + (size - 1))); + } + #else + (void)ptr; (void)size; + #endif +} + +void Dqn_ASAN_UnpoisonMemoryRegion(void const volatile *ptr, Dqn_usize size) +{ + #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) + __asan_unpoison_memory_region(ptr, size); + if (DQN_ASAN_VET_POISON) { + DQN_HARD_ASSERT(__asan_region_is_poisoned((void *)ptr, size) == 0); + } + #else + (void)ptr; (void)size; + #endif +} + +// NOTE: [$DEBG] Dqn_Debug ========================================================================= DQN_API Dqn_String8 Dqn_Debug_CleanStackTrace(Dqn_String8 stack_trace) { // NOTE: Remove the stacktrace's library invocations from the stack trace @@ -164,7 +191,7 @@ DQN_API void Dqn_Debug_DumpLeaks() Dqn_Log_WarningF("There were %I64u leaked allocations totalling %_$$I64u", leak_count, leaked_bytes); } } -#endif /// defined(DQN_LEAK_TRACING) +#endif // defined(DQN_LEAK_TRACING) // NOTE: [$LLOG] Dqn_Log ========================================================================== DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator, @@ -239,27 +266,23 @@ DQN_API Dqn_String8 Dqn_Log_MakeString(Dqn_Allocator allocator, DQN_FILE_SCOPE void Dqn_Log_FVDefault_(Dqn_String8 type, int log_type, void *user_data, Dqn_CallSite call_site, char const *fmt, va_list args) { + Dqn_Library *lib = g_dqn_library; (void)log_type; (void)user_data; // NOTE: Open log file for appending if requested ========================== - Dqn_TicketMutex_Begin(&g_dqn_library->log_file_mutex); - if (g_dqn_library->log_to_file && !g_dqn_library->log_file) { - Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); - #if (defined(DQN_OS_WIN32) && !defined(DQN_NO_WIN)) || !defined(DQN_OS_WIN32) - Dqn_String8 exe_dir = Dqn_OS_EXEDir(scratch.arena); - #else - Dqn_String8 exe_dir = DQN_STRING8("."); - #endif - Dqn_String8 log_file = Dqn_String8_InitF(scratch.allocator, "%.*s/dqn.log", DQN_STRING_FMT(exe_dir)); - fopen_s(DQN_CAST(FILE **)&g_dqn_library->log_file, log_file.data, "a"); + Dqn_TicketMutex_Begin(&lib->log_file_mutex); + if (lib->log_to_file && !lib->log_file.handle && lib->log_file.error_size == 0) { + Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); + Dqn_String8 log_path = Dqn_FsPath_ConvertF(scratch.arena, "%.*s/dqn.log", DQN_STRING_FMT(lib->exe_dir)); + lib->log_file = Dqn_Fs_OpenFile(log_path, Dqn_FsFileOpen_CreateAlways, Dqn_FsFileAccess_AppendOnly); } - Dqn_TicketMutex_End(&g_dqn_library->log_file_mutex); + Dqn_TicketMutex_End(&lib->log_file_mutex); // NOTE: Generate the log header =========================================== Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); Dqn_String8 log_line = Dqn_Log_MakeString(scratch.allocator, - !g_dqn_library->log_no_colour, + !lib->log_no_colour, type, log_type, call_site, @@ -269,11 +292,10 @@ DQN_FILE_SCOPE void Dqn_Log_FVDefault_(Dqn_String8 type, int log_type, void *use // NOTE: Print log ========================================================= Dqn_Print_StdLn(Dqn_PrintStd_Out, log_line); - Dqn_TicketMutex_Begin(&g_dqn_library->log_file_mutex); - if (g_dqn_library->log_to_file && g_dqn_library->log_file) { - fprintf(DQN_CAST(FILE *)g_dqn_library->log_file, "%.*s\n", DQN_STRING_FMT(log_line)); - } - Dqn_TicketMutex_End(&g_dqn_library->log_file_mutex); + Dqn_TicketMutex_Begin(&lib->log_file_mutex); + Dqn_Fs_WriteFile(&lib->log_file, log_line); + Dqn_Fs_WriteFile(&lib->log_file, DQN_STRING8("\n")); + Dqn_TicketMutex_End(&lib->log_file_mutex); } DQN_API void Dqn_Log_FVCallSite(Dqn_String8 type, Dqn_CallSite call_site, char const *fmt, va_list args) diff --git a/dqn_debug.h b/dqn_debug.h index 9925061..069258a 100644 --- a/dqn_debug.h +++ b/dqn_debug.h @@ -34,6 +34,10 @@ #define DQN_ASAN_POISON 0 #endif +#if !defined(DQN_ASAN_POISON_VET) + #define DQN_ASAN_POISON_VET 0 +#endif + #if !defined(DQN_ASAN_POISON_ALIGNMENT) #define DQN_ASAN_POISON_ALIGNMENT 8 #endif @@ -44,31 +48,14 @@ #define __has_feature(x) 0 #endif +// NOTE: [$ASAN] Dqn_Asan ========================================================================== === #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) #include - #if defined(DQN_ASAN_VET_POISON) - #define DQN_ASAN_POISON_MEMORY_REGION(ptr, size) \ - do { \ - __asan_poison_memory_region((ptr), (size)); \ - DQN_ASSERT(__asan_address_is_poisoned((ptr))); \ - DQN_ASSERT(__asan_address_is_poisoned((char *)(ptr) + ((size) - 1))); \ - DQN_ASSERT(!__asan_address_is_poisoned((char *)(ptr) + (size))); \ - } while (0) - - #define DQN_ASAN_UNPOISON_MEMORY_REGION(ptr, size) \ - do { \ - __asan_unpoison_memory_region((ptr), (size)); \ - DQN_ASSERT(__asan_region_is_poisoned((ptr), (size)) == 0); \ - } while (0) - #else - #define DQN_ASAN_POISON_MEMORY_REGION(ptr, size) __asan_poison_memory_region(ptr, size) - #define DQN_ASAN_UNPOISON_MEMORY_REGION(ptr, size) __asan_unpoison_memory_region(ptr, size) - #endif -#else - #define DQN_ASAN_POISON_MEMORY_REGION(ptr, size) (void)(ptr); (void)(size) - #define DQN_ASAN_UNPOISON_MEMORY_REGION(ptr, size) (void)(ptr); (void)(size) #endif +void Dqn_ASAN_PoisonMemoryRegion(void const volatile *ptr, Dqn_usize size); +void Dqn_ASAN_UnpoisonMemoryRegion(void const volatile *ptr, Dqn_usize size); + // NOTE: [$CALL] Dqn_CallSite ====================================================================== struct Dqn_CallSite { diff --git a/dqn_external.cpp b/dqn_external.cpp index bd1bf92..a410b99 100644 --- a/dqn_external.cpp +++ b/dqn_external.cpp @@ -141,6 +141,10 @@ static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uin return (stbsp__uint32)(sn - s); } + +#if defined(__clang__) + __attribute__((no_sanitize("undefined"))) +#endif STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) { static char hex[] = "0123456789abcdefxp"; diff --git a/dqn_helpers.cpp b/dqn_helpers.cpp index 906110a..a5272ea 100644 --- a/dqn_helpers.cpp +++ b/dqn_helpers.cpp @@ -794,24 +794,17 @@ DQN_API Dqn_Library *Dqn_Library_Init() g_dqn_library = &default_instance; } + // NOTE: Init check =========================================================================== + Dqn_Library *result = g_dqn_library; Dqn_TicketMutex_Begin(&result->lib_mutex); DQN_DEFER { Dqn_TicketMutex_End(&result->lib_mutex); }; if (result->lib_init) return result; - // ============================================================================================= + // NOTE: Query OS page size ==================================================================== - Dqn_ArenaCatalog_Init(&result->arena_catalog, &result->arena_catalog_backup_arena); - result->lib_init = true; - - #if !defined(DQN_NO_PROFILER) - result->profiler = &result->profiler_default_instance; - #endif - - // ============================================================================================= - - { // NOTE: Query OS page size + { SYSTEM_INFO system_info = {}; #if defined(DQN_OS_WIN32) GetSystemInfo(&system_info); @@ -824,7 +817,17 @@ DQN_API Dqn_Library *Dqn_Library_Init() #endif } - // ============================================================================================= + // NOTE Initialise fields ====================================================================== + + #if !defined(DQN_NO_PROFILER) + result->profiler = &result->profiler_default_instance; + #endif + + result->lib_init = true; + Dqn_ArenaCatalog_Init(&result->arena_catalog, &result->arena); + result->exe_dir = Dqn_OS_EXEDir(&result->arena); + + // NOTE: Leak tracing ========================================================================== #if defined(DQN_LEAK_TRACING) // NOTE: Initialise the allocation leak tracker { @@ -840,17 +843,23 @@ DQN_API Dqn_Library *Dqn_Library_Init() } #endif - // ============================================================================================ + // NOTE: Print out init features =============================================================== - Dqn_Log_DebugF("Dqn Library initialised with features\n"); + Dqn_Log_DebugF("Dqn Library initialised:\n"); + Dqn_Print_StdLnF(Dqn_PrintStd_Err, " OS Page Size/Alloc Granularity: %$$_I32u/%$$_I32u", result->os_page_size, result->os_alloc_granularity); if (DQN_ASAN_POISON) - Dqn_Print_StdLnF(Dqn_PrintStd_Err, " - ASAN manual poisoning"); + Dqn_Print_StdLnF(Dqn_PrintStd_Err, " ASAN manual poisoning%s", DQN_ASAN_VET_POISON ? " (+vet sanity checks)" : ""); - #if defined(DQN_ASAN_VET_POISON) - Dqn_Print_StdLnF(Dqn_PrintStd_Err, " - ASAN manual poisoning vetting"); + #if defined(DQN_LEAK_TRACING) + Dqn_Print_StdLnF(Dqn_PrintStd_Err, " Allocation leak tracing"); #endif + #if !defined(DQN_NO_PROFILER) + Dqn_Print_StdLnF(Dqn_PrintStd_Err, " TSC profiler available"); + #endif + + Dqn_Print_StdLnF(Dqn_PrintStd_Err, ""); return result; } @@ -874,14 +883,6 @@ DQN_API void Dqn_Library_SetLogCallback(Dqn_LogProc *proc, void *user_data) g_dqn_library->log_user_data = user_data; } -DQN_API void Dqn_Library_SetLogFile(FILE *file) -{ - Dqn_TicketMutex_Begin(&g_dqn_library->log_file_mutex); - g_dqn_library->log_file = file; - g_dqn_library->log_to_file = file ? true : false; - Dqn_TicketMutex_End(&g_dqn_library->log_file_mutex); -} - DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_String8 file_path) { #if defined(DQN_DEBUG_THREAD_CONTEXT) diff --git a/dqn_helpers.h b/dqn_helpers.h index e938c7e..57dd0fd 100644 --- a/dqn_helpers.h +++ b/dqn_helpers.h @@ -587,20 +587,20 @@ void Dqn_Profiler_SwapAnchorBuffer (uint32_t anchor_count); struct Dqn_Library { - bool lib_init; + bool lib_init; // True if the library has been initialised via `Dqn_Library_Init` Dqn_TicketMutex lib_mutex; + Dqn_String8 exe_dir; // The directory of the current executable - Dqn_LogProc *log_callback; ///< Set this pointer to override the logging routine - void * log_user_data; - bool log_to_file; ///< Output logs to file as well as standard out - void * log_file; ///< TODO(dqn): Hmmm, how should we do this... ? - Dqn_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 - - /// The backup arena to use if no arena is passed into Dqn_Library_Init - Dqn_Arena arena_catalog_backup_arena; + Dqn_Arena arena; Dqn_ArenaCatalog arena_catalog; + Dqn_LogProc *log_callback; // Set this pointer to override the logging routine + void * log_user_data; + bool log_to_file; // Output logs to file as well as standard out + Dqn_FsFile log_file; // TODO(dqn): Hmmm, how should we do this... ? + Dqn_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: Leak Tracing ========================================================================== bool allocs_are_allowed_to_leak; @@ -627,14 +627,6 @@ struct Dqn_Library uint32_t os_page_size; uint32_t os_alloc_granularity; - // NOTE: Thread Context ======================================================================== - - #if defined(DQN_DEBUG_THREAD_CONTEXT) - Dqn_TicketMutex thread_context_mutex; - Dqn_ArenaStat thread_context_arena_stats[256]; - uint8_t thread_context_arena_stats_count; - #endif - // NOTE: Profiler ============================================================================== #if !defined(DQN_NO_PROFILER) @@ -650,6 +642,5 @@ DQN_API void Dqn_Library_SetPointer (Dqn_Library *library DQN_API void Dqn_Library_SetProfiler (Dqn_Profiler *profiler); #endif DQN_API void Dqn_Library_SetLogCallback (Dqn_LogProc *proc, void *user_data); -DQN_API void Dqn_Library_SetLogFile (void *file); DQN_API void Dqn_Library_DumpThreadContextArenaStat(Dqn_String8 file_path); diff --git a/dqn_memory.cpp b/dqn_memory.cpp index 85aa910..8a82b3b 100644 --- a/dqn_memory.cpp +++ b/dqn_memory.cpp @@ -237,7 +237,7 @@ DQN_API Dqn_MemBlock *Dqn_MemBlock_Init(Dqn_usize reserve, Dqn_usize commit, uin DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result->size, DQN_ASAN_POISON_ALIGNMENT)); void *poison_ptr = DQN_CAST(void *)Dqn_AlignUpPowerOfTwo(DQN_CAST(char *)result + sizeof(Dqn_MemBlock), DQN_ASAN_POISON_ALIGNMENT); Dqn_usize bytes_to_poison = g_dqn_library->os_page_size + result->size; - DQN_ASAN_POISON_MEMORY_REGION(poison_ptr, bytes_to_poison); + Dqn_ASAN_PoisonMemoryRegion(poison_ptr, bytes_to_poison); } } return result; @@ -261,7 +261,7 @@ DQN_API void *Dqn_MemBlock_Alloc(Dqn_MemBlock *block, Dqn_usize size, uint8_t al DQN_ASSERT(Dqn_IsPowerOfTwoAligned(result, alignment)); if (DQN_ASAN_POISON) - DQN_ASAN_UNPOISON_MEMORY_REGION(result, size); + Dqn_ASAN_UnpoisonMemoryRegion(result, size); if (zero_mem == Dqn_ZeroMem_Yes) { Dqn_usize reused_bytes = DQN_MIN(block->commit - size_required.data_offset, size); @@ -285,7 +285,7 @@ DQN_API void Dqn_MemBlock_Free(Dqn_MemBlock *block) return; Dqn_usize release_size = block->size + Dqn_MemBlock_MetadataSize(); if (DQN_ASAN_POISON) - DQN_ASAN_UNPOISON_MEMORY_REGION(block, release_size); + Dqn_ASAN_UnpoisonMemoryRegion(block, release_size); Dqn_VMem_Release(block, release_size); } @@ -307,7 +307,7 @@ DQN_API void Dqn_MemBlock_PopTo(Dqn_MemBlock *block, Dqn_usize to) void *poison_ptr = DQN_CAST(char *)block->data + to; void *end_ptr = DQN_CAST(void *)Dqn_AlignUpPowerOfTwo((DQN_CAST(uintptr_t)block->data + block->used), DQN_ASAN_POISON_ALIGNMENT); uintptr_t bytes_to_poison = DQN_CAST(uintptr_t)end_ptr - DQN_CAST(uintptr_t)poison_ptr; - DQN_ASAN_POISON_MEMORY_REGION(poison_ptr, bytes_to_poison); + Dqn_ASAN_PoisonMemoryRegion(poison_ptr, bytes_to_poison); } block->used = to; } diff --git a/dqn_memory.h b/dqn_memory.h index 4259c2e..778e7f9 100644 --- a/dqn_memory.h +++ b/dqn_memory.h @@ -295,9 +295,6 @@ struct Dqn_ArenaTempMemoryScope ~Dqn_ArenaTempMemoryScope(); Dqn_ArenaTempMemory temp_memory; bool cancel = false; - #if defined(DQN_LEAK_TRACING) - Dqn_CallSite leak_site_; - #endif }; enum Dqn_ArenaCommit diff --git a/dqn_platform.cpp b/dqn_platform.cpp index 1d517c2..6319bb5 100644 --- a/dqn_platform.cpp +++ b/dqn_platform.cpp @@ -645,15 +645,15 @@ DQN_API Dqn_FsFile Dqn_Fs_OpenFile(Dqn_String8 path, Dqn_FsFileOpen open_mode, u return result; } -DQN_API bool Dqn_Fs_WriteFile(Dqn_FsFile *file, char const *buffer, Dqn_usize size) +DQN_API bool Dqn_Fs_WriteFileBuffer(Dqn_FsFile *file, void const *buffer, Dqn_usize size) { if (!file || !file->handle || !buffer || size <= 0 || file->error_size) return false; bool result = true; #if defined(DQN_OS_WIN32) - char const *end = buffer + size; - for (char const *ptr = buffer; result && ptr != end; ) { + char const *end = DQN_CAST(char *)buffer + size; + for (char const *ptr = DQN_CAST(char const *)buffer; result && ptr != end; ) { unsigned long write_size = DQN_CAST(unsigned long)DQN_MIN((unsigned long)-1, end - ptr); unsigned long bytes_written = 0; result = WriteFile(file->handle, ptr, write_size, &bytes_written, nullptr /*lpOverlapped*/) != 0; @@ -675,6 +675,32 @@ DQN_API bool Dqn_Fs_WriteFile(Dqn_FsFile *file, char const *buffer, Dqn_usize si return result; } +DQN_API bool Dqn_Fs_WriteFile(Dqn_FsFile *file, Dqn_String8 buffer) +{ + bool result = Dqn_Fs_WriteFileBuffer(file, buffer.data, buffer.size); + return result; +} + +DQN_API bool Dqn_Fs_WriteFileFV(Dqn_FsFile *file, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args) +{ + bool result = false; + if (!file || !fmt) + return result; + Dqn_ThreadScratch scratch = Dqn_Thread_GetScratch(nullptr); + Dqn_String8 buffer = Dqn_String8_InitFV(scratch.allocator, fmt, args); + result = Dqn_Fs_WriteFileBuffer(file, buffer.data, buffer.size); + return result; +} + +DQN_API bool Dqn_Fs_WriteFileF(Dqn_FsFile *file, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) +{ + va_list args; + va_start(args, fmt); + bool result = Dqn_Fs_WriteFileFV(file, fmt, args); + va_end(args); + return result; +} + DQN_API void Dqn_Fs_CloseFile(Dqn_FsFile *file) { if (!file || !file->handle || file->error_size) @@ -1902,17 +1928,14 @@ DQN_API uint64_t Dqn_OS_EstimateTSCPerSecond(uint64_t duration_ms_to_gauge_tsc_f // NOTE: [$TCTX] Dqn_ThreadContext ================================================================= Dqn_ThreadScratch::Dqn_ThreadScratch(Dqn_ThreadContext *context, uint8_t context_index) { - index = context_index; - allocator = context->temp_allocators[index]; - arena = context->temp_arenas[index]; + allocator = context->scratch_allocators[context_index]; + arena = context->scratch_arenas[context_index]; temp_memory = Dqn_Arena_BeginTempMemory(arena); + destructed = false; } Dqn_ThreadScratch::~Dqn_ThreadScratch() { - #if defined(DQN_DEBUG_THREAD_CONTEXT) - temp_arenas_stat[index] = arena->stats; - #endif DQN_ASSERT(destructed == false); Dqn_Arena_EndTempMemory(temp_memory, /*cancel*/ false); destructed = true; @@ -1933,27 +1956,19 @@ DQN_API Dqn_ThreadContext *Dqn_Thread_GetContext() { DQN_THREAD_LOCAL Dqn_ThreadContext result = {}; if (!result.init) { - result.init = true; + result.init = true; + Dqn_ArenaCatalog *catalog = &g_dqn_library->arena_catalog; DQN_ASSERTF(g_dqn_library->lib_init, "Library must be initialised by calling Dqn_Library_Init(nullptr)"); - // NOTE: Setup permanent arena - Dqn_ArenaCatalog *catalog = &g_dqn_library->arena_catalog; - result.allocator = Dqn_Arena_Allocator(result.arena); - result.arena = Dqn_ArenaCatalog_AllocF(catalog, - DQN_GIGABYTES(1) /*size*/, - DQN_KILOBYTES(64) /*commit*/, - "Thread %u Arena", - Dqn_Thread_GetID()); - - // NOTE: Setup temporary arenas - for (uint8_t index = 0; index < DQN_THREAD_CONTEXT_ARENAS; index++) { - result.temp_arenas[index] = Dqn_ArenaCatalog_AllocF(catalog, - DQN_GIGABYTES(1) /*size*/, - DQN_KILOBYTES(64) /*commit*/, - "Thread %u Temp Arena %u", - Dqn_Thread_GetID(), - index); - result.temp_allocators[index] = Dqn_Arena_Allocator(result.temp_arenas[index]); + // NOTE: Setup scratch arenas + for (uint8_t index = 0; index < DQN_ARRAY_UCOUNT(result.scratch_arenas); index++) { + result.scratch_arenas[index] = Dqn_ArenaCatalog_AllocF(catalog, + DQN_GIGABYTES(1) /*size*/, + DQN_KILOBYTES(64) /*commit*/, + "Thread %u Scratch Arena %u", + Dqn_Thread_GetID(), + index); + result.scratch_allocators[index] = Dqn_Arena_Allocator(result.scratch_arenas[index]); } } return &result; @@ -1963,11 +1978,10 @@ DQN_API Dqn_ThreadContext *Dqn_Thread_GetContext() // manually pass it in? DQN_API Dqn_ThreadScratch Dqn_Thread_GetScratch(void const *conflict_arena) { - static_assert(DQN_THREAD_CONTEXT_ARENAS < (uint8_t)-1, "We use UINT8_MAX as a sentinel value"); Dqn_ThreadContext *context = Dqn_Thread_GetContext(); uint8_t context_index = (uint8_t)-1; - for (uint8_t index = 0; index < DQN_THREAD_CONTEXT_ARENAS; index++) { - Dqn_Arena *arena = context->temp_arenas[index]; + for (uint8_t index = 0; index < DQN_ARRAY_UCOUNT(context->scratch_arenas); index++) { + Dqn_Arena *arena = context->scratch_arenas[index]; if (!conflict_arena || arena != conflict_arena) { context_index = index; break; @@ -1977,4 +1991,3 @@ DQN_API Dqn_ThreadScratch Dqn_Thread_GetScratch(void const *conflict_arena) DQN_ASSERT(context_index != (uint8_t)-1); return Dqn_ThreadScratch(context, context_index); } - diff --git a/dqn_platform.h b/dqn_platform.h index 97b9204..8fff68d 100644 --- a/dqn_platform.h +++ b/dqn_platform.h @@ -70,9 +70,9 @@ struct Dqn_FsFile enum Dqn_FsFileOpen { - Dqn_FsFileOpen_CreateAlways, ///< Create file if it does not exist, otherwise, zero out the file and open - Dqn_FsFileOpen_OpenIfExist, ///< Open file at path only if it exists - Dqn_FsFileOpen_OpenAlways, ///< Open file at path, create file if it does not exist + Dqn_FsFileOpen_CreateAlways, // Create file if it does not exist, otherwise, zero out the file and open + Dqn_FsFileOpen_OpenIfExist, // Open file at path only if it exists + Dqn_FsFileOpen_OpenAlways, // Open file at path, create file if it does not exist }; enum Dqn_FsFileAccess @@ -80,14 +80,17 @@ enum Dqn_FsFileAccess Dqn_FsFileAccess_Read = 1 << 0, Dqn_FsFileAccess_Write = 1 << 1, Dqn_FsFileAccess_Execute = 1 << 2, - Dqn_FsFileAccess_AppendOnly = 1 << 3, ///< This flag cannot be combined with any other acess mode + Dqn_FsFileAccess_AppendOnly = 1 << 3, // This flag cannot be combined with any other access mode Dqn_FsFileAccess_ReadWrite = Dqn_FsFileAccess_Read | Dqn_FsFileAccess_Write, Dqn_FsFileAccess_All = Dqn_FsFileAccess_ReadWrite | Dqn_FsFileAccess_Execute, }; -DQN_API Dqn_FsFile Dqn_Fs_OpenFile (Dqn_String8 path, Dqn_FsFileOpen open_mode, uint32_t access); -DQN_API bool Dqn_Fs_WriteFile(Dqn_FsFile *file, char const *buffer, Dqn_usize size); -DQN_API void Dqn_Fs_CloseFile(Dqn_FsFile *file); +DQN_API Dqn_FsFile Dqn_Fs_OpenFile (Dqn_String8 path, Dqn_FsFileOpen open_mode, uint32_t access); +DQN_API bool Dqn_Fs_WriteFileBuffer(Dqn_FsFile *file, void const *data, Dqn_usize size); +DQN_API bool Dqn_Fs_WriteFile (Dqn_FsFile *file, Dqn_String8 buffer); +DQN_API bool Dqn_Fs_WriteFileFV (Dqn_FsFile *file, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args); +DQN_API bool Dqn_Fs_WriteFileF (Dqn_FsFile *file, DQN_FMT_STRING_ANNOTATE char const *fmt, ...); +DQN_API void Dqn_Fs_CloseFile (Dqn_FsFile *file); #endif // !defined(DQN_NO_FS) // NOTE: File system paths ========================================================================= @@ -459,27 +462,16 @@ DQN_API uint64_t Dqn_OS_EstimateTSCPerSecond(uint64_t duration_ms_to_gauge_ts // @param[in] conflict_arena A pointer to the arena currently being used in the // function -#if !defined(DQN_THREAD_CONTEXT_ARENAS) - #define DQN_THREAD_CONTEXT_ARENAS 2 -#endif - struct Dqn_ThreadContext { Dqn_b32 init; - Dqn_Arena *arena; ///< Per thread arena - Dqn_Allocator allocator; ///< Allocator that uses the arena + // Scratch memory arena's for the calling thread + Dqn_Arena *scratch_arenas[2]; - /// Temp memory arena's for the calling thread - Dqn_Arena *temp_arenas[DQN_THREAD_CONTEXT_ARENAS]; - - /// Allocators that use the corresponding arena from the thread context. - /// Provided for convenience when interfacing with allocator interfaces. - Dqn_Allocator temp_allocators[DQN_THREAD_CONTEXT_ARENAS]; - - #if defined(DQN_DEBUG_THREAD_CONTEXT) - Dqn_ArenaStat temp_arenas_stat[DQN_THREAD_CONTEXT_ARENAS]; - #endif + // Allocators that use the corresponding arena from the thread context. + // Provided for convenience when interfacing with allocator interfaces. + Dqn_Allocator scratch_allocators[2]; }; struct Dqn_ThreadScratch @@ -487,16 +479,10 @@ struct Dqn_ThreadScratch Dqn_ThreadScratch(Dqn_ThreadContext *context, uint8_t context_index); ~Dqn_ThreadScratch(); - /// Index into the arena/allocator/stat array in the thread context - /// specifying what arena was assigned. - uint8_t index; Dqn_Allocator allocator; Dqn_Arena *arena; - Dqn_b32 destructed = false; /// Detect copies of the scratch + Dqn_b32 destructed; Dqn_ArenaTempMemory temp_memory; - #if defined(DQN_LEAK_TRACING) - Dqn_CallSite leak_site__; - #endif }; // NOTE: Context =================================================================================== diff --git a/dqn_platform_print.cpp b/dqn_platform_print.cpp deleted file mode 100644 index 6521772..0000000 --- a/dqn_platform_print.cpp +++ /dev/null @@ -1,191 +0,0 @@ -// NOTE: [$PRIN] Dqn_Print ========================================================================= -DQN_API Dqn_PrintStyle Dqn_Print_StyleColour(uint8_t r, uint8_t g, uint8_t b, Dqn_PrintBold bold) -{ - Dqn_PrintStyle result = {}; - result.bold = bold; - result.colour = true; - result.r = r; - result.g = g; - result.b = b; - return result; -} - -DQN_API Dqn_PrintStyle Dqn_Print_StyleColourU32(uint32_t rgb, Dqn_PrintBold bold) -{ - uint8_t r = (rgb >> 24) & 0xFF; - uint8_t g = (rgb >> 16) & 0xFF; - uint8_t b = (rgb >> 8) & 0xFF; - Dqn_PrintStyle result = Dqn_Print_StyleColour(r, g, b, bold); - return result; -} - -DQN_API Dqn_PrintStyle Dqn_Print_StyleBold() -{ - Dqn_PrintStyle result = {}; - result.bold = Dqn_PrintBold_Yes; - return result; -} - -DQN_API void Dqn_Print_Std(Dqn_PrintStd std_handle, Dqn_String8 string) -{ - DQN_ASSERT(std_handle == Dqn_PrintStd_Out || std_handle == Dqn_PrintStd_Err); - - #if defined(DQN_OS_WIN32) - // NOTE: Get the output handles from kernel ==================================================== - DQN_THREAD_LOCAL void *std_out_print_handle = nullptr; - DQN_THREAD_LOCAL void *std_err_print_handle = nullptr; - DQN_THREAD_LOCAL bool std_out_print_to_console = false; - DQN_THREAD_LOCAL bool std_err_print_to_console = false; - - if (!std_out_print_handle) { - unsigned long mode = 0; (void)mode; - std_out_print_handle = GetStdHandle(STD_OUTPUT_HANDLE); - std_out_print_to_console = GetConsoleMode(std_out_print_handle, &mode) != 0; - - std_err_print_handle = GetStdHandle(STD_ERROR_HANDLE); - std_err_print_to_console = GetConsoleMode(std_err_print_handle, &mode) != 0; - } - - // NOTE: Select the output handle ============================================================== - void *print_handle = std_out_print_handle; - bool print_to_console = std_out_print_to_console; - if (std_handle == Dqn_PrintStd_Err) { - print_handle = std_err_print_handle; - print_to_console = std_err_print_to_console; - } - - // NOTE: Write the string ====================================================================== - DQN_ASSERT(string.size < DQN_CAST(unsigned long)-1); - unsigned long bytes_written = 0; (void)bytes_written; - if (print_to_console) { - WriteConsoleA(print_handle, string.data, DQN_CAST(unsigned long)string.size, &bytes_written, nullptr); - } else { - WriteFile(print_handle, string.data, DQN_CAST(unsigned long)string.size, &bytes_written, nullptr); - } - #else - fprintf(std_handle == Dqn_PrintStd_Out ? stdout : stderr, "%.*s", DQN_STRING_FMT(string)); - #endif -} - -DQN_API void Dqn_Print_StdStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string) -{ - if (string.data && string.size) { - if (style.colour) - Dqn_Print_Std(std_handle, Dqn_Print_ESCColourFgString(style.r, style.g, style.b)); - if (style.bold == Dqn_PrintBold_Yes) - Dqn_Print_Std(std_handle, Dqn_Print_ESCBoldString); - Dqn_Print_Std(std_handle, string); - if (style.colour || style.bold == Dqn_PrintBold_Yes) - Dqn_Print_Std(std_handle, Dqn_Print_ESCResetString); - } -} - -DQN_FILE_SCOPE char *Dqn_Print_VSPrintfChunker_(const char *buf, void *user, int len) -{ - Dqn_String8 string = {}; - string.data = DQN_CAST(char *)buf; - string.size = len; - - Dqn_PrintStd std_handle = DQN_CAST(Dqn_PrintStd)DQN_CAST(uintptr_t)user; - Dqn_Print_Std(std_handle, string); - return (char *)buf; -} - -DQN_API void Dqn_Print_StdF(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - Dqn_Print_StdFV(std_handle, fmt, args); - va_end(args); -} - -DQN_API void Dqn_Print_StdFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - Dqn_Print_StdFVStyle(std_handle, style, fmt, args); - va_end(args); -} - -DQN_API void Dqn_Print_StdFV(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args) -{ - char buffer[STB_SPRINTF_MIN]; - STB_SPRINTF_DECORATE(vsprintfcb)(Dqn_Print_VSPrintfChunker_, DQN_CAST(void *)DQN_CAST(uintptr_t)std_handle, buffer, fmt, args); -} - -DQN_API void Dqn_Print_StdFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args) -{ - if (fmt) { - if (style.colour) - Dqn_Print_Std(std_handle, Dqn_Print_ESCColourFgString(style.r, style.g, style.b)); - if (style.bold == Dqn_PrintBold_Yes) - Dqn_Print_Std(std_handle, Dqn_Print_ESCBoldString); - Dqn_Print_StdFV(std_handle, fmt, args); - if (style.colour || style.bold == Dqn_PrintBold_Yes) - Dqn_Print_Std(std_handle, Dqn_Print_ESCResetString); - } -} - -DQN_API void Dqn_Print_StdLn(Dqn_PrintStd std_handle, Dqn_String8 string) -{ - Dqn_Print_Std(std_handle, string); - Dqn_Print_Std(std_handle, DQN_STRING8("\n")); -} - -DQN_API void Dqn_Print_StdLnF(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - Dqn_Print_StdLnFV(std_handle, fmt, args); - va_end(args); -} - -DQN_API void Dqn_Print_StdLnFV(Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args) -{ - Dqn_Print_StdFV(std_handle, fmt, args); - Dqn_Print_Std(std_handle, DQN_STRING8("\n")); -} - -DQN_API void Dqn_Print_StdLnStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string) -{ - Dqn_Print_StdStyle(std_handle, style, string); - Dqn_Print_Std(std_handle, DQN_STRING8("\n")); -} - -DQN_API void Dqn_Print_StdLnFStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...) -{ - va_list args; - va_start(args, fmt); - Dqn_Print_StdLnFVStyle(std_handle, style, fmt, args); - va_end(args); -} - -DQN_API void Dqn_Print_StdLnFVStyle(Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args) -{ - Dqn_Print_StdFVStyle(std_handle, style, fmt, args); - Dqn_Print_Std(std_handle, DQN_STRING8("\n")); -} - -DQN_API Dqn_String8 Dqn_Print_ESCColourString(Dqn_PrintESCColour colour, uint8_t r, uint8_t g, uint8_t b) -{ - DQN_THREAD_LOCAL char buffer[32]; - buffer[0] = 0; - Dqn_String8 result = {}; - result.size = STB_SPRINTF_DECORATE(snprintf)(buffer, - DQN_ARRAY_UCOUNT(buffer), - "\x1b[%d;2;%u;%u;%um", - colour == Dqn_PrintESCColour_Fg ? 38 : 48, - r, g, b); - result.data = buffer; - return result; -} - -DQN_API Dqn_String8 Dqn_Print_ESCColourU32String(Dqn_PrintESCColour colour, uint32_t value) -{ - uint8_t r = DQN_CAST(uint8_t)(value >> 24); - uint8_t g = DQN_CAST(uint8_t)(value >> 16); - uint8_t b = DQN_CAST(uint8_t)(value >> 8); - Dqn_String8 result = Dqn_Print_ESCColourString(colour, r, g, b); - return result; -} - diff --git a/dqn_platform_print.h b/dqn_platform_print.h deleted file mode 100644 index b0e37fb..0000000 --- a/dqn_platform_print.h +++ /dev/null @@ -1,84 +0,0 @@ -// NOTE: [$PRIN] Dqn_Print ========================================================================= -enum Dqn_PrintStd -{ - Dqn_PrintStd_Out, - Dqn_PrintStd_Err, -}; - -enum Dqn_PrintBold -{ - Dqn_PrintBold_No, - Dqn_PrintBold_Yes, -}; - -struct Dqn_PrintStyle -{ - Dqn_PrintBold bold; - bool colour; - uint8_t r, g, b; -}; - -enum Dqn_PrintESCColour -{ - Dqn_PrintESCColour_Fg, - Dqn_PrintESCColour_Bg, -}; - -// NOTE: Print Style =============================================================================== -DQN_API Dqn_PrintStyle Dqn_Print_StyleColour (uint8_t r, uint8_t g, uint8_t b, Dqn_PrintBold bold); -DQN_API Dqn_PrintStyle Dqn_Print_StyleColourU32 (uint32_t rgb, Dqn_PrintBold bold); -DQN_API Dqn_PrintStyle Dqn_Print_StyleBold (); - -// NOTE: Print Standard Out ======================================================================== -#define Dqn_Print(string) Dqn_Print_Std(Dqn_PrintStd_Out, string) -#define Dqn_Print_F(fmt, ...) Dqn_Print_StdF(Dqn_PrintStd_Out, fmt, ## __VA_ARGS__) -#define Dqn_Print_FV(fmt, args) Dqn_Print_StdFV(Dqn_PrintStd_Out, fmt, args) - -#define Dqn_Print_Style(style, string) Dqn_Print_StdStyle(Dqn_PrintStd_Out, style, string) -#define Dqn_Print_FStyle(style, fmt, ...) Dqn_Print_StdFStyle(Dqn_PrintStd_Out, style, fmt, ## __VA_ARGS__) -#define Dqn_Print_FVStyle(style, fmt, args, ...) Dqn_Print_StdFVStyle(Dqn_PrintStd_Out, style, fmt, args) - -#define Dqn_Print_Ln(string) Dqn_Print_StdLn(Dqn_PrintStd_Out, string) -#define Dqn_Print_LnF(fmt, ...) Dqn_Print_StdLnF(Dqn_PrintStd_Out, fmt, ## __VA_ARGS__) -#define Dqn_Print_LnFV(fmt, args) Dqn_Print_StdLnFV(Dqn_PrintStd_Out, fmt, args) - -#define Dqn_Print_LnStyle(style, string) Dqn_Print_StdLnStyle(Dqn_PrintStd_Out, style, string); -#define Dqn_Print_LnFStyle(style, fmt, ...) Dqn_Print_StdLnFStyle(Dqn_PrintStd_Out, style, fmt, ## __VA_ARGS__); -#define Dqn_Print_LnFVStyle(style, fmt, args) Dqn_Print_StdLnFVStyle(Dqn_PrintStd_Out, style, fmt, args); - -// NOTE: Print ===================================================================================== -DQN_API void Dqn_Print_Std (Dqn_PrintStd std_handle, Dqn_String8 string); -DQN_API void Dqn_Print_StdF (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...); -DQN_API void Dqn_Print_StdFV (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args); - -DQN_API void Dqn_Print_StdStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string); -DQN_API void Dqn_Print_StdFStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...); -DQN_API void Dqn_Print_StdFVStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args); - -DQN_API void Dqn_Print_StdLn (Dqn_PrintStd std_handle, Dqn_String8 string); -DQN_API void Dqn_Print_StdLnF (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, ...); -DQN_API void Dqn_Print_StdLnFV (Dqn_PrintStd std_handle, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args); - -DQN_API void Dqn_Print_StdLnStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, Dqn_String8 string); -DQN_API void Dqn_Print_StdLnFStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, ...); -DQN_API void Dqn_Print_StdLnFVStyle (Dqn_PrintStd std_handle, Dqn_PrintStyle style, DQN_FMT_STRING_ANNOTATE char const *fmt, va_list args); - -// NOTE: ANSI Formatting Codes ===================================================================== -Dqn_String8 Dqn_Print_ESCColourString (Dqn_PrintESCColour colour, uint8_t r, uint8_t g, uint8_t b); -Dqn_String8 Dqn_Print_ESCColourU32String(Dqn_PrintESCColour colour, uint32_t value); - -#define Dqn_Print_ESCColourFgString(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Fg, r, g, b) -#define Dqn_Print_ESCColourBgString(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Bg, r, g, b) -#define Dqn_Print_ESCColourFg(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Fg, r, g, b).data -#define Dqn_Print_ESCColourBg(r, g, b) Dqn_Print_ESCColourString(Dqn_PrintESCColour_Bg, r, g, b).data - -#define Dqn_Print_ESCColourFgU32String(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Fg, value) -#define Dqn_Print_ESCColourBgU32String(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Bg, value) -#define Dqn_Print_ESCColourFgU32(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Fg, value).data -#define Dqn_Print_ESCColourBgU32(value) Dqn_Print_ESCColourU32String(Dqn_PrintESCColour_Bg, value).data - -#define Dqn_Print_ESCReset "\x1b[0m" -#define Dqn_Print_ESCBold "\x1b[1m" -#define Dqn_Print_ESCResetString DQN_STRING8(Dqn_Print_ESCReset) -#define Dqn_Print_ESCBoldString DQN_STRING8(Dqn_Print_ESCBold) -