From 6970a59c3574ec20811331fdbf08ba26760712a2 Mon Sep 17 00:00:00 2001 From: Musa Mahmood Date: Fri, 5 Dec 2025 21:24:50 -0500 Subject: [PATCH] Lots of refactoring, overhaul logging system to use context (see log_error macro) --- lib/Base/Arena.h | 6 +- .../{Arena_Table.cpp => Arena_Free_List.cpp} | 48 +++--- lib/Base/Arena_Hash_Table.h | 3 + lib/Base/Base_Thread_Context.cpp | 10 +- lib/Base/Base_Thread_Context.h | 6 +- lib/Base/ErrorType.cpp | 152 ++++++++++++++++-- lib/Base/Expandable_Arena.cpp | 2 +- lib/Base/Logger.cpp | 30 +--- lib/Base/Logger.h | 3 +- lib/Base/Serializer.h | 6 +- lib/Base/String.cpp | 2 +- lib/Base/String.h | 5 +- lib/Base/Threads.cpp | 2 +- lib/Base/run_tests.cpp | 4 + lib/OS/OS_Filesystem.cpp | 87 ++++++++++ lib/OS/OS_Win32.cpp | 14 +- lib/OS/OS_Win32.h | 7 +- lib/OS/OS_Win32_NTFS.cpp | 39 ++--- lib_main.cpp | 5 +- src/Ex1.cpp | 2 +- src/ImGui_Supplementary.cpp | 4 +- src/explorer_main.cpp | 4 +- 22 files changed, 325 insertions(+), 116 deletions(-) rename lib/Base/{Arena_Table.cpp => Arena_Free_List.cpp} (53%) create mode 100644 lib/OS/OS_Filesystem.cpp diff --git a/lib/Base/Arena.h b/lib/Base/Arena.h index 4198705..c3eb7d3 100644 --- a/lib/Base/Arena.h +++ b/lib/Base/Arena.h @@ -12,7 +12,7 @@ constexpr u16 ARENA_DEFAULT_ALIGNMENT = CPU_REGISTER_WIDTH_BYTES; #define ARENA_DEBUG BUILD_DEBUG enum class Arena_Reserve: u8 { - Size_64K = 0, // these are used as indices in Arena_Table! + Size_64K = 0, // these are used as indices in Arena_Free_List! Size_2M = 1, Size_64M = 2, Size_2G = 3, @@ -60,8 +60,8 @@ typedef void* (*Memory_Wipe_Function)(void* memory, u64 byte_count); void* arena_allocator_proc (Allocator_Mode mode, s64 requested_size, s64 old_size, void* old_memory, void* allocator_data); -// Interface API for normal use (idk how to explain - see Arena_Table.cpp) -struct Arena_Table { +// Interface API for normal use (idk how to explain - see Arena_Free_List.cpp) +struct Arena_Free_List { Mutex mutex; s32 in_flight_count[6]; Array free_table[6]; diff --git a/lib/Base/Arena_Table.cpp b/lib/Base/Arena_Free_List.cpp similarity index 53% rename from lib/Base/Arena_Table.cpp rename to lib/Base/Arena_Free_List.cpp index 0a2f5eb..6cb6767 100644 --- a/lib/Base/Arena_Table.cpp +++ b/lib/Base/Arena_Free_List.cpp @@ -1,71 +1,71 @@ -// #TODO: #Arena_Table #garbage_collection in `release_arena` +// #TODO: #Arena_Free_List #garbage_collection in `release_arena` // [ ] Garbage collection if we have >> 64 in a particular table for a while. // There should be some parameters regarding what the upper limit for idle // committed pages should be and a heuristic for maximum number of arenas waiting -global Arena_Table* arena_table; +global Arena_Free_List* arena_free_list; // Only call once from main thread! -void initialize_arena_table (Allocator allocator) { - mutex_init(&arena_table->mutex); - Assert(arena_table != nullptr); - if (arena_table->initialized) +void initialize_arena_free_list (Allocator allocator) { + mutex_init(&arena_free_list->mutex); + Assert(arena_free_list != nullptr); + if (arena_free_list->initialized) return; for (s32 i = 0; i < 6; i += 1) { - arena_table->in_flight_count[i] = 0; - arena_table->free_table[i].allocator = allocator; - array_reserve(arena_table->free_table[i], 64); + arena_free_list->in_flight_count[i] = 0; + arena_free_list->free_table[i].allocator = allocator; + array_reserve(arena_free_list->free_table[i], 64); #if ARENA_DEBUG - arena_table->in_flight[i].allocator = allocator; - array_reserve(arena_table->in_flight[i], 64); + arena_free_list->in_flight[i].allocator = allocator; + array_reserve(arena_free_list->in_flight[i], 64); #endif } - arena_table->initialized = true; + arena_free_list->initialized = true; } Arena* next_arena (Arena_Reserve reserve_size) { - Assert(arena_table != nullptr); + Assert(arena_free_list != nullptr); Arena* arena; - lock_guard(&arena_table->mutex); + lock_guard(&arena_free_list->mutex); s64 reserve_index = (s64)reserve_size; - if (!arena_table->free_table[reserve_index].count) { + if (!arena_free_list->free_table[reserve_index].count) { arena = bootstrap_arena(reserve_size, ARENA_DEFAULT_COMMIT_PAGE_COUNT); } else { - arena = pop(arena_table->free_table[reserve_index]); + arena = pop(arena_free_list->free_table[reserve_index]); } #if ARENA_DEBUG - array_add(arena_table->in_flight[reserve_index], arena); + array_add(arena_free_list->in_flight[reserve_index], arena); #endif - arena_table->in_flight_count[reserve_index] += 1; + arena_free_list->in_flight_count[reserve_index] += 1; - unlock(&arena_table->mutex); + unlock(&arena_free_list->mutex); Assert(arena != nullptr); return arena; } void release_arena (Arena* arena, bool delete_extra_pages) { - Assert(arena_table != nullptr); + Assert(arena_free_list != nullptr); Assert(arena != nullptr); Assert(arena_is_bootstrapped(arena)); // Only put into free table if arena is bootstrapped? - lock_guard(&arena_table->mutex); + lock_guard(&arena_free_list->mutex); s64 reserve_index = (s64)arena->reserve_size; #if ARENA_DEBUG - array_unordered_remove_by_value(arena_table->in_flight[reserve_index], arena, 1); // BUILD_DEBUG! + array_unordered_remove_by_value(arena_free_list->in_flight[reserve_index], arena, 1); // BUILD_DEBUG! #endif arena_reset_keeping_memory(arena); if (delete_extra_pages) { free_pages_down_to(arena, arena->initial_commit_page_count); } - array_add(arena_table->free_table[reserve_index], arena); + array_add(arena_free_list->free_table[reserve_index], arena); - arena_table->in_flight_count[reserve_index] -= 1; + arena_free_list->in_flight_count[reserve_index] -= 1; // #TODO #garbage_collection // if (arena_free_table[reserve_index].count > 64) { // s64 arenas_to_delete_count = arena_free_table[reserve_index].count - 64; diff --git a/lib/Base/Arena_Hash_Table.h b/lib/Base/Arena_Hash_Table.h index 1af59c3..96a9af3 100644 --- a/lib/Base/Arena_Hash_Table.h +++ b/lib/Base/Arena_Hash_Table.h @@ -1,3 +1,6 @@ +// #ArenaTableConfusion I just realized ArenaTable (a hash-table backed by an Arena allocator) may be confused with Arena_Table (which is a table tracking free Arenas) +// Solution: rename Arena_Table, to Arena_Free_List. + // Should ArenaTable be bootstrapped like String_Builder? // see: new_string_builder template diff --git a/lib/Base/Base_Thread_Context.cpp b/lib/Base/Base_Thread_Context.cpp index 9b2e285..baccae4 100644 --- a/lib/Base/Base_Thread_Context.cpp +++ b/lib/Base/Base_Thread_Context.cpp @@ -6,12 +6,11 @@ internal void Bootstrap_Main_Thread_Context () { GPAllocator_Initialize_Allocation_Tracker(); // 1. Setup arena table - arena_table = (Arena_Table*)GPAllocator_New(sizeof(Arena_Table), 64, true); // permanent allocation. - memset(arena_table, 0, sizeof(Arena_Table)); - initialize_arena_table(GPAllocator()); + arena_free_list = (Arena_Free_List*)GPAllocator_New(sizeof(Arena_Free_List), 64, true); // permanent allocation. + memset(arena_free_list, 0, sizeof(Arena_Free_List)); + initialize_arena_free_list(GPAllocator()); - // 2. Setup thread local context - // #NewContext + // 2. #NewContext Setup thread local context ExpandableArena* arena_ex = expandable_arena_new(Arena_Reserve::Size_64M, 16); thread_local_context = New(allocator(arena_ex)); @@ -21,6 +20,7 @@ internal void Bootstrap_Main_Thread_Context () { thread_local_context->thread_idx = 0; thread_local_context->thread_name = "Main Thread"; thread_local_context->log_builder = new_string_builder(Arena_Reserve::Size_64M); + thread_local_context->error_arena = next_arena(Arena_Reserve::Size_64M); default_logger_initialize(); thread_local_context->logger = {default_logger_proc, &default_logger}; diff --git a/lib/Base/Base_Thread_Context.h b/lib/Base/Base_Thread_Context.h index 0b2f31b..64d05c5 100644 --- a/lib/Base/Base_Thread_Context.h +++ b/lib/Base/Base_Thread_Context.h @@ -1,4 +1,6 @@ -struct Thread; // hacky fwd declare +// #hacky fwd declares +struct Thread; +struct Error; struct Graphics; struct Thread_Context { @@ -21,6 +23,7 @@ struct Thread_Context { Allocator error_allocator = GPAllocator(); Error* first_error = nullptr; Error* current_error = nullptr; + Arena* error_arena; // Graphics stuff: Graphics* graphics; @@ -30,6 +33,7 @@ struct Thread_Context { thread_static Thread_Context* thread_local_context; // #TODO #NewContext void create_thread_context (Thread_Context** context, string thread_name, bool is_main_thread); +// Thread-context #Errors: internal void Bootstrap_Main_Thread_Context (); diff --git a/lib/Base/ErrorType.cpp b/lib/Base/ErrorType.cpp index 10b3f01..a59cda9 100644 --- a/lib/Base/ErrorType.cpp +++ b/lib/Base/ErrorType.cpp @@ -15,26 +15,154 @@ struct Error { ErrorClass severity = ErrorClass::NONE; s32 thread_id; s32 source_line; - s32 path_length; - char* path; + string file_path; + string function_name; // Linked list to errors Error* previous_error; // if we're passing errors up the callstack. Error* next_error; - - // Arena* arena; - - // Error () { memset(this, 0, sizeof(*this)); } }; -// string create_error(ErrorClass severity, string fmt, ...) { - -// } - -string to_string (Error error) { - return { error.count, error.data }; +char* error_severity (ErrorClass severity) { + switch (severity) { + case ErrorClass::NONE: { + } break; + case ErrorClass::WARNING: { + return "[WARNING]"; + } break; + case ErrorClass::ERROR: { + return "[ERROR]"; + } break; + case ErrorClass::FATAL: { + return "[FATAL ERROR]"; + } break; + } + return ""; } +void push_error (Error* new_error); + +string to_string (Error* error) { + return { error->count, error->data }; +} + +#define log_fatal_error(fmt, ...) \ + Log_Error_2(__FILE__, __FUNCTION__, __LINE__, ErrorClass::FATAL, fmt, ##__VA_ARGS__) + +#define log_error(fmt, ...) \ + Log_Error_2(__FILE__, __FUNCTION__, __LINE__, ErrorClass::ERROR, fmt, ##__VA_ARGS__) + +#define log_warning(fmt, ...) \ + Log_Error_2(__FILE__, __FUNCTION__, __LINE__, ErrorClass::WARNING, fmt, ##__VA_ARGS__) + +Error* new_error (ErrorClass severity, string error_string) { + Error* error = New(); + error->count = error_string.count; + error->data = error_string.data; + error->severity = severity; + + return error; +} + +// #TODO: // void OS_Log_Error_With_Code // OS-SPECIFIC CALLING GetLastError, etc. +// Then remove all instances of log_error_code_and_string() +// + +void Log_Error_2 (string file_path, string function_name, s32 line_number, ErrorClass severity, string fmt, ...) { + Assert(thread_context() != nullptr); + push_arena(thread_context()->error_arena); + + String_Builder* sb = new_string_builder(Arena_Reserve::Size_64K); + // #TODO: prepend severity, other information + print_to_builder(sb, "%s ", error_severity(severity)); + + va_list args; + va_start(args, fmt); + print_to_builder_internal(sb, fmt, args); + va_end(args); + + append(sb, "\n"); + + string error_string = builder_to_string(sb); + Error* error = new_error(severity, error_string); + // Additional information + error->thread_id = thread_context()->thread_idx; + error->source_line = line_number; + error->file_path = copy_string(file_path); + error->function_name = copy_string(function_name); + // Note: we don't need to assign previous_error or next_error, as that is done by the thread_context when we #push_error + error->previous_error = nullptr; + error->next_error = nullptr; + + push_error(error); +} + +void push_error (Error* new_error) { + Assert(new_error != nullptr); + if (new_error == nullptr) return; + Error* current_error = thread_context()->current_error; + if (current_error) { + current_error->next_error = new_error; + new_error->previous_error = current_error; + } else { + thread_context()->first_error = new_error; + new_error->previous_error = nullptr; + } + thread_context()->current_error = new_error; + + switch (new_error->severity) { + case ErrorClass::NONE: + case ErrorClass::WARNING: { + print(to_string(new_error)); + } break; + case ErrorClass::ERROR: + case ErrorClass::FATAL: { + print_error(to_string(new_error)); + } break; + } +} + +void clear_errors () { // Reset pointers and reset error_arena + arena_reset(thread_context()->error_arena); // maybe overwrite memory? + thread_context()->first_error = nullptr; + thread_context()->current_error = nullptr; +} + +void clear_error (Error* error) { + // If we want to clear a specific error (simply remove from the list) + Assert(error != nullptr); + bool is_current_error = (thread_context()->current_error == error); + bool is_first_error = (thread_context()->first_error == error); + + Error* current_error = thread_context()->first_error; + if (current_error == nullptr) return; // no errors in linked list. + + while (current_error != error && current_error != nullptr) { + current_error = current_error->next_error; + } + Assert(current_error != nullptr); + if (current_error == nullptr) return; // shouldn't happen + Error* the_previous_error = current_error->previous_error; + Error* the_next_error = current_error->next_error; + // Remove current_node from linked list: + the_previous_error->next_error = the_next_error; + the_next_error->previous_error = the_previous_error; + if (is_first_error && is_current_error) { // It matches the only item in the list, just empty the list: + clear_errors(); + return; + } + if (is_first_error) { + // the_next_error becomes new first error. + thread_context()->first_error = the_next_error; + } + if (is_current_error) { + // the current_error becomes the previous error + thread_context()->current_error = the_previous_error; + } +} + + + // Will need to use __FILE__ and __LINE__ macros // Error* new_error (string error_message, ErrorClass severity, Error* previous_error=nullptr); diff --git a/lib/Base/Expandable_Arena.cpp b/lib/Base/Expandable_Arena.cpp index 7b0b6b7..92f1d1a 100644 --- a/lib/Base/Expandable_Arena.cpp +++ b/lib/Base/Expandable_Arena.cpp @@ -46,7 +46,7 @@ void* expandable_arena_alloc (ExpandableArena* arena_ex, s64 byte_count) { Assert(arena_ex != nullptr); Assert(arena_ex->memory_base != nullptr); // must be initialized before calling. Assert(is_valid(arena_ex)); - Assert(arena_table->initialized); + Assert(arena_free_list->initialized); Arena* arena = (Arena*)arena_ex->current; diff --git a/lib/Base/Logger.cpp b/lib/Base/Logger.cpp index 6f9eadb..abb9bca 100644 --- a/lib/Base/Logger.cpp +++ b/lib/Base/Logger.cpp @@ -1,32 +1,9 @@ -void log_error (string fmt, ...) { - String_Builder* sb = thread_context()->log_builder; - - va_list args; - va_start(args, fmt); - print_to_builder(sb, fmt, args); - va_end(args); - - // Append newline if needed - string result = string_view(sb); - bool ends_with_newline = (result.data[result.count-1] == '\n'); - if (!ends_with_newline) { - append(sb, "\n"); - } - - string message = string_view(sb); - - Logger* logger = context_logger(); - logger->proc(message, Log_Level::Error, logger->data); - - reset_string_builder(sb, true); -} - void log (string fmt, ...) { String_Builder* sb = thread_context()->log_builder; va_list args; va_start(args, fmt); - print_to_builder(sb, fmt, args); + print_to_builder_internal(sb, fmt, args); va_end(args); // Append newline if needed @@ -48,3 +25,8 @@ void print (string message) { Logger* logger = context_logger(); logger->proc(message, Log_Level::None, logger->data); } + +void print_error (string error_message) { + Logger* logger = context_logger(); + logger->proc(error_message, Log_Level::Error, logger->data); +} \ No newline at end of file diff --git a/lib/Base/Logger.h b/lib/Base/Logger.h index a193c7a..e79fc8e 100644 --- a/lib/Base/Logger.h +++ b/lib/Base/Logger.h @@ -65,7 +65,6 @@ void default_logger_initialize() { #endif } -void log_error (string fmt, ...); void log (string fmt, ...); void print (string message); - +void print_error (string error_message); diff --git a/lib/Base/Serializer.h b/lib/Base/Serializer.h index 0e3c242..adb3459 100644 --- a/lib/Base/Serializer.h +++ b/lib/Base/Serializer.h @@ -37,18 +37,18 @@ template force_inline void AddArray (Serializer* serializer, ArrayV AddArray_NoSize(serializer, view); } -template force_inline void AddString (Serializer* serializer, string s) { +force_inline void AddString (Serializer* serializer, string s) { Add(serializer, s.count); AddArray_NoSize(serializer, to_view(s)); } -template force_inline void AddString32 (Serializer* serializer, string s) { +force_inline void AddString32 (Serializer* serializer, string s) { u32 string_length = (u32)s.count; Add(serializer, string_length); AddArray_NoSize(serializer, to_view(s)); } -template force_inline void AddString16 (Serializer* serializer, string s) { +force_inline void AddString16 (Serializer* serializer, string s) { u16 string_length = (u16)s.count; Add(serializer, string_length); AddArray_NoSize(serializer, to_view(s)); diff --git a/lib/Base/String.cpp b/lib/Base/String.cpp index 04e3189..7a2ab6d 100644 --- a/lib/Base/String.cpp +++ b/lib/Base/String.cpp @@ -199,7 +199,7 @@ force_inline void append_no_add (String_Builder* sb, string s) { // Unfortunately this follows the printf format, which is annoying. // I'd rather have something like fmt:: -void print_to_builder (String_Builder* sb, string format, va_list args) { +void print_to_builder_internal (String_Builder* sb, string format, va_list args) { s64 expected_final_count = max_array_size(*sb);// amount to reserve if (sb->allocated < expected_final_count) { diff --git a/lib/Base/String.h b/lib/Base/String.h index 869c95b..e1713e6 100644 --- a/lib/Base/String.h +++ b/lib/Base/String.h @@ -117,9 +117,10 @@ void append (String_Builder* sb, ArrayView strings); // This should probably be called append_but_do_not_increment_count internal force_inline void append_no_add (String_Builder* sb, string s); // for appending null terminators, does not increment count. void print_to_builder (String_Builder* sb, string format, ...); -void print_to_builder (String_Builder* sb, string format, va_list args); +void print_to_builder_internal (String_Builder* sb, string format, va_list args); string string_view (String_Builder* sb); internal force_inline void reset_string_builder (String_Builder* sb, bool keep_memory=false); -force_inline string builder_to_string (String_Builder* sb); // returns string view +// #rename copy_string_and_free_builder +force_inline string builder_to_string (String_Builder* sb); // returns copy and frees string_builder internal force_inline void free_string_builder (String_Builder* sb); diff --git a/lib/Base/Threads.cpp b/lib/Base/Threads.cpp index d02da5b..d061a6b 100644 --- a/lib/Base/Threads.cpp +++ b/lib/Base/Threads.cpp @@ -53,7 +53,7 @@ struct Worker_Info { u8 padding1[48]; }; static_assert(sizeof(Worker_Info) % 64 == 0); // This MUST be padded to cache line! -enum class Thread_Continue_Status : s32 { +enum class Thread_Continue_Status: s32 { THREAD_STOP = 0, THREAD_CONTINUE = 1 }; diff --git a/lib/Base/run_tests.cpp b/lib/Base/run_tests.cpp index 6c11e15..a51972f 100644 --- a/lib/Base/run_tests.cpp +++ b/lib/Base/run_tests.cpp @@ -6,6 +6,10 @@ void run_pre_setup_tests() { string string_literal_example = "Hello, I am a string literal."; void run_post_setup_tests() { + debug_break(); + log_warning("Hello, I am a warning :), and I am a big number: %lld", (s64)293509357); + log_error("Hello, I am an error - %s", "I'm another string"); + log_error("This is an error"); printf("Running post-setup tests...\n"); // See: main_thread_base_entry_point { Timed_Block_Print("string_builder_testing"); diff --git a/lib/OS/OS_Filesystem.cpp b/lib/OS/OS_Filesystem.cpp new file mode 100644 index 0000000..f2dedd9 --- /dev/null +++ b/lib/OS/OS_Filesystem.cpp @@ -0,0 +1,87 @@ +// So NTFS (and most systems) sort the tree by default in lexicographical descending order. +// For lookups, this often isn't that useful if you only know substrings of the path. + + +// struct BTNode { +// u16 key_count; +// BTNode* keys; +// u16 allocated; +// }; + +// struct B_Tree { +// BTNode* root; +// Allocator allocator; +// }; + +// A compact collection of data with sorting indices +// Maybe we can make B+ trees for sorting according to +// size and modtime. + +// It really doesn't make sense to store data in memory as a B-tree except +// if we need ordered insertions and deletes. +// + +// Returns offset +force_inline s32 AddString_NoCount (Serializer* serializer, u8* data, u8 count) { // #TODO: , bool null_terminate=false + u8* current_point = &serializer->data[serializer->count]; + s64 final_count = serializer->allocated + (count * sizeof(u8)); + + if (serializer->allocated < final_count) { + array_reserve(*serializer, final_count); + } + + memcpy(current_point, data, count * sizeof(u8)); + serializer->count += count * sizeof(u8); +} + +constexpr s64 DFS_Preallocation_Count = 4194304; // 2^22 + +// template +struct DFS_Array { + Serializer* strings; + + ArenaArray* offsets; // offsets into string_arena + ArenaArray* lengths; // this type may vary Not sure if I should make it a template argument. Seems yucky. + ArenaArray* modtimes; + ArenaArray* sizes; + ArenaArray* parent_indices; + + s64 index; // current index when inserting; + + // #Temporary arrays for linking??? + ArenaArray* record_ids; + ArenaArray* parent_ids; + + // #TODO: Sort indices (should these be trees?) + // ArenaArray indices_sorted_by_modtime; + // ArenaArray indices_sorted_by_size; +}; + +void initialize (DFS_Array* dfsa) { + Assert(dfsa != nullptr); + dfsa->strings = new_serializer(Arena_Reserve::Size_2G); + + dfsa->offsets = arena_array_new(DFS_Preallocation_Count, Arena_Reserve::Size_2G); + dfsa->lengths = arena_array_new (DFS_Preallocation_Count, Arena_Reserve::Size_2G); + dfsa->modtimes = arena_array_new(DFS_Preallocation_Count, Arena_Reserve::Size_2G); + dfsa->sizes = arena_array_new(DFS_Preallocation_Count, Arena_Reserve::Size_2G); + dfsa->parent_indices = arena_array_new(DFS_Preallocation_Count, Arena_Reserve::Size_2G); + + dfsa->index = 0; +} + +struct Dense_FS { // Link to OS_Drive + OS_Drive* drive; // backlink for reference. + DFS_Array paths; + DFS_Array files; + + ArenaTable path_table; // . +}; + +void initialize (Dense_FS* dfs, OS_Drive* drive) { + Assert(drive != nullptr); + dfs->drive = drive; + initialize(&dfs->paths); + initialize(&dfs->files); + table_init(&dfs->path_table, DFS_Preallocation_Count); +} \ No newline at end of file diff --git a/lib/OS/OS_Win32.cpp b/lib/OS/OS_Win32.cpp index 358f352..1558b0c 100644 --- a/lib/OS/OS_Win32.cpp +++ b/lib/OS/OS_Win32.cpp @@ -222,9 +222,10 @@ internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name= } s64 this_thread_index = InterlockedIncrement(&next_thread_index); - // #NewContext + // 2. #NewContext Setup NEW thread local context ExpandableArena* arena_ex = expandable_arena_new(Arena_Reserve::Size_64M, 16); + // #NOTE: we don't assign thread_local_context until we hit the #thread_entry_point thread->context = New(allocator(arena_ex)); thread->context->temp = expandable_arena_new(Arena_Reserve::Size_2M, 16); thread->context->arena = arena_ex; @@ -232,6 +233,7 @@ internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name= thread->context->thread_idx = (s32)this_thread_index; thread->context->thread_name = copy_string(thread_name); thread->context->log_builder = new_string_builder(Arena_Reserve::Size_64M); + thread->context->error_arena = next_arena(Arena_Reserve::Size_64M); thread->os_thread.windows_thread = windows_thread; thread->os_thread.windows_thread_id = windows_thread_id; @@ -338,7 +340,7 @@ internal string get_error_string (OS_Error_Code error_code) { return result; // trim_right(result, "\r\n"); } -internal void log_error_code_and_string () { +internal void log_error_code_and_string () { // #TODO: replace with call to log_error_with_code OS_Error_Code error_code = GetLastError(); log_error(" > GetLastError code: %d, %s\n", error_code, get_error_string(error_code).data); } @@ -372,8 +374,9 @@ internal File file_open (string file_path, bool for_writing, bool keep_existing_ } if (handle == INVALID_HANDLE_VALUE && log_errors) { - OS_Error_Code error_code = GetLastError(); - log_error("Could not open file `%s`, code: %d, %s", file_path, error_code, get_error_string(error_code).data); + // OS_Error_Code error_code = GetLastError(); + log_error("Could not open file `%s`", file_path); + log_error_code_and_string(); } File file; @@ -390,6 +393,7 @@ internal bool file_read (File file, u8* data, s64 bytes_to_read_count, s64* byte // ignore bytes_read_count if null. if (data == nullptr) { log_error("file_read called with null destination pointer.\n"); + log_error_code_and_string(); if (bytes_read_count) (*bytes_read_count) = 0; return false; } @@ -574,7 +578,7 @@ internal void os_enumerate_monitors () { if (!global_win32_state.system_info.monitors_enumerated) { // should reset array? if (!EnumDisplayMonitors(nullptr, nullptr, monitor_enum_proc, 0)) { - log_error("Failed to enumerate monitors\n"); + log_fatal_error("Failed to enumerate monitors\n"); Assert(false); // Failed to enumerate monitors ExitProcess(1); } diff --git a/lib/OS/OS_Win32.h b/lib/OS/OS_Win32.h index ef729dd..e3ddc30 100644 --- a/lib/OS/OS_Win32.h +++ b/lib/OS/OS_Win32.h @@ -5,7 +5,7 @@ f64 GetUnixTimestamp (); s64 GetUnixTimestampNanoseconds (); -enum class Wait_For_Result : s32 { +enum class Wait_For_Result: s32 { SUCCESS = 0, TIMEOUT = 1, ERROR = 2 // can't use ERROR because of Windows.h *sigh* @@ -165,7 +165,7 @@ File_System Win32_filesystem_from_string (string s) { Assert(false); return File_System::Unknown; } - +struct Dense_FS; // #Temp forward declare! struct Win32_Drive { string label; string volume_name; @@ -180,8 +180,11 @@ struct Win32_Drive { // Not sure if this should be here... // f32 enumeration_time; // f64 last_seen_alive_timestamp; + Dense_FS* data; }; +typedef Win32_Drive OS_Drive; + bool os_window_is_minimized (Window_Type window); bool os_main_window_is_minimized (); diff --git a/lib/OS/OS_Win32_NTFS.cpp b/lib/OS/OS_Win32_NTFS.cpp index c6c42df..b05aa65 100644 --- a/lib/OS/OS_Win32_NTFS.cpp +++ b/lib/OS/OS_Win32_NTFS.cpp @@ -141,38 +141,31 @@ bool NTFS_read_internal (NTFS_MFT_Internal* mft, void* buffer, u64 from, u64 cou return bytes_accessed_internal == count; } -enum class NTFS_Block_Flag : s32 { - idk = 0, - idk2 = 1, -}; - -struct NTFS_MFT_Copy { - u32 error_code; - // Array> mft_blocks; // idk if this is correct! - // Array mft_flags; -}; - -// #TODO: make a version where we just reconstruct the MFT as a deque in memory. -NTFS_MFT_Copy* NTFS_MFT_read_raw (string drive_path) { +// #TODO: Release resources if we face an early return! +Dense_FS* NTFS_MFT_read_raw (string drive_path) { Table* drive_table = &global_win32_state.system_info.drives; - // We should be able to fetch from the table using table_find_pointer + bool just_added = false; + Win32_Drive* drive = table_find_or_add(drive_table, drive_path, &just_added); + Assert(just_added == false && drive != nullptr); + if (drive == nullptr) { + return nullptr; + } + Assert(context_allocator() != temp()); // pointless as we're releasing temp end-of-scope Allocator primary_allocator = context_allocator(); auto_release_temp(); push_allocator(temp()); - NTFS_MFT_Copy* mft_copy = New(primary_allocator); //use context allocator. - string drive_letter = Win32_drive_letter(drive_path); + string create_file_target = format_string("\\\\.\\%s:", drive_letter.data); HANDLE file_handle = CreateFileA((LPCSTR)create_file_target.data, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if (file_handle == INVALID_HANDLE_VALUE) { log_error("CreateFileA failed on target %s", create_file_target.data); log_error_code_and_string(); - mft_copy->error_code = GetLastError(); - return mft_copy; + return nullptr; } push_allocator(primary_allocator); @@ -271,11 +264,11 @@ NTFS_MFT_Copy* NTFS_MFT_read_raw (string drive_path) { NTFS_FileNameAttributeHeader* fileNameAttribute = (NTFS_FileNameAttributeHeader*)attribute; if (fileNameAttribute->namespaceType != 2 && !fileNameAttribute->nonResident) { - file.parent_id = (u32)fileNameAttribute->parentRecordNumber; // truncate - file.record_id = fileRecord->recordNumber; - file.name_count = fileNameAttribute->fileNameLength; - file.name_data = (u16*)fileNameAttribute->fileName; - file.name_utf8 = wide_to_utf8(file.name_data, file.name_count); + file.parent_id = (u32)fileNameAttribute->parentRecordNumber; // truncate + file.record_id = fileRecord->recordNumber; + file.name_count = fileNameAttribute->fileNameLength; + file.name_data = (u16*)fileNameAttribute->fileName; + file.name_utf8 = wide_to_utf8(file.name_data, file.name_count); file.file_modtime = (u64)fileNameAttribute->modificationTime; file.is_directory = fileRecord->isDirectory; // We need to get size from the data attribute diff --git a/lib_main.cpp b/lib_main.cpp index 84fec25..6a102c6 100644 --- a/lib_main.cpp +++ b/lib_main.cpp @@ -31,15 +31,15 @@ #include "lib/Base/Serializer.h" #include "lib/Base/Serializer.cpp" -#include "lib/Base/ErrorType.cpp" #include "lib/Base/Base_Thread_Context.h" #include "lib/Base/Expandable_Arena.h" #include "lib/Base/Timing.h" -#include "lib/Base/Arena_Table.cpp" +#include "lib/Base/Arena_Free_List.cpp" #include "lib/Base/Arena.cpp" #include "lib/Base/Base_Thread_Context.cpp" +#include "lib/Base/ErrorType.cpp" #include "lib/Base/Logger.cpp" #include "lib/Base/Expandable_Arena.cpp" #include "lib/Base/Allocator.cpp" @@ -47,6 +47,7 @@ // OS-Abstraction Layer #include "lib/Base/Threads.cpp" +#include "lib/OS/OS_Filesystem.cpp" #if OS_WINDOWS # include "lib/OS/OS_Win32.cpp" diff --git a/src/Ex1.cpp b/src/Ex1.cpp index 8ecd759..5455702 100644 --- a/src/Ex1.cpp +++ b/src/Ex1.cpp @@ -26,7 +26,7 @@ void Ex1_Unregister_Global_Hotkeys () { bool Ex1_Register_Global_Hotkeys () { if (!RegisterHotKey(nullptr, HOTKEY_ID_BRING_TO_FOREGROUND, MOD_CONTROL|MOD_SHIFT|MOD_ALT, VK_SPACE_KEY_CODE)) { Assert(false); - log_error("Failed to register global hotkey Ctrl-Alt-Space"); + log_error("Failed to register global hotkey Ctrl-Shift-Alt-Space"); return false; } return true; diff --git a/src/ImGui_Supplementary.cpp b/src/ImGui_Supplementary.cpp index cbb139c..de9c136 100644 --- a/src/ImGui_Supplementary.cpp +++ b/src/ImGui_Supplementary.cpp @@ -371,8 +371,8 @@ void ImGui_Debug_Panel () { if (ImGui::Button(button_label)) { push_arena(thread_context()->arena); // auto_release(thread_context()->arena); - auto result = NTFS_MFT_read_raw(entry->value.label); - if (result->error_code != 0) { + auto dfs = NTFS_MFT_read_raw(entry->value.label); + if (dfs == nullptr) { log("[NTFS_MFT_read_raw] operation failed"); } } diff --git a/src/explorer_main.cpp b/src/explorer_main.cpp index 78e7614..77530bd 100644 --- a/src/explorer_main.cpp +++ b/src/explorer_main.cpp @@ -20,9 +20,9 @@ void Explorer_ImGui_Application_Win32 () { HWND hwnd = get_main_window().window; success = Win32_Load_Main_Window_Icon("tmp.ico"); - if (!success) { log_error("Failed to load tmp.ico"); } + if (!success) { log_warning("Failed to load tmp.ico"); } success = Win32_Load_Main_Window_Icon_Minimized("tmp_min.ico"); - if (!success) { log_error("Failed to load tmp_min.ico"); } + if (!success) { log_warning("Failed to load tmp_min.ico"); } // :Win32_Initialize_Extended Win32_Set_Main_Icon();