Lots of small changes
This commit is contained in:
parent
6970a59c35
commit
619cd76ea9
@ -1,7 +1,7 @@
|
|||||||
#include "lib_main.cpp"
|
#include "lib_main.cpp"
|
||||||
|
|
||||||
// Toggles:
|
// Toggles:
|
||||||
#define BASE_RUN_TESTS 1
|
#define BASE_RUN_TESTS 0
|
||||||
#define BUILD_EXPLORER_APP_WIN32 1
|
#define BUILD_EXPLORER_APP_WIN32 1
|
||||||
#define BUILD_CUSTOM_GUI 0
|
#define BUILD_CUSTOM_GUI 0
|
||||||
|
|
||||||
|
|||||||
@ -180,17 +180,8 @@ s64 reserve_size (Arena_Reserve ar) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr s64 Arena_Sizes[6] = {
|
|
||||||
64LL * 1024,
|
|
||||||
2LL * 1024 * 1024,
|
|
||||||
64LL * 1024 * 1024,
|
|
||||||
2LL * 1024 * 1024 * 1024,
|
|
||||||
64LL * 1024 * 1024 * 1024,
|
|
||||||
2LL * 1024 * 1024 * 1024 * 1024,
|
|
||||||
};
|
|
||||||
|
|
||||||
Arena_Reserve next_reserve_size (s64 size) {
|
Arena_Reserve next_reserve_size (s64 size) {
|
||||||
for (u8 i = 0; i < 6; i += 1) {
|
for (u8 i = 0; i < Arena_Reserve_Count; i += 1) {
|
||||||
if (size <= Arena_Sizes[i]) {
|
if (size <= Arena_Sizes[i]) {
|
||||||
return (Arena_Reserve)i;
|
return (Arena_Reserve)i;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ constexpr u16 ARENA_DEFAULT_ALIGNMENT = CPU_REGISTER_WIDTH_BYTES;
|
|||||||
|
|
||||||
#define ARENA_DEBUG BUILD_DEBUG
|
#define ARENA_DEBUG BUILD_DEBUG
|
||||||
|
|
||||||
|
constexpr s32 Arena_Reserve_Count = 7;
|
||||||
enum class Arena_Reserve: u8 {
|
enum class Arena_Reserve: u8 {
|
||||||
Size_64K = 0, // these are used as indices in Arena_Free_List!
|
Size_64K = 0, // these are used as indices in Arena_Free_List!
|
||||||
Size_2M = 1,
|
Size_2M = 1,
|
||||||
@ -21,6 +22,16 @@ enum class Arena_Reserve: u8 {
|
|||||||
Size_64T = 6,
|
Size_64T = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr s64 Arena_Sizes[Arena_Reserve_Count] = {
|
||||||
|
64LL * 1024,
|
||||||
|
2LL * 1024 * 1024,
|
||||||
|
64LL * 1024 * 1024,
|
||||||
|
2LL * 1024 * 1024 * 1024,
|
||||||
|
64LL * 1024 * 1024 * 1024,
|
||||||
|
2LL * 1024 * 1024 * 1024 * 1024,
|
||||||
|
64LL * 1024 * 1024 * 1024 * 1024,
|
||||||
|
};
|
||||||
|
|
||||||
enum class Arena_Flags: u8 {
|
enum class Arena_Flags: u8 {
|
||||||
None = 0,
|
None = 0,
|
||||||
Chained = 0x01,
|
Chained = 0x01,
|
||||||
@ -61,18 +72,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);
|
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_Free_List.cpp)
|
// 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<Arena*> free_table[6];
|
|
||||||
|
|
||||||
#if ARENA_DEBUG
|
|
||||||
Array<Arena*> in_flight[6];
|
|
||||||
#endif
|
|
||||||
b32 initialized;
|
|
||||||
};
|
|
||||||
|
|
||||||
void initialize_arena_table (Allocator allocator);
|
void initialize_arena_free_list (Allocator allocator);
|
||||||
Arena* next_arena (Arena_Reserve reserve_size);
|
Arena* next_arena (Arena_Reserve reserve_size);
|
||||||
void release_arena (Arena* arena, bool delete_extra_pages=true);
|
void release_arena (Arena* arena, bool delete_extra_pages=true);
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,17 @@
|
|||||||
// There should be some parameters regarding what the upper limit for idle
|
// 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
|
// committed pages should be and a heuristic for maximum number of arenas waiting
|
||||||
|
|
||||||
|
struct Arena_Free_List {
|
||||||
|
Mutex mutex;
|
||||||
|
s32 in_flight_count[Arena_Reserve_Count];
|
||||||
|
Array<Arena*> free_table[Arena_Reserve_Count];
|
||||||
|
|
||||||
|
#if ARENA_DEBUG
|
||||||
|
Array<Arena*> in_flight[Arena_Reserve_Count];
|
||||||
|
#endif
|
||||||
|
b32 initialized;
|
||||||
|
};
|
||||||
|
|
||||||
global Arena_Free_List* arena_free_list;
|
global Arena_Free_List* arena_free_list;
|
||||||
|
|
||||||
// Only call once from main thread!
|
// Only call once from main thread!
|
||||||
@ -12,7 +23,7 @@ void initialize_arena_free_list (Allocator allocator) {
|
|||||||
if (arena_free_list->initialized)
|
if (arena_free_list->initialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
for (s32 i = 0; i < 6; i += 1) {
|
for (s32 i = 0; i < Arena_Reserve_Count; i += 1) {
|
||||||
arena_free_list->in_flight_count[i] = 0;
|
arena_free_list->in_flight_count[i] = 0;
|
||||||
arena_free_list->free_table[i].allocator = allocator;
|
arena_free_list->free_table[i].allocator = allocator;
|
||||||
array_reserve(arena_free_list->free_table[i], 64);
|
array_reserve(arena_free_list->free_table[i], 64);
|
||||||
@ -75,5 +86,14 @@ void release_arena (Arena* arena, bool delete_extra_pages) {
|
|||||||
// arenas_to_delete_count -= 1;
|
// arenas_to_delete_count -= 1;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
s64 committed_bytes (ArrayView<Arena*> arenas) {
|
||||||
|
s64 sum = 0;
|
||||||
|
|
||||||
|
for (s64 i = 0; i < arenas.count; i += 1) {
|
||||||
|
sum += arena_usage_committed_bytes(arenas[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,14 +62,14 @@ void arena_delete (Arena* arena) {
|
|||||||
if (!is_valid(arena)) return;
|
if (!is_valid(arena)) return;
|
||||||
bool arena_was_boostrapped = (arena->flags & Arena_Flags::Is_Bootstrapped) == Arena_Flags::Is_Bootstrapped;
|
bool arena_was_boostrapped = (arena->flags & Arena_Flags::Is_Bootstrapped) == Arena_Flags::Is_Bootstrapped;
|
||||||
|
|
||||||
VirtualFree(arena->memory_base, 0, MEM_RELEASE);
|
// s64 size_tmp = reserve_size(arena);
|
||||||
|
|
||||||
s64 size_tmp = reserve_size(arena);
|
|
||||||
// printf("Releasing range %p:%p (size: %llu)\n", arena->memory_base, (u8*)arena->memory_base + size_tmp, size_tmp);
|
// printf("Releasing range %p:%p (size: %llu)\n", arena->memory_base, (u8*)arena->memory_base + size_tmp, size_tmp);
|
||||||
|
|
||||||
if (!arena_was_boostrapped) {
|
if (!arena_was_boostrapped) {
|
||||||
arena->memory_base = nullptr;
|
arena->memory_base = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VirtualFree(arena->memory_base, 0, MEM_RELEASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -190,7 +190,7 @@ void array_add (Array<T>& src, T new_item) {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
s64 array_find (Array<T>& src, T item) {
|
s64 array_find (Array<T>& src, T item) {
|
||||||
ForArray(i, src) {
|
for (s64 i = 0; i < src.count; i += 1) {
|
||||||
if (src[i] == item) return i;
|
if (src[i] == item) return i;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@ -169,12 +169,6 @@ force_inline s64 Next_Power_Of_Two(s64 v) {
|
|||||||
#define MSVC_RUNTIME_CHECKS_RESTORE
|
#define MSVC_RUNTIME_CHECKS_RESTORE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ForExpansions. Not sure if this is a good idea...
|
|
||||||
// ↓TODO(Low priority): Maybe remove these. I prefer verbose and clear over this.
|
|
||||||
#define ForArray(_idx_, _array_) for (s64 _idx_ = 0; _idx_ < (_array_).count; ++_idx_)
|
|
||||||
#define ForArrayStartingAt(_it_, _array_, _start_) for (s64 _it_ = _start_; _it_ < (_array_).count; _it_ += 1)
|
|
||||||
#define ForUpTo(_it_, _end_) for (s64 _it_ = 0; _it_ < _end_; _it_ += 1)
|
|
||||||
|
|
||||||
// Scoped Macros/Functions for auto_reset and auto_release
|
// Scoped Macros/Functions for auto_reset and auto_release
|
||||||
// usage `Auto_Reset guard(arena);` within a scope.
|
// usage `Auto_Reset guard(arena);` within a scope.
|
||||||
#define auto_reset(x) \
|
#define auto_reset(x) \
|
||||||
@ -324,3 +318,11 @@ struct Mutex_Lock_Guard {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Helper macros for raw arrays:
|
||||||
|
#define ArrayCount(array) sizeof(array) / sizeof(array[0])
|
||||||
|
// For-loop construct macros
|
||||||
|
#define for_each_index(_idx_, _until_) for (s64 _idx_ = 0; _idx_ < _until_; ++_idx_)
|
||||||
|
// For-loops for ArrayView<> compatible types
|
||||||
|
#define for_each(_idx_, _array_) for (s64 _idx_ = 0; _idx_ < (_array_).count; ++_idx_)
|
||||||
|
// #define for_each_starting_at(_it_, _array_, _start_) for (s64 _it_ = _start_; _it_ < (_array_).count; _it_ += 1)
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,30 @@
|
|||||||
// #NOTE: This Hash Table is borrowed from Jai's implementation! (With some tweaks)
|
// #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.
|
// 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;
|
typedef u32 hash_result;
|
||||||
|
|
||||||
constexpr hash_result HASH_TABLE_FIRST_VALID_HASH = 2;
|
constexpr hash_result HASH_TABLE_FIRST_VALID_HASH = 2;
|
||||||
|
|||||||
@ -281,4 +281,7 @@ string to_lower_copy (string s_orig) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define format_cstring(fmt, ...) \
|
||||||
|
(char*)format_string(fmt, ##__VA_ARGS__).data
|
||||||
@ -117,7 +117,7 @@ s64 thread_group_run (Thread* thread) {
|
|||||||
|
|
||||||
|
|
||||||
// Thread_Group API:
|
// Thread_Group API:
|
||||||
void init (Thread_Group* group, s32 group_thread_count, Thread_Group_Proc group_proc,
|
void thread_group_init (Thread_Group* group, s32 group_thread_count, Thread_Group_Proc group_proc,
|
||||||
bool enable_work_stealing = false) {
|
bool enable_work_stealing = false) {
|
||||||
// Set allocator if not already set:
|
// Set allocator if not already set:
|
||||||
if (!group->allocator.proc) {
|
if (!group->allocator.proc) {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// really hacky forward declares.
|
// really #hacky forward declares.
|
||||||
struct Work_Entry;
|
struct Work_Entry;
|
||||||
struct Worker_Info;
|
struct Worker_Info;
|
||||||
struct Work_List;
|
struct Work_List;
|
||||||
|
|||||||
@ -69,7 +69,7 @@ string format_cycles (u64 ticks) {
|
|||||||
return format_string("%1.2f %s", count_f64, units[unit_index].data);
|
return format_string("%1.2f %s", count_f64, units[unit_index].data);
|
||||||
}
|
}
|
||||||
|
|
||||||
string format_bytes (s64 bytes) {
|
string format_bytes (s64 bytes, s32 trailing_width = 3) {
|
||||||
string units[6] = { "B", "KB", "MB", "GB", "TB", "PB" };
|
string units[6] = { "B", "KB", "MB", "GB", "TB", "PB" };
|
||||||
f64 count_f64 = (f64)bytes;
|
f64 count_f64 = (f64)bytes;
|
||||||
s32 unit_index = 0;
|
s32 unit_index = 0;
|
||||||
@ -79,7 +79,16 @@ string format_bytes (s64 bytes) {
|
|||||||
unit_index += 1;
|
unit_index += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return format_string("%1.3f %s", count_f64, units[unit_index].data);
|
switch (trailing_width) {
|
||||||
|
case 0: return format_string("%.0f %s", count_f64, units[unit_index].data);
|
||||||
|
case 1: return format_string("%.1f %s", count_f64, units[unit_index].data);
|
||||||
|
case 2: return format_string("%.2f %s", count_f64, units[unit_index].data);
|
||||||
|
case 3: return format_string("%.3f %s", count_f64, units[unit_index].data);
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
Assert(trailing_width >= 0 && trailing_width <= 3);
|
||||||
|
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
struct timed_block_print {
|
struct timed_block_print {
|
||||||
|
|||||||
@ -6,8 +6,7 @@ void run_pre_setup_tests() {
|
|||||||
|
|
||||||
string string_literal_example = "Hello, I am a string literal.";
|
string string_literal_example = "Hello, I am a string literal.";
|
||||||
void run_post_setup_tests() {
|
void run_post_setup_tests() {
|
||||||
debug_break();
|
log_warning("Hello, I am a warning :), and I am a big number: %lld", (s64)2935088889357);
|
||||||
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("Hello, I am an error - %s", "I'm another string");
|
||||||
log_error("This is an error");
|
log_error("This is an error");
|
||||||
printf("Running post-setup tests...\n");
|
printf("Running post-setup tests...\n");
|
||||||
@ -40,7 +39,6 @@ void run_post_setup_tests() {
|
|||||||
|
|
||||||
print("Hello, I am just a printed message to stdout\n\n");
|
print("Hello, I am just a printed message to stdout\n\n");
|
||||||
|
|
||||||
|
|
||||||
// Testing file writes and reads:
|
// Testing file writes and reads:
|
||||||
print("Writing some nonsense to a file.\n");
|
print("Writing some nonsense to a file.\n");
|
||||||
bool success = write_entire_file("D:/TempLocal/junk.txt", to_view(result));
|
bool success = write_entire_file("D:/TempLocal/junk.txt", to_view(result));
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
// #TODO: #OS_Win32
|
// #TODO: #OS_Win32
|
||||||
// [ ] #Thread cleanup: in `thread_deinit` is there any requirement to cleanup child threads?
|
|
||||||
// [ ] #Exception handling code in `Win32_Exception_Filter`
|
// [ ] #Exception handling code in `Win32_Exception_Filter`
|
||||||
// [ ] #cpuid - enumerate CPUs and Thread count (current implementation doesn't work)
|
// [~] #Thread cleanup: in `thread_deinit` is there any requirement to cleanup child threads?
|
||||||
|
// - I think no? Threads should handle their own lifetimes, and the parent threads should ensure child threads are complete
|
||||||
|
// before terminating.
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
constexpr s64 FILETIME_TO_UNIX = 116444736000000000i64;
|
constexpr s64 FILETIME_TO_UNIX = 116444736000000000i64;
|
||||||
@ -26,6 +27,7 @@ s64 GetUnixTimestampNanoseconds () {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct OS_System_Info {
|
struct OS_System_Info {
|
||||||
|
// #cpuid
|
||||||
s32 logical_processor_count;
|
s32 logical_processor_count;
|
||||||
s32 physical_core_count;
|
s32 physical_core_count;
|
||||||
s32 primary_core_count;
|
s32 primary_core_count;
|
||||||
@ -40,7 +42,9 @@ struct OS_System_Info {
|
|||||||
Array<Monitor> monitors; // Back with GPAllocator
|
Array<Monitor> monitors; // Back with GPAllocator
|
||||||
|
|
||||||
// #Drives
|
// #Drives
|
||||||
Table<string, Win32_Drive> drives;
|
Table<string, OS_Drive> drives; // should we just store ptrs to OS_Drive? I think so..
|
||||||
|
// That way we can fetch the OS_Drive* and have the pointer be stable. Especially if it's b
|
||||||
|
// backed by an arena.
|
||||||
};
|
};
|
||||||
|
|
||||||
struct OS_Process_Info {
|
struct OS_Process_Info {
|
||||||
@ -126,7 +130,7 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) {
|
|||||||
info->process_id = GetCurrentProcessId();
|
info->process_id = GetCurrentProcessId();
|
||||||
}
|
}
|
||||||
// #cpuid
|
// #cpuid
|
||||||
/*{ OS_System_Info* info = &global_win32_state.system_info;
|
{ OS_System_Info* info = &global_win32_state.system_info;
|
||||||
// [ ] Extract input args
|
// [ ] Extract input args
|
||||||
u32 length;
|
u32 length;
|
||||||
GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, (PDWORD)&length);
|
GetLogicalProcessorInformationEx(RelationProcessorCore, nullptr, (PDWORD)&length);
|
||||||
@ -136,7 +140,8 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) {
|
|||||||
|
|
||||||
u32 offset = 0;
|
u32 offset = 0;
|
||||||
|
|
||||||
u32 all_cpus_count = 0;
|
u32 all_cpus_count = 0; // all logical cpus
|
||||||
|
u32 physical_cpu_count = 0;
|
||||||
u32 max_performance = 0;
|
u32 max_performance = 0;
|
||||||
u32 performance_core_count = 0;
|
u32 performance_core_count = 0;
|
||||||
// u32 efficient_core_count;
|
// u32 efficient_core_count;
|
||||||
@ -159,14 +164,15 @@ internal void Win32_Entry_Point (int argc, WCHAR **argv) {
|
|||||||
performance_core_count += count_per_group_physical;
|
performance_core_count += count_per_group_physical;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
physical_cpu_count += count_per_group_physical;
|
||||||
all_cpus_count += count_per_group;
|
all_cpus_count += count_per_group;
|
||||||
}
|
}
|
||||||
|
|
||||||
info->physical_core_count = (s32)all_cpus_count;
|
info->physical_core_count = (s32)physical_cpu_count;
|
||||||
info->primary_core_count = (s32)performance_core_count;
|
info->primary_core_count = (s32)performance_core_count;
|
||||||
|
info->secondary_core_count = info->physical_core_count - info->primary_core_count;
|
||||||
}
|
}
|
||||||
// info->secondary_core_count = ;
|
|
||||||
*/
|
|
||||||
{ OS_System_Info* info = &global_win32_state.system_info;
|
{ OS_System_Info* info = &global_win32_state.system_info;
|
||||||
info->monitors.allocator = GPAllocator();
|
info->monitors.allocator = GPAllocator();
|
||||||
u8 buffer[MAX_COMPUTERNAME_LENGTH + 1] = {0};
|
u8 buffer[MAX_COMPUTERNAME_LENGTH + 1] = {0};
|
||||||
@ -209,6 +215,8 @@ C_LINKAGE DWORD OS_Windows_Thread_Entry_Point (void* parameter) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Individual Thread API
|
// Individual Thread API
|
||||||
|
#define thread_task(T) (T*)thread->data;
|
||||||
|
|
||||||
internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name="") {
|
internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name="") {
|
||||||
Assert(thread != nullptr && proc != nullptr);
|
Assert(thread != nullptr && proc != nullptr);
|
||||||
|
|
||||||
@ -234,6 +242,7 @@ internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name=
|
|||||||
thread->context->thread_name = copy_string(thread_name);
|
thread->context->thread_name = copy_string(thread_name);
|
||||||
thread->context->log_builder = new_string_builder(Arena_Reserve::Size_64M);
|
thread->context->log_builder = new_string_builder(Arena_Reserve::Size_64M);
|
||||||
thread->context->error_arena = next_arena(Arena_Reserve::Size_64M);
|
thread->context->error_arena = next_arena(Arena_Reserve::Size_64M);
|
||||||
|
thread->context->logger = {default_logger_proc, &default_logger};
|
||||||
|
|
||||||
thread->os_thread.windows_thread = windows_thread;
|
thread->os_thread.windows_thread = windows_thread;
|
||||||
thread->os_thread.windows_thread_id = windows_thread_id;
|
thread->os_thread.windows_thread_id = windows_thread_id;
|
||||||
@ -244,20 +253,24 @@ internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name=
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void thread_deinit (Thread* thread) {
|
internal void thread_deinit (Thread* thread, bool zero_thread=false) {
|
||||||
if (thread->os_thread.windows_thread) {
|
if (thread->os_thread.windows_thread) {
|
||||||
CloseHandle(thread->os_thread.windows_thread);
|
CloseHandle(thread->os_thread.windows_thread);
|
||||||
}
|
}
|
||||||
thread->os_thread.windows_thread = nullptr;
|
thread->os_thread.windows_thread = nullptr;
|
||||||
|
|
||||||
arena_delete(thread->context->temp);
|
// #TODO: before releasing arena, force-delete extra pages?
|
||||||
arena_delete(thread->context->arena);
|
// array_reset(*thread->context->log_builder);
|
||||||
free_string_builder(thread->context->log_builder);
|
free_string_builder(thread->context->log_builder);
|
||||||
|
release_arena(thread->context->error_arena);
|
||||||
|
arena_delete(thread->context->temp);
|
||||||
|
arena_delete(thread->context->arena); // must come last because thread->context is allocated with this arena!
|
||||||
|
|
||||||
// memset(thread, 0xCD, sizeof(Thread);
|
if (zero_thread) memset(thread, 0, sizeof(Thread));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void thread_start (Thread* thread) {
|
internal void thread_start (Thread* thread, void* thread_data = nullptr) {
|
||||||
|
if (thread_data) thread->data = thread_data;
|
||||||
ResumeThread(thread->os_thread.windows_thread);
|
ResumeThread(thread->os_thread.windows_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -899,6 +912,26 @@ bool os_main_window_is_minimized () {
|
|||||||
return os_window_is_minimized(get_main_window().window);
|
return os_window_is_minimized(get_main_window().window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s32 os_cpu_logical_core_count () {
|
||||||
|
OS_System_Info* info = &global_win32_state.system_info;
|
||||||
|
return info->logical_processor_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 os_cpu_physical_core_count () {
|
||||||
|
OS_System_Info* info = &global_win32_state.system_info;
|
||||||
|
return info->physical_core_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 os_cpu_primary_core_count () {
|
||||||
|
OS_System_Info* info = &global_win32_state.system_info;
|
||||||
|
return info->primary_core_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
s32 os_cpu_secondary_core_count () {
|
||||||
|
OS_System_Info* info = &global_win32_state.system_info;
|
||||||
|
return info->secondary_core_count;
|
||||||
|
}
|
||||||
|
|
||||||
// #Drives
|
// #Drives
|
||||||
constexpr u64 Win32_Max_Path_Length = 260;
|
constexpr u64 Win32_Max_Path_Length = 260;
|
||||||
bool Win32_Discover_Drives () {
|
bool Win32_Discover_Drives () {
|
||||||
|
|||||||
@ -167,6 +167,7 @@ File_System Win32_filesystem_from_string (string s) {
|
|||||||
}
|
}
|
||||||
struct Dense_FS; // #Temp forward declare!
|
struct Dense_FS; // #Temp forward declare!
|
||||||
struct Win32_Drive {
|
struct Win32_Drive {
|
||||||
|
// Arena* pool;
|
||||||
string label;
|
string label;
|
||||||
string volume_name;
|
string volume_name;
|
||||||
Win32_Drive_Type type;
|
Win32_Drive_Type type;
|
||||||
|
|||||||
@ -294,14 +294,24 @@ Dense_FS* NTFS_MFT_read_raw (string drive_path) {
|
|||||||
log("Found %lld files (bytes_accessed: %s)", mft->file_count, format_bytes(mft->bytes_accessed).data);
|
log("Found %lld files (bytes_accessed: %s)", mft->file_count, format_bytes(mft->bytes_accessed).data);
|
||||||
|
|
||||||
CloseHandle(file_handle);
|
CloseHandle(file_handle);
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
// Version where we transform the format so it's optimal for sorting and searching:
|
|
||||||
// bool NTFS_MFT_read_and_convert () { // pass the structure we want to read into!
|
struct NTFS_Enumeration_Task {
|
||||||
// auto_release_temp();
|
Arena* pool; // small arena just for results
|
||||||
|
OS_Drive* drive;
|
||||||
|
string drive_path; // The drive path we want to enumerate
|
||||||
|
};
|
||||||
|
|
||||||
|
s64 ntfs_enumeration_thread_proc (Thread* thread) {
|
||||||
|
auto task = thread_task(NTFS_Enumeration_Task);
|
||||||
|
|
||||||
// push_allocator(temp());
|
log("(Thread index: %lld) Task pointer: %p", thread->index, task);
|
||||||
// NTFS_MFT_Internal* mft = new_ntfs_drive();
|
|
||||||
|
|
||||||
|
// NTFS_MFT_read_raw|#TODO:
|
||||||
|
|
||||||
// }
|
Sleep(100); // #temp
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
144
src/Ex1.cpp
144
src/Ex1.cpp
@ -11,9 +11,16 @@ struct Explorer {
|
|||||||
// Array<Image_Data> frame_textures;
|
// Array<Image_Data> frame_textures;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Ex1_NTFS_Enumeration {
|
||||||
|
bool initialized;
|
||||||
|
ArrayView<Thread> threads;
|
||||||
|
Array<Thread*> threads_in_flight;
|
||||||
|
};
|
||||||
|
|
||||||
// #Ex1_global_state
|
// #Ex1_global_state
|
||||||
global ExplorerUI explorer_ui;
|
global ExplorerUI explorer_ui;
|
||||||
global Explorer explorer;
|
global Explorer explorer;
|
||||||
|
global Ex1_NTFS_Enumeration ex1_ntfs;
|
||||||
|
|
||||||
#define HOTKEY_ID_BRING_TO_FOREGROUND 1
|
#define HOTKEY_ID_BRING_TO_FOREGROUND 1
|
||||||
#define VK_SPACE_KEY_CODE 0x20
|
#define VK_SPACE_KEY_CODE 0x20
|
||||||
@ -39,19 +46,144 @@ bool Ex1_Register_Global_Hotkeys () {
|
|||||||
#define TRIGGER_EVERY_FRAME false
|
#define TRIGGER_EVERY_FRAME false
|
||||||
#define KEY_UNUSED false
|
#define KEY_UNUSED false
|
||||||
|
|
||||||
// #global_hotkeys - should rename to 'generic program hotkeys'
|
// #program_hotkeys (Not specific to Ex1)
|
||||||
global Key_Combination global_exit_hotkey { ImGuiKey_W, USE_CTRL, USE_SHIFT, KEY_UNUSED, TRIGGER_ONCE };
|
global Key_Combination program_exit_hotkey { ImGuiKey_W, USE_CTRL, USE_SHIFT, KEY_UNUSED, TRIGGER_ONCE };
|
||||||
global Key_Combination global_minimize_hotkey { ImGuiKey_W, USE_CTRL, KEY_UNUSED, KEY_UNUSED, TRIGGER_ONCE };
|
global Key_Combination program_minimize_hotkey { ImGuiKey_W, USE_CTRL, KEY_UNUSED, KEY_UNUSED, TRIGGER_ONCE };
|
||||||
|
|
||||||
bool Ex1_check_key_combinations() {
|
bool Ex1_check_key_combinations() {
|
||||||
update_global_keyboard_state();
|
update_global_keyboard_state();
|
||||||
// #global_hotkeys
|
// #program_hotkeys
|
||||||
if (check_key_combination(&global_exit_hotkey)) {
|
if (check_key_combination(&program_exit_hotkey)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (check_key_combination(&global_minimize_hotkey)) {
|
if (check_key_combination(&program_minimize_hotkey)) {
|
||||||
Win32_Minimize_Window_To_Tray(get_main_window_pointer());
|
Win32_Minimize_Window_To_Tray(get_main_window_pointer());
|
||||||
}
|
}
|
||||||
// #Ex1_hotkeys
|
// #Ex1_hotkeys
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// #define drive_table() &global_win32_state.system_info.drives
|
||||||
|
void Ex1_Control_Panel () { using namespace ImGui;
|
||||||
|
Table<string, OS_Drive>* drive_table = &global_win32_state.system_info.drives;
|
||||||
|
|
||||||
|
Begin("Control Panel");
|
||||||
|
if (Button("Discover drives") || !table_is_valid(drive_table)) {
|
||||||
|
Win32_Discover_Drives();
|
||||||
|
}
|
||||||
|
|
||||||
|
Text("drive_table is valid: %d", table_is_valid(drive_table));
|
||||||
|
// Basic Hash Table iterator: #hash_table_iterator
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (drive_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 (drive_count > 0 && ex1_ntfs.initialized && Button("Enumerate all NTFS drives")) {
|
||||||
|
// 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:
|
||||||
|
// see: #hash_table_iterator (what part of this can we macro out?):
|
||||||
|
|
||||||
|
if (drive_count > ex1_ntfs.threads.count) {
|
||||||
|
debug_break(); // #TODO: Fix this!
|
||||||
|
}
|
||||||
|
for (s32 t = 0; t < drive_count; t += 1) {
|
||||||
|
Thread* thread = &ex1_ntfs.threads[t];
|
||||||
|
Arena* thread_arena = next_arena(Arena_Reserve::Size_64K);
|
||||||
|
push_arena(thread_arena);
|
||||||
|
auto thread_data = New<NTFS_Enumeration_Task>();
|
||||||
|
thread_data->pool = thread_arena;
|
||||||
|
// #TODO: fill out
|
||||||
|
thread_start(thread, thread_data);
|
||||||
|
array_add(ex1_ntfs.threads_in_flight, thread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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])) {
|
||||||
|
Thread* thread = ex1_ntfs.threads_in_flight[t];
|
||||||
|
auto task = thread_task(NTFS_Enumeration_Task);
|
||||||
|
release_arena(task->pool);
|
||||||
|
|
||||||
|
thread_deinit(ex1_ntfs.threads_in_flight[t], true);
|
||||||
|
array_unordered_remove_by_index(ex1_ntfs.threads_in_flight, t);
|
||||||
|
t -= 1; // check this element index again!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ImGui_Debug_Panel () { using namespace ImGui;
|
||||||
|
push_allocator(temp());
|
||||||
|
Begin("Debug Panel");
|
||||||
|
SeparatorText("ex1_ntfs");
|
||||||
|
Text("Threads in flight count: %d", ex1_ntfs.threads_in_flight.count);
|
||||||
|
for_each(i, ex1_ntfs.threads) {
|
||||||
|
Text(" [%d] initialized: %d, has_context: %d, has_data: %d",
|
||||||
|
i, ex1_ntfs.threads[i].proc != nullptr, ex1_ntfs.threads[i].context != nullptr, ex1_ntfs.threads[i].data != nullptr);
|
||||||
|
}
|
||||||
|
// #cpuid
|
||||||
|
// Text("[cpus] physical: %d, logical: %d, primary: %d, secondary: %d", os_cpu_physical_core_count(), os_cpu_logical_core_count(), os_cpu_primary_core_count(), os_cpu_secondary_core_count());
|
||||||
|
SeparatorText("Arena In-Use List");
|
||||||
|
for (u8 i = 0; i < Arena_Reserve_Count; i += 1) {
|
||||||
|
auto t = format_cstring(
|
||||||
|
" [%s] in_use: %d, committed_bytes: %s",
|
||||||
|
format_bytes(Arena_Sizes[i], 0).data,
|
||||||
|
arena_free_list->in_flight_count[i],
|
||||||
|
format_bytes(committed_bytes(arena_free_list->in_flight[i])).data
|
||||||
|
);
|
||||||
|
Text(t);
|
||||||
|
}
|
||||||
|
SeparatorText("Arena Free List");
|
||||||
|
for (u8 i = 0; i < Arena_Reserve_Count; i += 1) {
|
||||||
|
auto t = format_cstring(
|
||||||
|
" [%s] free: %d, committed_bytes: %s",
|
||||||
|
format_bytes(Arena_Sizes[i], 0).data,
|
||||||
|
(s32)arena_free_list->free_table[i].count,
|
||||||
|
format_bytes(committed_bytes(arena_free_list->free_table[i])).data
|
||||||
|
);
|
||||||
|
Text(t);
|
||||||
|
}
|
||||||
|
SeparatorText("Child Threads");
|
||||||
|
|
||||||
|
End();
|
||||||
}
|
}
|
||||||
@ -339,49 +339,6 @@ struct ImGui_Font_Size {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
void ImGui_Debug_Panel () {
|
|
||||||
ImGui::Begin("Debug Panel");
|
|
||||||
|
|
||||||
Table<string, Win32_Drive>* drive_table = &global_win32_state.system_info.drives;
|
|
||||||
|
|
||||||
if (ImGui::Button("Debug_Break()")) {
|
|
||||||
debug_break();
|
|
||||||
}
|
|
||||||
if (ImGui::Button("Discover drives") || !table_is_valid(drive_table)) {
|
|
||||||
Win32_Discover_Drives();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::Text("drive_table is valid: %d", table_is_valid(drive_table));
|
|
||||||
// Most basic Table iterator
|
|
||||||
s32 current_index = 0;
|
|
||||||
for (s64 i = 0; i < drive_table->allocated; i += 1) {
|
|
||||||
Table_Entry<string, Win32_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;
|
|
||||||
|
|
||||||
ImGui::Text(" > [%d] drive letter: %s (is_present: %d)", current_index, entry->value.label.data, entry->value.is_present);
|
|
||||||
current_index += 1;
|
|
||||||
ImGui::SameLine();
|
|
||||||
push_allocator(temp());
|
|
||||||
|
|
||||||
char* button_label = (char*)format_string("Read NTFS MFT Raw##%s", entry->value.label.data).data;
|
|
||||||
|
|
||||||
if (ImGui::Button(button_label)) {
|
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ImGui_Show_Font_Info () {
|
void ImGui_Show_Font_Info () {
|
||||||
ImGui::Begin("Font Settings"); // imgui_push_default_font_index(0);
|
ImGui::Begin("Font Settings"); // imgui_push_default_font_index(0);
|
||||||
if (!ImGui_Default_Font_Loaded()){
|
if (!ImGui_Default_Font_Loaded()){
|
||||||
|
|||||||
@ -86,7 +86,7 @@ void Explorer_ImGui_Application_Win32 () {
|
|||||||
imgui_default_font.sizes.allocator = GPAllocator();
|
imgui_default_font.sizes.allocator = GPAllocator();
|
||||||
imgui_default_font.font_name = font_file_name;
|
imgui_default_font.font_name = font_file_name;
|
||||||
|
|
||||||
for (s64 i = 0; i < 6; i += 1) {
|
for (s64 i = 0; i < ArrayCount(imgui_font_sizes); i += 1) {
|
||||||
f32 font_size = imgui_font_sizes[i];
|
f32 font_size = imgui_font_sizes[i];
|
||||||
ImFont* new_font = io.Fonts->AddFontFromFileTTF((char*)font_file_name.data, font_size);
|
ImFont* new_font = io.Fonts->AddFontFromFileTTF((char*)font_file_name.data, font_size);
|
||||||
if (new_font) {
|
if (new_font) {
|
||||||
@ -150,6 +150,7 @@ void Explorer_ImGui_Application_Win32 () {
|
|||||||
ImGui::DockSpaceOverViewport();
|
ImGui::DockSpaceOverViewport();
|
||||||
|
|
||||||
ImGui_Debug_Panel();
|
ImGui_Debug_Panel();
|
||||||
|
Ex1_Control_Panel();
|
||||||
ImGui_Show_Font_Info();
|
ImGui_Show_Font_Info();
|
||||||
|
|
||||||
ImGui_Pop_Default_Font();
|
ImGui_Pop_Default_Font();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user