Cleanup TODOs, refactoring, major bug fixes
This commit is contained in:
parent
7755ef9225
commit
5c18e6f4da
@ -43,8 +43,6 @@ void* internal_alloc (s64 size);
|
||||
void internal_free (void* memory);
|
||||
void* internal_realloc (void* memory, s64 size, s64 old_size);
|
||||
|
||||
template <typename T> force_inline void Initialize (T* memory) { (*memory) = T(); }
|
||||
|
||||
template <typename T> T* New (Allocator allocator, bool initialize=true) {
|
||||
auto memory = (T*)allocator.proc(Allocator_Mode::ALLOCATE, sizeof(T), 0, nullptr, allocator.data);
|
||||
|
||||
@ -105,20 +103,19 @@ force_inline void Delete (Allocator allocator, void* memory) {
|
||||
// current allocator on the context.
|
||||
// For Resizes and Deletes, use internal_realloc and internal_free.
|
||||
|
||||
template <typename T> void reset_struct (T* src) {
|
||||
(*src) = T();
|
||||
}
|
||||
// #NOTE: Initialize<T> and reset_struct<T> are exactly the same!
|
||||
template <typename T> force_inline void Initialize (T* memory) { (*memory) = T(); }
|
||||
template <typename T> force_inline void reset_struct (T* src) { (*src) = T(); }
|
||||
|
||||
template <typename T> void zero_struct(T* src) {
|
||||
template <typename T> void zero_struct (T* src) {
|
||||
memset(src, 0, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T> void poison_struct(T* src) {
|
||||
template <typename T> void poison_struct (T* src) {
|
||||
memset(src, 0xCD, sizeof(T));
|
||||
}
|
||||
|
||||
template <typename T> T* copy_struct(T* src) {
|
||||
template <typename T> T* copy_struct (T* src) {
|
||||
T* dst = New<T>(false);
|
||||
memcpy(dst, src, sizeof(T));
|
||||
}
|
||||
|
||||
|
||||
@ -209,9 +209,9 @@ struct Auto_Reset {
|
||||
this->starting_point = arena->current_point;
|
||||
}
|
||||
|
||||
// #TODO: Implement with ExpandableArena
|
||||
// #TODO: Implement with ExpandableArena (probably just use the same implementation as Auto_Release?)
|
||||
// Auto_Reset(ExpandableArena* arena_ex) {
|
||||
// Auto_Reset((Arena*)arena_ex);
|
||||
//
|
||||
// }
|
||||
|
||||
~Auto_Reset() {
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
constexpr s64 ARRAY_ARENA_START_OFFSET = 64;
|
||||
|
||||
template <typename T>
|
||||
struct ArenaArray { // downcasts to an ArrayView.
|
||||
struct ArenaArray { // #downcasts to an ArrayView.
|
||||
using ValueType = T;
|
||||
s64 count;
|
||||
T* data;
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
MSVC_RUNTIME_CHECKS_OFF
|
||||
|
||||
template <typename T>
|
||||
struct Array { // downcasts to an ArrayView.
|
||||
struct Array { // #downcasts to an ArrayView.
|
||||
using ValueType = T;
|
||||
s64 count;
|
||||
T* data;
|
||||
@ -249,12 +249,17 @@ struct ArrayView {
|
||||
s64 count;
|
||||
T* data;
|
||||
|
||||
// #TODO: Add initializers ArrayView<u8> from string, ArrayView<T> from ArenaArray<T>
|
||||
ArrayView(Array<T> array) { // auto-downcast from Array<T>
|
||||
ArrayView(Array<T> array) { // auto-#downcast from Array<T>
|
||||
count = array.count;
|
||||
data = array.data;
|
||||
}
|
||||
|
||||
// Unfortunately we need ArenaArray to be declared ahead. God, I hate C++.
|
||||
// ArrayView(ArenaArray<T> array) { // auto-#downcast from ArenaArray<T>
|
||||
// count = array.count;
|
||||
// data = array.data;
|
||||
// }
|
||||
|
||||
ArrayView() { count = 0; data = nullptr; }
|
||||
|
||||
ArrayView(s64 new_count, bool initialize=true) {
|
||||
|
||||
@ -192,7 +192,6 @@ force_inline s64 Next_Power_Of_Two(s64 v) {
|
||||
#define context_allocator() thread_context()->allocator
|
||||
#define context_logger() &thread_context()->logger
|
||||
|
||||
// #TODO #constexpr #MATH - make these constexpr
|
||||
// CHECK THAT THESE ARE CORRECT!
|
||||
constexpr f32 TAU = 6.283185f;
|
||||
constexpr f64 TAU_64 = 6.28318530717958648;
|
||||
|
||||
@ -1,6 +1,3 @@
|
||||
// #NOTE: To keep things simple, all allocations for Error should be via GPAllocator.
|
||||
// We really allocate two things: the Error struct and the error string copy.
|
||||
|
||||
#define NO_ERROR nullptr
|
||||
|
||||
enum class ErrorClass: s32 {
|
||||
@ -19,6 +16,8 @@ struct Error {
|
||||
s32 source_line;
|
||||
string file_path;
|
||||
string function_name;
|
||||
string thread_name;
|
||||
f64 timestamp;
|
||||
|
||||
// Linked list to errors
|
||||
Error* previous_error; // if we're passing errors up the callstack.
|
||||
@ -70,10 +69,6 @@ Error* new_error (ErrorClass severity, string error_string) {
|
||||
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, ...) {
|
||||
auto tctx = thread_context();
|
||||
Assert(tctx != nullptr);
|
||||
@ -100,10 +95,30 @@ void Log_Error_2 (string file_path, string function_name, s32 line_number, Error
|
||||
// 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;
|
||||
error->thread_name = copy_string(tctx->thread_name);
|
||||
error->timestamp = GetUnixTimestamp();
|
||||
|
||||
push_error(tctx, error);
|
||||
}
|
||||
|
||||
Error* copy_error (Thread_Context* tctx, Error* old_error) {
|
||||
push_arena(tctx->error_arena);
|
||||
|
||||
Error* error = new_error(old_error->severity, to_string(old_error));
|
||||
|
||||
error->thread_id = old_error->thread_id;
|
||||
error->source_line = old_error->source_line;
|
||||
error->file_path = copy_string(old_error->file_path);
|
||||
error->function_name = copy_string(old_error->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;
|
||||
error->thread_name = copy_string(old_error->thread_name);
|
||||
error->timestamp = old_error->timestamp;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void push_error (Thread_Context* tctx, Error* new_error) {
|
||||
Assert(tctx == thread_context()); // Not a real assert, just wondering if we'll ever call this with a non-local context?
|
||||
Assert(new_error != nullptr);
|
||||
@ -191,7 +206,8 @@ void push_errors_to_parent_thread (Thread_Context* tctx) {
|
||||
Assert(tctx->parent_thread_context);
|
||||
|
||||
while (tctx->first_error) {
|
||||
push_error_no_context(tctx->parent_thread_context, tctx->first_error);
|
||||
Error* error_copy = copy_error(tctx->parent_thread_context, tctx->first_error);
|
||||
push_error_no_context(tctx->parent_thread_context, error_copy);
|
||||
clear_error(tctx, tctx->first_error);
|
||||
}
|
||||
}
|
||||
@ -206,9 +222,11 @@ ArrayView<Error*> get_all_errors (Thread_Context* tctx) {
|
||||
}
|
||||
|
||||
|
||||
for_each(t, tctx->child_threads) {
|
||||
// #TODO: also recurse through child threads?
|
||||
}
|
||||
// #TODO(Low priority): also recurse through child threads?
|
||||
// NOTE: I don't think we actually want this, because we merge
|
||||
// our errors on the main thread when we thread_deinit.
|
||||
// for_each(t, tctx->child_threads) {
|
||||
// }
|
||||
|
||||
return error_array;
|
||||
}
|
||||
|
||||
@ -51,8 +51,9 @@ u32 table_hash_function_knuth (void* key, s64 size) {
|
||||
u32 string_hash_function_fnv1a (void* key, s64 size) {
|
||||
Assert(size == sizeof(string));
|
||||
string key_as_string = *((string*)key);
|
||||
// #TODO It should be xor folded to the desired range rather than shifted.
|
||||
return (u32)(fnv1a_hash_any(key_as_string.data, key_as_string.count));
|
||||
u64 hash_u64 = fnv1a_hash_any(key_as_string.data, key_as_string.count);
|
||||
// It should be xor folded to the desired range rather than shifted:
|
||||
return (u32)(hash_u64 ^ (hash_u64 >> 32));
|
||||
}
|
||||
|
||||
bool u64_keys_match (void* key1, void* key2) {
|
||||
|
||||
@ -1,30 +1,5 @@
|
||||
// #NOTE: This Hash Table is borrowed from Jai's implementation! (With some tweaks)
|
||||
// I made my own version that's arena-backed, but the mechanisms are the same.
|
||||
|
||||
// s32 drive_count = 0;
|
||||
// for (s64 i = 0; i < drive_table->allocated; i += 1) {
|
||||
// Table_Entry<string, OS_Drive>* entry = &drive_table->entries[i]; // we should take ptr here if we want to modify?
|
||||
// if (entry->hash > HASH_TABLE_FIRST_VALID_HASH) {
|
||||
// // #TODO #MOVE THIS + maybe don't check this every frame!
|
||||
// // entry->value.is_present = Win32_Drive_Exists(entry->value.label);
|
||||
// if (entry->value.label.data == nullptr) continue;
|
||||
|
||||
// Text(" > [%d] drive letter: %s (is_present: %d)", drive_count + 1, entry->value.label.data, entry->value.is_present);
|
||||
// drive_count += 1;
|
||||
// SameLine();
|
||||
// push_allocator(temp());
|
||||
|
||||
// if (Button(format_cstring("Read NTFS MFT Raw##%s", entry->value.label.data))) {
|
||||
// push_arena(thread_context()->arena);
|
||||
// // auto_release(thread_context()->arena);
|
||||
// auto dfs = NTFS_MFT_read_raw(entry->value.label);
|
||||
// if (dfs == nullptr) {
|
||||
// log("[NTFS_MFT_read_raw] operation failed");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
typedef u32 hash_result;
|
||||
|
||||
constexpr hash_result HASH_TABLE_FIRST_VALID_HASH = 2;
|
||||
@ -198,8 +173,6 @@ template <typename T, typename U> void table_resize (Table<T, U>* table, s64 slo
|
||||
return;
|
||||
}
|
||||
|
||||
// #TODO: When you resize you need to reinsert all the values, so we
|
||||
// need a temporary copy of the original data:
|
||||
ArrayView<Table_Entry<T, U>> old_entries = table->entries;
|
||||
|
||||
s64 n = Next_Power_Of_Two(slots_to_allocate);
|
||||
@ -290,10 +263,10 @@ template <typename T, typename U> bool table_remove (Table<T, U>* table, T key,
|
||||
return false;
|
||||
}
|
||||
|
||||
// #TODO: We should allow setting an allocator instead of defaulting to temp()?
|
||||
template <typename T, typename U> ArrayView<U> table_find_multiple (Table<T, U>* table, T key, U* value) {
|
||||
Array<U> results;
|
||||
results.allocator = temp();
|
||||
// #NOTE: We should allow setting an allocator instead of defaulting to temp()?
|
||||
// results.allocator = temp();
|
||||
|
||||
// #Walk_Table
|
||||
u32 mask = (u32)(table->allocated - 1);
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// #TODO #Logger module
|
||||
// #TODO(Low priority) #Logger module
|
||||
// [ ] Add colored prints (See: Print_Color.jai)
|
||||
|
||||
// See Logger.jai in our jiim-dev-gui project for how to do fancy colored text.
|
||||
|
||||
@ -54,7 +54,7 @@ force_inline void AddString16 (Serializer* serializer, string s) {
|
||||
AddArray_NoSize(serializer, to_view(s));
|
||||
}
|
||||
|
||||
struct Deserializer { // downcasts to ArrayView<u8>
|
||||
struct Deserializer { // #downcasts to ArrayView<u8>
|
||||
s64 count;
|
||||
u8* data;
|
||||
s64 cursor;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
// #TODO #string module
|
||||
// [ ] I'm debating if string type should automatically null-terminate.
|
||||
// I personally do not like it, and think we should temp-copy c-strings as they're needed.
|
||||
// #NOTE: All string building, printing and copying operations SHOULD null-terminate the
|
||||
// strings for backwards compatibility reasons. #FIX if something doesn't follow this rule!
|
||||
bool is_valid (string s) {
|
||||
return (s.data != nullptr && s.count > 0);
|
||||
}
|
||||
@ -309,4 +308,4 @@ string trim_right (string s, string chars, bool replace_with_zeros) {
|
||||
}
|
||||
|
||||
return string_view(s, 0, count);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
// #TODO: #strings:
|
||||
// [x] Always null-terminate strings!
|
||||
// [ ] How do I accept variadic arguments of any type to my print function?
|
||||
// [ ] see: #Parsing stuff:
|
||||
// [?] How do I accept variadic arguments of any type to my print function?
|
||||
// [ ] Need to sort out how formatted strings and string builders are allocated
|
||||
// [ ] Separate functions for temp alloc (tprint??)
|
||||
// [ ] I should also put path manipulation here or in a separate file?
|
||||
@ -82,7 +82,6 @@ force_inline string string_view (string s, s64 start_index, s64 view_count);
|
||||
bool strings_match (string first_string, string second_string);
|
||||
|
||||
// #Unicode
|
||||
// #TODO: Make a raw version that returns the raw pointer?
|
||||
string wide_to_utf8 (u16* source, s32 length=-1);
|
||||
wstring utf8_to_wide (string source);
|
||||
|
||||
|
||||
@ -82,6 +82,6 @@ void graphics_set_render_target (Window_Info window_info) {
|
||||
graphics->texture_render_target = nullptr;
|
||||
|
||||
graphics->current_window = window_info;
|
||||
// #TODO: graphics_update_window ::
|
||||
// #TODO: #Graphics graphics_update_window ::
|
||||
|
||||
}
|
||||
@ -87,7 +87,7 @@ ArrayView<OS_Drive*> os_get_available_drives () {
|
||||
Table_Entry<string, OS_Drive*>* entry = &drive_table->entries[i]; // we should take ptr here if we want to modify?
|
||||
|
||||
if (entry->hash > HASH_TABLE_FIRST_VALID_HASH) {
|
||||
if (entry->value->label.data == nullptr) continue; // Some volumes may not be real and therefore have no label.
|
||||
if (entry->value->label.data == nullptr || !entry->value->is_present) continue; // Some volumes may not be real and therefore have no label.
|
||||
|
||||
array_add(drives, entry->value);
|
||||
}
|
||||
@ -264,13 +264,15 @@ internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name=
|
||||
s64 this_thread_index = InterlockedIncrement(&next_thread_index);
|
||||
// 2. #NewContext Setup NEW thread local context
|
||||
ExpandableArena* arena_ex = expandable_arena_new(Arena_Reserve::Size_64M, 16);
|
||||
push_arena(arena_ex);
|
||||
|
||||
// #NOTE: we don't assign thread_local_context until we hit the #thread_entry_point
|
||||
thread->context = New<Thread_Context>(allocator(arena_ex));
|
||||
thread->context = New<Thread_Context>();
|
||||
thread->context->temp = expandable_arena_new(Arena_Reserve::Size_2M, 16);
|
||||
thread->context->arena = arena_ex;
|
||||
thread->context->allocator = allocator(arena_ex);
|
||||
thread->context->thread_idx = (s32)this_thread_index;
|
||||
// #NOTE: This will disappear once the thread is de-initted. If we want this string, copy it!
|
||||
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);
|
||||
@ -296,8 +298,8 @@ internal void thread_deinit (Thread* thread, bool zero_thread=false) {
|
||||
|
||||
if (thread->os_thread.windows_thread) {
|
||||
CloseHandle(thread->os_thread.windows_thread);
|
||||
thread->os_thread.windows_thread = nullptr;
|
||||
}
|
||||
thread->os_thread.windows_thread = nullptr;
|
||||
|
||||
array_reset(*thread->context->log_builder);
|
||||
free_string_builder(thread->context->log_builder);
|
||||
@ -392,7 +394,7 @@ internal string get_error_string (OS_Error_Code error_code) {
|
||||
return trim_right(result);
|
||||
}
|
||||
|
||||
internal void log_error_code_and_string () { // #TODO: replace with call to log_error_with_code
|
||||
internal void os_log_error () {
|
||||
OS_Error_Code error_code = GetLastError();
|
||||
log_error(" > GetLastError code: %d, %s", error_code, get_error_string(error_code).data);
|
||||
}
|
||||
@ -428,7 +430,7 @@ 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`", file_path);
|
||||
log_error_code_and_string();
|
||||
os_log_error();
|
||||
}
|
||||
|
||||
File file;
|
||||
@ -445,7 +447,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.");
|
||||
log_error_code_and_string();
|
||||
os_log_error();
|
||||
if (bytes_read_count) (*bytes_read_count) = 0;
|
||||
return false;
|
||||
}
|
||||
@ -624,8 +626,8 @@ monitor_enum_proc (HMONITOR hMonitor, HDC hdc, RECT* rect, LPARAM data) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// #TODO: how do I setup a callback if monitors configuration is changed?
|
||||
// we handle WM_DISPLAYCHANGE or WM_DEVICECHANGE and call EnumDisplayMonitors
|
||||
// #TODO(Low Priority): how do I setup a callback if monitors configuration is changed?
|
||||
// we handle WM_DISPLAYCHANGE or WM_DEVICECHANGE and call EnumDisplayMonitors again.
|
||||
internal void os_enumerate_monitors () {
|
||||
if (!global_win32_state.system_info.monitors_enumerated) {
|
||||
// should reset array?
|
||||
@ -979,7 +981,7 @@ bool Win32_Discover_Drives () {
|
||||
Table<string, OS_Drive*>* drive_table = get_drive_table();
|
||||
if (!drive_table->allocated) {
|
||||
drive_table->allocator = GPAllocator();
|
||||
// #TODO: #hash_table need a macro for string keys!
|
||||
// #TODO(Low priority): #hash_table need a macro for initializing with string keys!
|
||||
drive_table->hash_function = string_hash_function_fnv1a;
|
||||
drive_table->compare_function = string_keys_match;
|
||||
s64 slots_to_allocate = 64;
|
||||
@ -990,7 +992,7 @@ bool Win32_Discover_Drives () {
|
||||
u32 result_length = GetLogicalDriveStringsW(1024, (LPWSTR)lpBuf);
|
||||
if (!result_length) {
|
||||
log_error("GetLogicalDriveStringsW failed!");
|
||||
log_error_code_and_string();
|
||||
os_log_error();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1048,7 +1050,7 @@ bool Win32_Discover_Drives () {
|
||||
log(" - file_system: %s", wide_to_utf8(file_system_name).data);
|
||||
} else {
|
||||
log_error("GetVolumeInformationW failed! (drive label: %s)", drive_label.data);
|
||||
log_error_code_and_string();
|
||||
os_log_error();
|
||||
drive->is_present = false;
|
||||
}
|
||||
}
|
||||
@ -1072,7 +1074,7 @@ string Win32_drive_letter (string any_path) {
|
||||
return copy_string({1, any_path.data});
|
||||
}
|
||||
|
||||
// #TODO: #window_creation
|
||||
// #TODO: #window_creation #window_manipulation
|
||||
// [ ] resize_window
|
||||
// [ ] position_window
|
||||
// [ ] toggle_fullscreen
|
||||
|
||||
@ -164,7 +164,7 @@ Error* NTFS_MFT_read_raw (OS_Drive* drive) {
|
||||
|
||||
if (file_handle == INVALID_HANDLE_VALUE) {
|
||||
log_error("CreateFileA failed on target %s", create_file_target.data);
|
||||
log_error_code_and_string();
|
||||
os_log_error();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -272,7 +272,7 @@ Error* NTFS_MFT_read_raw (OS_Drive* drive) {
|
||||
file.is_directory = fileRecord->isDirectory;
|
||||
// We need to get size from the data attribute
|
||||
|
||||
// #TODO: continue from here!
|
||||
// #TODO: #continue from here!
|
||||
mft->file_count += 1;
|
||||
}
|
||||
}
|
||||
@ -292,7 +292,7 @@ Error* NTFS_MFT_read_raw (OS_Drive* drive) {
|
||||
|
||||
CloseHandle(file_handle);
|
||||
|
||||
log("Found %lld files (bytes_accessed: %s)", mft->file_count, format_bytes(mft->bytes_accessed).data);
|
||||
log_none("Found %lld files (bytes_accessed: %s)", mft->file_count, format_bytes(mft->bytes_accessed).data);
|
||||
|
||||
drive->file_count = mft->file_count;
|
||||
drive->bytes_accessed = mft->bytes_accessed;
|
||||
|
||||
@ -44,7 +44,7 @@ internal void Main_Entry_Point (int argc, WCHAR **argv) { // #entry_point
|
||||
graphics_set_render_target(get_main_window());
|
||||
|
||||
// 3. Init Graphics (DX11 or OpenGL3)
|
||||
// #TODO: #Main - `Main_Entry_Point`
|
||||
// #TODO: #Graphics#Main - `Main_Entry_Point`
|
||||
|
||||
// 4. [ ] Setup Mouse and Keyboard Inputs
|
||||
// 5. [ ] Launch second thread; thread groups
|
||||
|
||||
78
src/Ex1.cpp
78
src/Ex1.cpp
@ -12,7 +12,9 @@ struct Explorer {
|
||||
};
|
||||
|
||||
struct Ex1_NTFS_Enumeration {
|
||||
bool initialized;
|
||||
b32 initialized;
|
||||
b32 threads_started;
|
||||
|
||||
ArrayView<Thread> threads;
|
||||
Array<Thread*> threads_in_flight;
|
||||
};
|
||||
@ -22,6 +24,19 @@ global ExplorerUI explorer_ui;
|
||||
global Explorer explorer;
|
||||
global Ex1_NTFS_Enumeration ex1_ntfs;
|
||||
|
||||
void ntfs_create_enumeration_threads (s32 thread_count) {
|
||||
if (!ex1_ntfs.initialized) { Timed_Block_Print("Thread initialization (ntfs)");
|
||||
ex1_ntfs.initialized = true;
|
||||
ex1_ntfs.threads = ArrayView<Thread>(thread_count);
|
||||
ex1_ntfs.threads_in_flight.allocator = GPAllocator();
|
||||
for_each(t, ex1_ntfs.threads) {
|
||||
string thread_name = format_string("ntfs_enumeration_thread#%d", t);
|
||||
bool success = thread_init(&ex1_ntfs.threads[t], ntfs_enumeration_thread_proc, thread_name);
|
||||
Assert(success);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define HOTKEY_ID_BRING_TO_FOREGROUND 1
|
||||
#define VK_SPACE_KEY_CODE 0x20
|
||||
// #define HOTKEY_ID_HIDE_TITLEBAR
|
||||
@ -67,13 +82,14 @@ void Ex1_Control_Panel () { using namespace ImGui;
|
||||
Table<string, OS_Drive*>* drive_table = get_drive_table();
|
||||
|
||||
Begin("Control Panel");
|
||||
if (Button("Debug break")) { debug_break(); }
|
||||
if (Button("Discover drives") || !table_is_valid(drive_table)) {
|
||||
Win32_Discover_Drives();
|
||||
}
|
||||
|
||||
Text("drive_table is valid: %d", table_is_valid(drive_table));
|
||||
push_allocator(temp());
|
||||
ArrayView<OS_Drive*> drives = os_get_available_drives();
|
||||
ArrayView<OS_Drive*> drives = os_get_available_drives(); // only includes drives that are ready.
|
||||
|
||||
for_each(i, drives) {
|
||||
OS_Drive* drive = drives[i];
|
||||
@ -90,36 +106,24 @@ void Ex1_Control_Panel () { using namespace ImGui;
|
||||
// }
|
||||
}
|
||||
|
||||
if (drives.count > 0) {
|
||||
if (!ex1_ntfs.initialized) { Timed_Block_Print("Thread initialization (ntfs)");
|
||||
push_allocator(GPAllocator());
|
||||
ex1_ntfs.initialized = true;
|
||||
s32 cpu_core_count = os_cpu_physical_core_count();
|
||||
ex1_ntfs.threads = ArrayView<Thread>(cpu_core_count);
|
||||
ex1_ntfs.threads_in_flight.allocator = GPAllocator();
|
||||
for_each(t, ex1_ntfs.threads) {
|
||||
string thread_name = format_string("ntfs_enumeration_thread#%d", t);
|
||||
bool success = thread_init(&ex1_ntfs.threads[t], ntfs_enumeration_thread_proc, thread_name);
|
||||
Assert(success);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (drives.count > 0 && ex1_ntfs.initialized && Button("Enumerate all NTFS drives")) {
|
||||
if (drives.count > 0 && Button("Enumerate all NTFS drives")) { // && ex1_ntfs.initialized
|
||||
// if drive count exceeds the number of threads, we need to group them so each thread
|
||||
// can enumerate multiple drives.
|
||||
// We need to distribute the drives across our available threads:
|
||||
// #TODO #is_present - drive_count should only include if `drive->is_present`.
|
||||
push_allocator(GPAllocator());
|
||||
Array<ArrayView<OS_Drive*>> drive_split;
|
||||
s32 thread_count = (s32)ex1_ntfs.threads.count;
|
||||
drive_split.allocator = GPAllocator();
|
||||
|
||||
if (drives.count > thread_count) {
|
||||
drive_split.allocator = temp(); // this is only needed for this frame
|
||||
|
||||
if (drives.count > os_cpu_physical_core_count()) {
|
||||
s32 thread_count = os_cpu_physical_core_count();
|
||||
array_resize(drive_split, thread_count);
|
||||
ntfs_create_enumeration_threads(thread_count);
|
||||
|
||||
s32 threads_to_create = thread_count;
|
||||
s64 drives_per_thread = (drives.count / thread_count);
|
||||
s64 remainder = drives.count % thread_count;
|
||||
s64 current_drive = 0;
|
||||
push_allocator(GPAllocator());
|
||||
array_resize(drive_split, thread_count);
|
||||
|
||||
for_each(d, drive_split) {
|
||||
if (d == drive_split.count) {
|
||||
drive_split[d] = ArrayView<OS_Drive*>(remainder);
|
||||
@ -135,7 +139,9 @@ void Ex1_Control_Panel () { using namespace ImGui;
|
||||
|
||||
debug_break(); // #TODO: Check that the work has been distributed correctly.
|
||||
} else { // more threads than drives, or same amount
|
||||
s32 thread_count = (s32)drives.count;
|
||||
array_resize(drive_split, drives.count);
|
||||
ntfs_create_enumeration_threads(thread_count);
|
||||
|
||||
for_each(d, drives) {
|
||||
auto drive = drives[d];
|
||||
@ -147,6 +153,7 @@ void Ex1_Control_Panel () { using namespace ImGui;
|
||||
|
||||
s64 active_thread_count = drive_split.count;
|
||||
|
||||
ex1_ntfs.threads_started = true;
|
||||
for (s64 t = 0; t < active_thread_count; t += 1) {
|
||||
Thread* thread = &ex1_ntfs.threads[t];
|
||||
Arena* thread_arena = next_arena(Arena_Reserve::Size_64K);
|
||||
@ -159,19 +166,30 @@ void Ex1_Control_Panel () { using namespace ImGui;
|
||||
}
|
||||
}
|
||||
|
||||
if (ex1_ntfs.threads_started && !ex1_ntfs.threads_in_flight.count) {
|
||||
// All threads are complete, we're free to clean up remaining memory
|
||||
push_allocator(GPAllocator());
|
||||
array_free(ex1_ntfs.threads);
|
||||
array_free(ex1_ntfs.threads_in_flight);
|
||||
|
||||
// Instead maybe we should just memset this to zero.
|
||||
reset_struct(&ex1_ntfs);
|
||||
}
|
||||
|
||||
if (ex1_ntfs.threads_in_flight.count) {
|
||||
Text("Threads in flight: %d", ex1_ntfs.threads_in_flight.count);
|
||||
// keep track of which indices to remove!
|
||||
|
||||
for_each(t, ex1_ntfs.threads_in_flight) {
|
||||
if (thread_is_done(ex1_ntfs.threads_in_flight[t])) {
|
||||
push_allocator(GPAllocator());
|
||||
Thread* thread = ex1_ntfs.threads_in_flight[t];
|
||||
auto task = thread_task(NTFS_Enumeration_Task);
|
||||
array_free(task->drives);
|
||||
// internal_free(
|
||||
// make sure to retreive any data you need to from here!
|
||||
release_arena(task->pool);
|
||||
|
||||
// #TODO Before #deiniting thread we SHOULD copy the errors from the
|
||||
// thread before it's deleted forever.
|
||||
|
||||
thread_deinit(ex1_ntfs.threads_in_flight[t], true);
|
||||
thread_deinit(ex1_ntfs.threads_in_flight[t], false);
|
||||
array_unordered_remove_by_index(ex1_ntfs.threads_in_flight, t);
|
||||
t -= 1; // check this element index again!
|
||||
}
|
||||
|
||||
@ -298,6 +298,7 @@ global f32 imgui_font_sizes[6] = {18, 24, 30, 36, 42, 48};
|
||||
global ImGui_Font_Info imgui_default_font;
|
||||
|
||||
bool ImGui_Default_Font_Loaded () {
|
||||
// #TODO #font_crash Should only check once at the top of the frame!
|
||||
return imgui_default_font.sizes.count > 0;
|
||||
}
|
||||
|
||||
@ -306,10 +307,6 @@ f32 ImGui_Default_Font_Current_Size () {
|
||||
}
|
||||
|
||||
void ImGui_Push_Default_Font () {
|
||||
// #TODO: Replace these asserts so it just returns if not present!
|
||||
// And just warn in the UI that a font is missing.
|
||||
Assert(imgui_default_font.sizes.count > 0);
|
||||
Assert(imgui_default_font.current_size >= 0 && imgui_default_font.current_size < imgui_default_font.sizes.count);
|
||||
if (ImGui_Default_Font_Loaded()) {
|
||||
ImFont* font_data = imgui_default_font.sizes[imgui_default_font.current_size].data;
|
||||
f32 unscaled_font_size = imgui_default_font.sizes[imgui_default_font.current_size].font_size;
|
||||
@ -318,7 +315,8 @@ void ImGui_Push_Default_Font () {
|
||||
}
|
||||
|
||||
void ImGui_Pop_Default_Font () {
|
||||
// This will break if we load font mid-frame! don't do this.
|
||||
// #font_crash: This will break if we load font mid-frame! don't do this.
|
||||
// We should only check this once at the top of the frame!
|
||||
if (ImGui_Default_Font_Loaded()) {
|
||||
ImGui::PopFont();
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user