[wip] This is going to require some work to disentangle...
This commit is contained in:
parent
4b48ab696b
commit
d9cd1c618c
@ -17,6 +17,9 @@ SET (CMAKE_VERBOSE_MAKEFILE ON)
|
||||
if (MSVC)
|
||||
# Suppress warning: C++ exception handler used, but unwind semantics are not enabled.
|
||||
add_compile_options(/wd4530)
|
||||
add_compile_options(-D_CRT_SECURE_NO_WARNINGS)
|
||||
add_compile_options(-D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING)
|
||||
add_compile_options(-D_CRT_NONSTDC_NO_DEPRECATE)
|
||||
endif()
|
||||
|
||||
SET (EXE_NAME "mexplore_v2")
|
||||
@ -29,12 +32,41 @@ SET (SRC_FILES
|
||||
lib/third_party/dear-imgui/imgui_impl_dx11.cpp
|
||||
lib/third_party/dear-imgui/imgui_impl_win32.cpp
|
||||
|
||||
exe_main.cpp
|
||||
#lib_main
|
||||
lib/Base/Base.cpp
|
||||
lib/Base/Allocator.cpp
|
||||
lib/Base/General_Purpose_Allocator.cpp
|
||||
#lib/Base/Base_Thread_Context.cpp
|
||||
#lib/Base/Arena.cpp
|
||||
#lib/Base/String.cpp
|
||||
#lib/Base/ErrorType.cpp
|
||||
#lib/Base/Logger.cpp
|
||||
#lib/Base/Expandable_Arena.cpp
|
||||
#lib/Base/Threads.cpp
|
||||
#lib/OS/OS_Filesystem.cpp
|
||||
#lib/Base/Thread_Group.cpp
|
||||
#lib/Base/Unicode.cpp
|
||||
#lib/Base/RadixSort.cpp
|
||||
lib/OS/OS_Win32.cpp
|
||||
|
||||
#lib/Base/run_tests.cpp
|
||||
|
||||
#exe_main
|
||||
#src/ImGui_Supplementary.cpp
|
||||
#src/String_Analysis.cpp
|
||||
#src/explorer_main.cpp
|
||||
#src/Base_Entry_Point.cpp
|
||||
|
||||
# Not in main project: for future opengl backend
|
||||
#lib/Graphics.cpp
|
||||
)
|
||||
|
||||
SET (INCLUDE_DIRS
|
||||
${PROJECT_SOURCE_DIR}/src
|
||||
${PROJECT_SOURCE_DIR}/lib
|
||||
${PROJECT_SOURCE_DIR}/lib/Base
|
||||
${PROJECT_SOURCE_DIR}/lib/OS
|
||||
${PROJECT_SOURCE_DIR}/lib/UI
|
||||
${PROJECT_SOURCE_DIR}/lib/third_party
|
||||
)
|
||||
|
||||
@ -49,6 +81,7 @@ endif()
|
||||
SET (SYSTEM_LIBRARIES
|
||||
)
|
||||
|
||||
add_executable(${EXE_NAME} ${SRC_FILES})
|
||||
#add_executable(${EXE_NAME} ${SRC_FILES})
|
||||
add_library(${EXE_NAME} STATIC ${SRC_FILES})
|
||||
target_include_directories(${EXE_NAME} PRIVATE ${INCLUDE_DIRS})
|
||||
target_link_libraries(${EXE_NAME} PRIVATE ${LINK_LIBS_DIRS} ${SYSTEM_LIBRARIES})
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
#include "Allocator.h"
|
||||
#include "Base_Thread_Context.h"
|
||||
|
||||
void* internal_alloc (s64 size) {
|
||||
Allocator allocator = context_allocator();
|
||||
void* result = allocator.proc(Allocator_Mode::ALLOCATE, size, 0, nullptr, allocator.data);
|
||||
@ -16,9 +19,4 @@ void internal_free (void* memory) {
|
||||
allocator.proc(Allocator_Mode::DEALLOCATE, 0, 0, memory, allocator.data);
|
||||
}
|
||||
|
||||
void print_context_allocator () {
|
||||
Assert(thread_context()->allocator.proc);
|
||||
|
||||
char* result = (char*)thread_context()->allocator.proc(Allocator_Mode::DETAILS, 0, 0, nullptr, thread_context()->allocator.data);
|
||||
log_none("Current allocator details: %s", result);
|
||||
}
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Base.h"
|
||||
|
||||
#define ALLOCATOR_DEBUG_MODE 1
|
||||
#define ALLOCATOR_POISON_MEMORY_ON_ALLOCATION \
|
||||
(BUILD_DEBUG && ALLOCATOR_DEBUG_MODE)
|
||||
@ -120,6 +122,4 @@ template <typename T> T* copy_struct (T* src) {
|
||||
memcpy(dst, src, sizeof(T));
|
||||
}
|
||||
|
||||
// #TODO: Turn this into a macro that also provides the
|
||||
// file, line number to the print.
|
||||
void print_context_allocator ();
|
||||
|
||||
|
||||
@ -309,4 +309,115 @@ void* fixed_arena_allocator_proc (Allocator_Mode mode, s64 requested_size, s64 o
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// #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
|
||||
|
||||
#include "Base.h"
|
||||
|
||||
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;
|
||||
|
||||
// Only call once from main thread!
|
||||
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 < Arena_Reserve_Count; i += 1) {
|
||||
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_free_list->in_flight[i].allocator = allocator;
|
||||
array_reserve(arena_free_list->in_flight[i], 64);
|
||||
#endif
|
||||
}
|
||||
|
||||
arena_free_list->initialized = true;
|
||||
}
|
||||
|
||||
Arena* next_arena (Arena_Reserve reserve_size) {
|
||||
Assert(arena_free_list != nullptr);
|
||||
Arena* arena;
|
||||
lock_guard(&arena_free_list->mutex);
|
||||
s64 reserve_index = (s64)reserve_size;
|
||||
|
||||
if (!arena_free_list->free_table[reserve_index].count) {
|
||||
arena = bootstrap_arena(reserve_size, ARENA_DEFAULT_COMMIT_PAGE_COUNT);
|
||||
} else {
|
||||
arena = pop(arena_free_list->free_table[reserve_index]);
|
||||
}
|
||||
#if ARENA_DEBUG
|
||||
array_add(arena_free_list->in_flight[reserve_index], arena);
|
||||
#endif
|
||||
|
||||
arena_free_list->in_flight_count[reserve_index] += 1;
|
||||
|
||||
Assert(arena != nullptr);
|
||||
return arena;
|
||||
}
|
||||
|
||||
void release_arena (Arena* arena, bool delete_extra_pages) {
|
||||
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_free_list->mutex);
|
||||
s64 reserve_index = (s64)arena->reserve_size;
|
||||
|
||||
#if ARENA_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_free_list->free_table[reserve_index], arena);
|
||||
|
||||
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;
|
||||
// while (arenas_to_delete_count > 0) {
|
||||
// arena_delete(arena_free_table[arena_free_table.count-1]);
|
||||
// array_unordered_remove_by_index(..);
|
||||
// arenas_to_delete_count -= 1;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
s64 bytes_in_use (ArrayView<Arena*> arenas) {
|
||||
// does not include overhead from committed pages!
|
||||
s64 sum = 0;
|
||||
|
||||
for (s64 i = 0; i < arenas.count; i += 1) {
|
||||
sum += arena_usage_bytes(arenas[i]);
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "Base.h"
|
||||
#include "Array.h"
|
||||
#include "Allocator.h"
|
||||
|
||||
struct ExpandableArena; // fwd declare #temp
|
||||
|
||||
#if OS_WINDOWS
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Arena.h"
|
||||
|
||||
constexpr s64 ARRAY_ARENA_START_OFFSET = 64;
|
||||
|
||||
template <typename T>
|
||||
|
||||
@ -1,108 +0,0 @@
|
||||
// #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
|
||||
|
||||
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;
|
||||
|
||||
// Only call once from main thread!
|
||||
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 < Arena_Reserve_Count; i += 1) {
|
||||
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_free_list->in_flight[i].allocator = allocator;
|
||||
array_reserve(arena_free_list->in_flight[i], 64);
|
||||
#endif
|
||||
}
|
||||
|
||||
arena_free_list->initialized = true;
|
||||
}
|
||||
|
||||
Arena* next_arena (Arena_Reserve reserve_size) {
|
||||
Assert(arena_free_list != nullptr);
|
||||
Arena* arena;
|
||||
lock_guard(&arena_free_list->mutex);
|
||||
s64 reserve_index = (s64)reserve_size;
|
||||
|
||||
if (!arena_free_list->free_table[reserve_index].count) {
|
||||
arena = bootstrap_arena(reserve_size, ARENA_DEFAULT_COMMIT_PAGE_COUNT);
|
||||
} else {
|
||||
arena = pop(arena_free_list->free_table[reserve_index]);
|
||||
}
|
||||
#if ARENA_DEBUG
|
||||
array_add(arena_free_list->in_flight[reserve_index], arena);
|
||||
#endif
|
||||
|
||||
arena_free_list->in_flight_count[reserve_index] += 1;
|
||||
|
||||
Assert(arena != nullptr);
|
||||
return arena;
|
||||
}
|
||||
|
||||
void release_arena (Arena* arena, bool delete_extra_pages) {
|
||||
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_free_list->mutex);
|
||||
s64 reserve_index = (s64)arena->reserve_size;
|
||||
|
||||
#if ARENA_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_free_list->free_table[reserve_index], arena);
|
||||
|
||||
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;
|
||||
// while (arenas_to_delete_count > 0) {
|
||||
// arena_delete(arena_free_table[arena_free_table.count-1]);
|
||||
// array_unordered_remove_by_index(..);
|
||||
// arenas_to_delete_count -= 1;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
s64 bytes_in_use (ArrayView<Arena*> arenas) {
|
||||
// does not include overhead from committed pages!
|
||||
s64 sum = 0;
|
||||
|
||||
for (s64 i = 0; i < arenas.count; i += 1) {
|
||||
sum += arena_usage_bytes(arenas[i]);
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
// Strongly influenced by Array.jai in Basic module.
|
||||
#pragma once
|
||||
|
||||
#include "Allocator.h"
|
||||
|
||||
// For Arena-Backed arrays use ArenaArray
|
||||
|
||||
MSVC_RUNTIME_CHECKS_OFF
|
||||
|
||||
22
lib/Base/Base.cpp
Normal file
22
lib/Base/Base.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include "Base.h"
|
||||
// #TEMPORARY
|
||||
// #include "Allocator.h"
|
||||
// #include "Array.h"
|
||||
// #include "General_Purpose_Allocator.h"
|
||||
// #include "Arena.h"
|
||||
// #include "Arena_Array.h"
|
||||
// #include "MString.h"
|
||||
// #include "Hash_Functions.h"
|
||||
// #include "Hash_Table.h"
|
||||
// #include "Arena_Hash_Table.h"
|
||||
#if OS_WINDOWS
|
||||
// # include "OS_Win32.h"
|
||||
#endif
|
||||
// #include "Layout.h"
|
||||
// #include "Logger.h"
|
||||
|
||||
// #include "Serializer.h"
|
||||
|
||||
// #include "Base_Thread_Context.h"
|
||||
// #include "Expandable_Arena.h"
|
||||
// #include "Timing.h"
|
||||
@ -408,67 +408,6 @@ template <typename T> T clamp (T v, T min, T max) {
|
||||
return x;
|
||||
}
|
||||
|
||||
// #thread_primitives #move?
|
||||
#if OS_WINDOWS
|
||||
struct Condition_Variable {
|
||||
CONDITION_VARIABLE condition_variable;
|
||||
};
|
||||
struct Semaphore {
|
||||
HANDLE event;
|
||||
};
|
||||
struct Mutex {
|
||||
CRITICAL_SECTION csection;
|
||||
};
|
||||
struct OS_Thread {
|
||||
HANDLE windows_thread;
|
||||
s32 windows_thread_id;
|
||||
};
|
||||
struct File {
|
||||
HANDLE handle;
|
||||
};
|
||||
internal void mutex_init (Mutex* mutex);
|
||||
internal void mutex_destroy (Mutex* mutex);
|
||||
internal void lock (Mutex* mutex);
|
||||
internal void unlock (Mutex* mutex);
|
||||
#endif
|
||||
#define POSIX_THREADS OS_LINUX || OS_MACOS || OS_IOS || OS_ANDROID
|
||||
#if OS_MACOS
|
||||
struct Semaphore {
|
||||
task_t owner;
|
||||
semaphore_t event = 0;
|
||||
};
|
||||
#endif
|
||||
#if OS_LINUX || OS_ANDROID
|
||||
struct Semaphore {
|
||||
sem_t semaphore;
|
||||
};
|
||||
#endif
|
||||
#if OS_IS_UNIX // #posix threads
|
||||
struct OS_Thread {
|
||||
pthread_t thread_handle;
|
||||
Semaphore is_alive;
|
||||
Semaphore suspended;
|
||||
b32 is_done;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#define lock_guard(x) \
|
||||
Mutex_Lock_Guard Concat(_auto_lock_guard_, __LINE__)(x)
|
||||
|
||||
struct Mutex_Lock_Guard {
|
||||
Mutex* mutex;
|
||||
|
||||
Mutex_Lock_Guard (Mutex* mutex) {
|
||||
this->mutex = mutex;
|
||||
lock(mutex);
|
||||
}
|
||||
|
||||
~Mutex_Lock_Guard () {
|
||||
unlock(mutex);
|
||||
}
|
||||
};
|
||||
|
||||
// Helper macros for raw arrays:
|
||||
#define ArrayCount(array) sizeof(array) / sizeof(array[0])
|
||||
// For-loop construct macros
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
// See Context_Base in jai, and TCTX in raddebugger:
|
||||
#include "Base_Thread_Context.h"
|
||||
|
||||
internal void Bootstrap_Main_Thread_Context () {
|
||||
// Timed_Block_Print_No_Context("Bootstrap_Main_Thread_Context");
|
||||
|
||||
@ -1,31 +1,37 @@
|
||||
// #hacky fwd declares
|
||||
struct Error;
|
||||
struct Graphics;
|
||||
#pragma once
|
||||
|
||||
#include "Base.h"
|
||||
#include "General_Purpose_Allocator.h"
|
||||
// #include "Arena.h"
|
||||
// #include "Logger.h"
|
||||
#include "MString.h"
|
||||
// #include "Threads.h"
|
||||
// #include "Expandable_Arena.h"
|
||||
|
||||
struct Thread_Context {
|
||||
ExpandableArena* temp; // Used for temporary allocations, scratch space.
|
||||
ExpandableArena* arena; // general purpose local arena
|
||||
// ExpandableArena* temp; // Used for temporary allocations, scratch space.
|
||||
// ExpandableArena* arena; // general purpose local arena
|
||||
|
||||
Allocator allocator;
|
||||
s32 thread_idx;
|
||||
// u16 _padding0;
|
||||
u16 GPAllocator_alignment = 16;
|
||||
Logger logger = {nullptr, nullptr};
|
||||
String_Builder* log_builder;
|
||||
// Logger logger = {nullptr, nullptr};
|
||||
// String_Builder* log_builder;
|
||||
// Stack_Trace* stack_trace;
|
||||
|
||||
Array<Thread*> child_threads; // maybe should be linked-list?
|
||||
// Array<Thread*> child_threads; // maybe should be linked-list?
|
||||
Thread_Context* parent_thread_context = nullptr; // so we can remove from above array
|
||||
|
||||
string thread_name;
|
||||
|
||||
Allocator error_allocator = GPAllocator();
|
||||
Error* first_error = nullptr;
|
||||
Error* current_error = nullptr;
|
||||
Arena* error_arena;
|
||||
// Error* first_error = nullptr;
|
||||
// Error* current_error = nullptr;
|
||||
// Arena* error_arena;
|
||||
|
||||
// Graphics stuff:
|
||||
Graphics* graphics;
|
||||
// Graphics* graphics;
|
||||
|
||||
void* userdata; // for appending other arenas, etc.
|
||||
};
|
||||
@ -53,3 +59,13 @@ struct Push_Allocator {
|
||||
}
|
||||
};
|
||||
|
||||
// #TODO: Turn this into a macro that also provides the
|
||||
// file, line number to the print.
|
||||
void print_context_allocator ();
|
||||
|
||||
// void print_context_allocator () {
|
||||
// Assert(thread_context()->allocator.proc);
|
||||
|
||||
// char* result = (char*)thread_context()->allocator.proc(Allocator_Mode::DETAILS, 0, 0, nullptr, thread_context()->allocator.data);
|
||||
// log_none("Current allocator details: %s", result);
|
||||
// }
|
||||
|
||||
@ -1,3 +1,7 @@
|
||||
#include "General_Purpose_Allocator.h"
|
||||
#include "Base_Thread_Context.h"
|
||||
#include "Threads.h"
|
||||
|
||||
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
||||
global General_Allocator gAllocator; // @Shared
|
||||
global Mutex allocator_mutex;
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "Base.h"
|
||||
#include "Allocator.h"
|
||||
#include "Array.h"
|
||||
|
||||
#define GP_ALLOCATOR_TRACK_ALLOCATIONS BUILD_DEBUG
|
||||
#define GP_ALLOCATOR_VERY_DEBUG BUILD_DEBUG && 0
|
||||
|
||||
@ -21,6 +25,7 @@
|
||||
#define Aligned_Realloc(old_sz, ptr, sz, align) gp_aligned_realloc(old_sz, ptr, sz, align)
|
||||
#define Aligned_Free(ptr) std::free(ptr)
|
||||
#endif
|
||||
|
||||
struct Allocation {
|
||||
s64 size;
|
||||
void* memory;
|
||||
|
||||
@ -1,3 +1,5 @@
|
||||
#include "MString.h"
|
||||
|
||||
constexpr u32 HASH_INIT = 5381;
|
||||
u32 sdbm_hash (void* data, s64 size) {
|
||||
u32 h = HASH_INIT;
|
||||
|
||||
@ -1,4 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "Base.h"
|
||||
#include "Array.h"
|
||||
#include "Arena_Array.h"
|
||||
|
||||
// #TODO: #strings:
|
||||
// [ ] see: #Parsing stuff:
|
||||
// [?] How do I accept variadic arguments of any type to my print function?
|
||||
@ -1,3 +1,5 @@
|
||||
#include "MString.h"
|
||||
|
||||
// #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) {
|
||||
|
||||
62
lib/Base/Threads.h
Normal file
62
lib/Base/Threads.h
Normal file
@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
// #thread_primitives #move?
|
||||
#if OS_WINDOWS
|
||||
struct Condition_Variable {
|
||||
CONDITION_VARIABLE condition_variable;
|
||||
};
|
||||
struct Semaphore {
|
||||
HANDLE event;
|
||||
};
|
||||
struct Mutex {
|
||||
CRITICAL_SECTION csection;
|
||||
};
|
||||
struct OS_Thread {
|
||||
HANDLE windows_thread;
|
||||
s32 windows_thread_id;
|
||||
};
|
||||
struct File {
|
||||
HANDLE handle;
|
||||
};
|
||||
#endif
|
||||
#define POSIX_THREADS OS_LINUX || OS_MACOS || OS_IOS || OS_ANDROID
|
||||
#if OS_MACOS
|
||||
struct Semaphore {
|
||||
task_t owner;
|
||||
semaphore_t event = 0;
|
||||
};
|
||||
#endif
|
||||
#if OS_LINUX || OS_ANDROID
|
||||
struct Semaphore {
|
||||
sem_t semaphore;
|
||||
};
|
||||
#endif
|
||||
#if OS_IS_UNIX // #posix threads
|
||||
struct OS_Thread {
|
||||
pthread_t thread_handle;
|
||||
Semaphore is_alive;
|
||||
Semaphore suspended;
|
||||
b32 is_done;
|
||||
};
|
||||
#endif
|
||||
|
||||
internal void mutex_init (Mutex* mutex);
|
||||
internal void mutex_destroy (Mutex* mutex);
|
||||
internal void lock (Mutex* mutex);
|
||||
internal void unlock (Mutex* mutex);
|
||||
|
||||
#define lock_guard(x) \
|
||||
Mutex_Lock_Guard Concat(_auto_lock_guard_, __LINE__)(x)
|
||||
|
||||
struct Mutex_Lock_Guard {
|
||||
Mutex* mutex;
|
||||
|
||||
Mutex_Lock_Guard (Mutex* mutex) {
|
||||
this->mutex = mutex;
|
||||
lock(mutex);
|
||||
}
|
||||
|
||||
~Mutex_Lock_Guard () {
|
||||
unlock(mutex);
|
||||
}
|
||||
};
|
||||
@ -1,3 +1,6 @@
|
||||
#pragma once
|
||||
#include "Base.h"
|
||||
|
||||
// #Timing API:
|
||||
#define System_Timed_Block_Print(name) \
|
||||
system_timed_block_print Concat(_sys_timed_block_print_guard, __LINE__)(name)
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
// before terminating.
|
||||
// Or we can move child threads up to the parent?
|
||||
|
||||
#include "OS_Win32.h"
|
||||
|
||||
constexpr s64 FILETIME_TO_UNIX = 116444736000000000i64;
|
||||
f64 GetUnixTimestamp () {
|
||||
FILETIME fileTime;
|
||||
|
||||
@ -1,6 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "Base.h"
|
||||
#include "Array.h"
|
||||
#include "Threads.h"
|
||||
|
||||
#pragma comment(lib, "user32")
|
||||
#pragma comment(lib, "shell32")
|
||||
#include <shellapi.h>
|
||||
#include <math.h>
|
||||
#include <d3d11.h>
|
||||
#include <dwmapi.h>
|
||||
|
||||
f64 GetUnixTimestamp ();
|
||||
s64 GetUnixTimestampNanoseconds ();
|
||||
|
||||
@ -49,7 +49,6 @@
|
||||
// OS-Abstraction Layer
|
||||
#include "lib/Base/Threads.cpp"
|
||||
#include "lib/OS/OS_Filesystem.cpp"
|
||||
|
||||
#include "lib/Base/Thread_Group.cpp"
|
||||
|
||||
#if OS_WINDOWS
|
||||
|
||||
@ -1,3 +1,6 @@
|
||||
#include "Base_Entry_Point.h"
|
||||
#include "Timing.h"
|
||||
|
||||
internal void Main_Entry_Point (int argc, WCHAR **argv);
|
||||
|
||||
#if OS_WINDOWS
|
||||
|
||||
361
src/Ex1.cpp
361
src/Ex1.cpp
@ -1,361 +0,0 @@
|
||||
struct ExplorerUI {
|
||||
// u8 search_input[64];
|
||||
// u8 secondary_input[64];
|
||||
};
|
||||
|
||||
struct Explorer {
|
||||
// A bunch of flags?
|
||||
// Icon cache?
|
||||
// Array<Image_Data> frame_textures;
|
||||
};
|
||||
|
||||
struct Ex1_NTFS_Enumeration {
|
||||
b32 initialized;
|
||||
b32 threads_started;
|
||||
|
||||
ArrayView<Thread> threads;
|
||||
Array<Thread*> threads_in_flight;
|
||||
};
|
||||
|
||||
// #Ex1_global_state
|
||||
global ExplorerUI explorer_ui;
|
||||
global Explorer explorer;
|
||||
global Ex1_NTFS_Enumeration ex1_ntfs;
|
||||
|
||||
#define HOTKEY_ID_BRING_TO_FOREGROUND 1
|
||||
#define VK_SPACE_KEY_CODE 0x20
|
||||
// #define HOTKEY_ID_HIDE_TITLEBAR
|
||||
|
||||
void Ex1_Unregister_Global_Hotkeys () {
|
||||
UnregisterHotKey(nullptr, HOTKEY_ID_BRING_TO_FOREGROUND);
|
||||
}
|
||||
|
||||
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-Shift-Alt-Space");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define USE_CTRL true
|
||||
#define USE_SHIFT true
|
||||
#define USE_ALT true
|
||||
#define TRIGGER_ONCE true
|
||||
#define TRIGGER_EVERY_FRAME false
|
||||
#define KEY_UNUSED false
|
||||
|
||||
// #program_hotkeys (Not specific to Ex1)
|
||||
global Key_Combination program_exit_hotkey { ImGuiKey_W, USE_CTRL, USE_SHIFT, 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() {
|
||||
update_global_keyboard_state();
|
||||
// #program_hotkeys
|
||||
if (check_key_combination(&program_exit_hotkey)) {
|
||||
return true;
|
||||
}
|
||||
if (check_key_combination(&program_minimize_hotkey)) {
|
||||
Win32_Minimize_Window_To_Tray(get_main_window_pointer());
|
||||
}
|
||||
// #Ex1_hotkeys
|
||||
return false;
|
||||
}
|
||||
|
||||
// #Workspaces are FOR DEVELOPMENT ONLY.
|
||||
struct Ex1_Workspace {
|
||||
s32 path_select;
|
||||
s32 file_select;
|
||||
|
||||
RadixSort file_size_radix;
|
||||
RadixSort file_modtime_radix;
|
||||
RadixSort dir_modtime_radix;
|
||||
bool sort_completed;
|
||||
|
||||
// Reordered strings:
|
||||
ArrayView<string> files_sorted_by_size;
|
||||
ArrayView<string> files_sorted_by_modtime;
|
||||
};
|
||||
|
||||
global Ex1_Workspace ex1w;
|
||||
|
||||
void free_ex1_workspace_and_reset () {
|
||||
if (ex1w.sort_completed) {
|
||||
push_allocator(GPAllocator());
|
||||
|
||||
radix_sort_free(&ex1w.file_size_radix);
|
||||
radix_sort_free(&ex1w.file_modtime_radix);
|
||||
radix_sort_free(&ex1w.dir_modtime_radix);
|
||||
|
||||
array_free(ex1w.files_sorted_by_size);
|
||||
array_free(ex1w.files_sorted_by_modtime);
|
||||
|
||||
zero_struct(&ex1w);
|
||||
}
|
||||
}
|
||||
|
||||
// #TODO: Move all sort stuff to OS_Win32?
|
||||
// Make a general version of this that takes two ArrayView<T> and reorders.
|
||||
// There's no need to do this until we have the filtered results.
|
||||
void os_win32_reorder_files_by_radix (RadixSort* r, ArrayView<string>* files, bool reverse_order=false) {
|
||||
Timed_Block_Print("os_win32_reorder_files_by_radix");
|
||||
// Where are my source files!?
|
||||
(*files) = ArrayView<string>(r->ranks.count);
|
||||
for_each(f, (*files)) {
|
||||
// (*files)[f] = get_file_copy(stfe, r->ranks[f]);
|
||||
(*files)[f] = get_file_string_view(stfe, r->ranks[f]);
|
||||
}
|
||||
}
|
||||
|
||||
void Ex1_show_enumeration_workspace () { using namespace ImGui;
|
||||
push_imgui_window("Enumerated Data Workspace");
|
||||
|
||||
if (!ex1w.sort_completed) {
|
||||
push_allocator(GPAllocator());
|
||||
Timed_Block_Print("radix_sort_u64: file sizes, file modtimes, directory modtimes");
|
||||
ArrayView<u64> sizes = to_view(*stfe->files.sizes);
|
||||
radix_sort_u64(&ex1w.file_size_radix, sizes.data, (u32)sizes.count);
|
||||
ArrayView<u64> file_modtimes = to_view(*stfe->files.modtimes);
|
||||
radix_sort_u64(&ex1w.file_modtime_radix, file_modtimes.data, (u32)file_modtimes.count);
|
||||
ArrayView<u64> dirs_modtimes = to_view(*stfe->dirs.modtimes);
|
||||
radix_sort_u64(&ex1w.dir_modtime_radix, dirs_modtimes.data, (u32)dirs_modtimes.count);
|
||||
// Create ArrayView<string>, ArrayView<u64> sizes, and ArrayView<u64> modtimes
|
||||
os_win32_reorder_files_by_radix(&ex1w.file_size_radix, &ex1w.files_sorted_by_size);
|
||||
os_win32_reorder_files_by_radix(&ex1w.file_modtime_radix, &ex1w.files_sorted_by_modtime);
|
||||
// reordering by the rank permutations generated by RadixSort.
|
||||
ex1w.sort_completed = true;
|
||||
}
|
||||
|
||||
if (!ex1w.sort_completed) { return; }
|
||||
|
||||
SeparatorText("Files ordered by modtime");
|
||||
s32 file_count = (s32)ex1w.files_sorted_by_modtime.count;
|
||||
SliderInt("Select file index", &ex1w.file_select, 0, file_count-1);
|
||||
string file_name = copy_string(ex1w.files_sorted_by_modtime[ex1w.file_select]);
|
||||
Text("%s", file_name.data);
|
||||
u32 radix_index = rank(&ex1w.file_modtime_radix, ex1w.file_select);
|
||||
Text("date modified: %s", format_time_datetime(get_file_modtime(stfe, radix_index)).data);
|
||||
|
||||
SeparatorText("Files ordered by size");
|
||||
file_count = (s32)ex1w.files_sorted_by_size.count;
|
||||
// SliderInt("Select file index", &ex1w.file_select, 0, file_count-1);
|
||||
file_name = copy_string(ex1w.files_sorted_by_size[ex1w.file_select]);
|
||||
Text("%s", file_name.data);
|
||||
radix_index = rank(&ex1w.file_size_radix, ex1w.file_select);
|
||||
Text("size: %s", format_bytes(get_file_size_bytes(stfe, radix_index)).data);
|
||||
// Text("date modified: %s", format_time_datetime(get_file_modtime(stfe, radix_index)).data);
|
||||
|
||||
if (Button("Count unique UTF-8 characters")) {
|
||||
count_unique_utf8_chars();
|
||||
}
|
||||
|
||||
Text("unique_codepoints_utf32.count: %", unique_codepoints_utf32.count);
|
||||
|
||||
for_each(u, unique_codepoints_utf32) {
|
||||
Text("[%d] Code point as hex: 0x%X", u, unique_codepoints_utf32[u]);
|
||||
}
|
||||
|
||||
Text("files_sorted_by_size size in bytes: %lld", ex1w.files_sorted_by_size.count * sizeof(string));
|
||||
Text("files_sorted_by_modtime size in bytes: %lld", ex1w.files_sorted_by_modtime.count * sizeof(string));
|
||||
|
||||
for (s64 i = 1; i < 128; i += 1) {
|
||||
u8 cstring[2] = {};
|
||||
cstring[0] = (u8)i;
|
||||
cstring[1] = 0;
|
||||
Text("codepoint[0x%X]: %s, count: %lld", i, cstring, count_ascii_codepoints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Ex1_Control_Panel () { using namespace ImGui;
|
||||
f64 frame_time = GetUnixTimestamp();
|
||||
Table<string, OS_Drive*>* drive_table = get_drive_table();
|
||||
|
||||
push_imgui_window("Control Panel");
|
||||
|
||||
// if (Button("Debug break")) { debug_break(); }
|
||||
if (/*Button("Discover drives") ||*/!table_is_valid(drive_table)) { Win32_Discover_Drives(); }
|
||||
|
||||
// Text("ntfs_workspace_files_loaded: %s", ntfs_workspace_files_loaded()? "true": "false");
|
||||
// if (ntfs_workspace_files_loaded()) {
|
||||
// Ex1_show_ntfs_workspace();
|
||||
// return;
|
||||
// }
|
||||
|
||||
bool all_drives_enumerated = stfe && stfe->thread_completed;
|
||||
push_allocator(temp());
|
||||
ArrayView<OS_Drive*> drives = os_get_available_drives(); // only includes drives that are ready.
|
||||
|
||||
|
||||
if (!USN_Journal_Monitoring_Ready(drives[0]) && Button("Enable USN Monitoring for all drives")) {
|
||||
Win32_Enable_USN_Journal_Monitoring(drives);
|
||||
}
|
||||
if (USN_Journal_Monitoring_Ready(drives[0]) && Button("Query USN Journal")) {
|
||||
Query_USN_Journal(drives);
|
||||
}
|
||||
|
||||
if (!all_drives_enumerated) {
|
||||
// Text("drive_table is valid: %d", table_is_valid(drive_table));
|
||||
for_each(i, drives) {
|
||||
OS_Drive* drive = drives[i];
|
||||
|
||||
Text(" > [%d] drive letter: %s (is_present: %d)", i + 1, drive->label.data, drive->is_present);
|
||||
if (drive->time_to_enumerate != 0) {
|
||||
SameLine();
|
||||
Text("Enumerated in %.2f seconds", drive->time_to_enumerate);
|
||||
}
|
||||
// SameLine();
|
||||
// if (Button(format_cstring("Read NTFS MFT Raw##%s", drive->label.data))) {
|
||||
// push_arena(thread_context()->arena);
|
||||
// Error* error = NTFS_MFT_read_raw(drive);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
s32 drives_enumerated = 0;
|
||||
for_each(d, drives) {
|
||||
OS_Drive* drive = drives[d];
|
||||
if (!drives[d]->time_to_enumerate) { continue; }
|
||||
if (!drives[d]->data) { continue; }
|
||||
|
||||
if (drives[d]->data->paths.offsets->count > 0) {
|
||||
drives_enumerated += 1;
|
||||
}
|
||||
}
|
||||
// bool all_drives_enumerated = !ex1_ntfs.threads_in_flight.count
|
||||
// && (drives_enumerated == drives.count);
|
||||
|
||||
// string file_path = format_string_temp("%s_DriveData.bin", os_get_machine_name().data);
|
||||
string file_path = "D:/Projects/Cpp/Musa-Cpp-Lib-V2/bin/MUSA-PC3_DriveData.bin";// FIXED path.
|
||||
Text("fixed file_path: %s", file_path.data);
|
||||
if (!all_drives_enumerated && file_exists(file_path)) { // #autoload
|
||||
Deserialize_ST_File_Enumeration(file_path);
|
||||
}
|
||||
if (drives.count > 0 && !all_drives_enumerated && file_exists(file_path) && Button("Load from file (this machine)")) {
|
||||
Deserialize_ST_File_Enumeration(file_path);
|
||||
// Deserialize_Win32_Drives(file_path);
|
||||
}
|
||||
|
||||
// if (file_enum_multithreading_started()) {
|
||||
// if (thread_is_done(drive_enumeration->master_thread)) {
|
||||
// push_allocator(GPAllocator());
|
||||
// // Thread* thread = drive_enumeration->master_thread;
|
||||
// // auto task = thread_task(Drive_Enumeration);
|
||||
// // Nothing to free?
|
||||
// thread_deinit(drive_enumeration->master_thread, true);
|
||||
// }
|
||||
// }
|
||||
|
||||
// #FileEnumerationST
|
||||
if (stfe && stfe->thread_started) {
|
||||
// print dirs enumerated, etc
|
||||
if (!stfe->thread_completed) Text("Enumeration Thread Active (elapsed: %s)", format_time_seconds(frame_time-stfe->start_time).data);
|
||||
if (stfe->dirs.offsets) {
|
||||
s64 dirs_enumerated = stfe->dirs.offsets->count;
|
||||
Text("Dirs enumerated: %lld", dirs_enumerated);
|
||||
// if (!stfe->thread_completed) Text("Current dir: %s", get_last_path_copy(stfe).data);
|
||||
}
|
||||
if (stfe->files.offsets) {
|
||||
s64 files_enumerated = stfe->files.offsets->count;
|
||||
Text("Files enumerated: %lld", files_enumerated);
|
||||
// if (!stfe->thread_completed) Text("Current file: %s", get_last_file_copy(stfe).data);
|
||||
}
|
||||
|
||||
if (stfe->thread_completed) {
|
||||
Text("String bytes stored: %s", format_bytes(stfe->dirs.strings->count + stfe->files.strings->count).data);
|
||||
Text("Elapsed time: %s", format_time_seconds(stfe->end_time-stfe->start_time).data);
|
||||
}
|
||||
}
|
||||
if (stfe && stfe->thread_started && !stfe->thread_completed) {
|
||||
Assert(stfe->master_thread != nullptr);
|
||||
if (thread_is_done(stfe->master_thread)) {
|
||||
thread_deinit(stfe->master_thread, true);
|
||||
stfe->thread_completed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_drives_enumerated && Button("Save enumerated data")) {
|
||||
if (!Serialize_ST_File_Enumeration(file_path)) {
|
||||
log_error("Failed to write enumerated files");
|
||||
os_log_error();
|
||||
}
|
||||
}
|
||||
|
||||
if (all_drives_enumerated && Button("Reset State")) {
|
||||
free_ex1_workspace_and_reset();
|
||||
free_stfe_and_reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (all_drives_enumerated) {
|
||||
Ex1_show_enumeration_workspace();
|
||||
}
|
||||
|
||||
if (drives.count > 0 && !all_drives_enumerated && Button("Enumerate all NTFS drives")) { // && ex1_ntfs.initialized
|
||||
os_run_file_enumeration_single_threaded();
|
||||
// os_run_file_enumeration_multithreaded(); // #disabled for now
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui_Debug_Panel () { using namespace ImGui;
|
||||
push_allocator(temp());
|
||||
|
||||
Begin("Debug Panel");
|
||||
// #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");
|
||||
lock_guard(&arena_free_list->mutex);
|
||||
for (u8 i = 0; i < Arena_Reserve_Count; i += 1) {
|
||||
#if ARENA_DEBUG
|
||||
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
|
||||
);
|
||||
#else
|
||||
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],
|
||||
"disabled in release mode"
|
||||
);
|
||||
#endif
|
||||
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");
|
||||
SeparatorText("Errors");
|
||||
ArrayView<Error*> errors = get_all_errors(thread_context());
|
||||
if (errors.count && Button("Clear all errors")) {
|
||||
clear_errors(thread_context());
|
||||
errors.count = 0;
|
||||
}
|
||||
for_each(e, errors) {
|
||||
auto button_label = format_cstring("Clear##%d", e);
|
||||
if (Button(button_label)) {
|
||||
clear_error(thread_context(), errors[e]);
|
||||
continue;
|
||||
}
|
||||
SameLine();
|
||||
Text(" [%d] %s", e, to_string(errors[e]).data);
|
||||
}
|
||||
Spacing();
|
||||
if (Button("Push some error")) {
|
||||
log_warning("This is a warning.");
|
||||
log_error("... and this is an error.");
|
||||
}
|
||||
|
||||
End();
|
||||
}
|
||||
@ -1,4 +1,366 @@
|
||||
#include "Ex1.cpp"
|
||||
// #include "
|
||||
|
||||
struct ExplorerUI {
|
||||
// u8 search_input[64];
|
||||
// u8 secondary_input[64];
|
||||
};
|
||||
|
||||
struct Explorer {
|
||||
// A bunch of flags?
|
||||
// Icon cache?
|
||||
// Array<Image_Data> frame_textures;
|
||||
};
|
||||
|
||||
struct Ex1_NTFS_Enumeration {
|
||||
b32 initialized;
|
||||
b32 threads_started;
|
||||
|
||||
ArrayView<Thread> threads;
|
||||
Array<Thread*> threads_in_flight;
|
||||
};
|
||||
|
||||
// #Ex1_global_state
|
||||
global ExplorerUI explorer_ui;
|
||||
global Explorer explorer;
|
||||
global Ex1_NTFS_Enumeration ex1_ntfs;
|
||||
|
||||
#define HOTKEY_ID_BRING_TO_FOREGROUND 1
|
||||
#define VK_SPACE_KEY_CODE 0x20
|
||||
// #define HOTKEY_ID_HIDE_TITLEBAR
|
||||
|
||||
void Ex1_Unregister_Global_Hotkeys () {
|
||||
UnregisterHotKey(nullptr, HOTKEY_ID_BRING_TO_FOREGROUND);
|
||||
}
|
||||
|
||||
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-Shift-Alt-Space");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#define USE_CTRL true
|
||||
#define USE_SHIFT true
|
||||
#define USE_ALT true
|
||||
#define TRIGGER_ONCE true
|
||||
#define TRIGGER_EVERY_FRAME false
|
||||
#define KEY_UNUSED false
|
||||
|
||||
// #program_hotkeys (Not specific to Ex1)
|
||||
global Key_Combination program_exit_hotkey { ImGuiKey_W, USE_CTRL, USE_SHIFT, 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() {
|
||||
update_global_keyboard_state();
|
||||
// #program_hotkeys
|
||||
if (check_key_combination(&program_exit_hotkey)) {
|
||||
return true;
|
||||
}
|
||||
if (check_key_combination(&program_minimize_hotkey)) {
|
||||
Win32_Minimize_Window_To_Tray(get_main_window_pointer());
|
||||
}
|
||||
// #Ex1_hotkeys
|
||||
return false;
|
||||
}
|
||||
|
||||
// #Workspaces are FOR DEVELOPMENT ONLY.
|
||||
struct Ex1_Workspace {
|
||||
s32 path_select;
|
||||
s32 file_select;
|
||||
|
||||
RadixSort file_size_radix;
|
||||
RadixSort file_modtime_radix;
|
||||
RadixSort dir_modtime_radix;
|
||||
bool sort_completed;
|
||||
|
||||
// Reordered strings:
|
||||
ArrayView<string> files_sorted_by_size;
|
||||
ArrayView<string> files_sorted_by_modtime;
|
||||
};
|
||||
|
||||
global Ex1_Workspace ex1w;
|
||||
|
||||
void free_ex1_workspace_and_reset () {
|
||||
if (ex1w.sort_completed) {
|
||||
push_allocator(GPAllocator());
|
||||
|
||||
radix_sort_free(&ex1w.file_size_radix);
|
||||
radix_sort_free(&ex1w.file_modtime_radix);
|
||||
radix_sort_free(&ex1w.dir_modtime_radix);
|
||||
|
||||
array_free(ex1w.files_sorted_by_size);
|
||||
array_free(ex1w.files_sorted_by_modtime);
|
||||
|
||||
zero_struct(&ex1w);
|
||||
}
|
||||
}
|
||||
|
||||
// #TODO: Move all sort stuff to OS_Win32?
|
||||
// Make a general version of this that takes two ArrayView<T> and reorders.
|
||||
// There's no need to do this until we have the filtered results.
|
||||
void os_win32_reorder_files_by_radix (RadixSort* r, ArrayView<string>* files, bool reverse_order=false) {
|
||||
Timed_Block_Print("os_win32_reorder_files_by_radix");
|
||||
// Where are my source files!?
|
||||
(*files) = ArrayView<string>(r->ranks.count);
|
||||
for_each(f, (*files)) {
|
||||
// (*files)[f] = get_file_copy(stfe, r->ranks[f]);
|
||||
(*files)[f] = get_file_string_view(stfe, r->ranks[f]);
|
||||
}
|
||||
}
|
||||
|
||||
void Ex1_show_enumeration_workspace () { using namespace ImGui;
|
||||
push_imgui_window("Enumerated Data Workspace");
|
||||
|
||||
if (!ex1w.sort_completed) {
|
||||
push_allocator(GPAllocator());
|
||||
Timed_Block_Print("radix_sort_u64: file sizes, file modtimes, directory modtimes");
|
||||
ArrayView<u64> sizes = to_view(*stfe->files.sizes);
|
||||
radix_sort_u64(&ex1w.file_size_radix, sizes.data, (u32)sizes.count);
|
||||
ArrayView<u64> file_modtimes = to_view(*stfe->files.modtimes);
|
||||
radix_sort_u64(&ex1w.file_modtime_radix, file_modtimes.data, (u32)file_modtimes.count);
|
||||
ArrayView<u64> dirs_modtimes = to_view(*stfe->dirs.modtimes);
|
||||
radix_sort_u64(&ex1w.dir_modtime_radix, dirs_modtimes.data, (u32)dirs_modtimes.count);
|
||||
// Create ArrayView<string>, ArrayView<u64> sizes, and ArrayView<u64> modtimes
|
||||
os_win32_reorder_files_by_radix(&ex1w.file_size_radix, &ex1w.files_sorted_by_size);
|
||||
os_win32_reorder_files_by_radix(&ex1w.file_modtime_radix, &ex1w.files_sorted_by_modtime);
|
||||
// reordering by the rank permutations generated by RadixSort.
|
||||
ex1w.sort_completed = true;
|
||||
}
|
||||
|
||||
if (!ex1w.sort_completed) { return; }
|
||||
|
||||
SeparatorText("Files ordered by modtime");
|
||||
s32 file_count = (s32)ex1w.files_sorted_by_modtime.count;
|
||||
SliderInt("Select file index", &ex1w.file_select, 0, file_count-1);
|
||||
string file_name = copy_string(ex1w.files_sorted_by_modtime[ex1w.file_select]);
|
||||
Text("%s", file_name.data);
|
||||
u32 radix_index = rank(&ex1w.file_modtime_radix, ex1w.file_select);
|
||||
Text("date modified: %s", format_time_datetime(get_file_modtime(stfe, radix_index)).data);
|
||||
|
||||
SeparatorText("Files ordered by size");
|
||||
file_count = (s32)ex1w.files_sorted_by_size.count;
|
||||
// SliderInt("Select file index", &ex1w.file_select, 0, file_count-1);
|
||||
file_name = copy_string(ex1w.files_sorted_by_size[ex1w.file_select]);
|
||||
Text("%s", file_name.data);
|
||||
radix_index = rank(&ex1w.file_size_radix, ex1w.file_select);
|
||||
Text("size: %s", format_bytes(get_file_size_bytes(stfe, radix_index)).data);
|
||||
// Text("date modified: %s", format_time_datetime(get_file_modtime(stfe, radix_index)).data);
|
||||
|
||||
if (Button("Count unique UTF-8 characters")) {
|
||||
count_unique_utf8_chars();
|
||||
}
|
||||
|
||||
Text("unique_codepoints_utf32.count: %", unique_codepoints_utf32.count);
|
||||
|
||||
for_each(u, unique_codepoints_utf32) {
|
||||
Text("[%d] Code point as hex: 0x%X", u, unique_codepoints_utf32[u]);
|
||||
}
|
||||
|
||||
Text("files_sorted_by_size size in bytes: %lld", ex1w.files_sorted_by_size.count * sizeof(string));
|
||||
Text("files_sorted_by_modtime size in bytes: %lld", ex1w.files_sorted_by_modtime.count * sizeof(string));
|
||||
|
||||
for (s64 i = 1; i < 128; i += 1) {
|
||||
u8 cstring[2] = {};
|
||||
cstring[0] = (u8)i;
|
||||
cstring[1] = 0;
|
||||
Text("codepoint[0x%X]: %s, count: %lld", i, cstring, count_ascii_codepoints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Ex1_Control_Panel () { using namespace ImGui;
|
||||
f64 frame_time = GetUnixTimestamp();
|
||||
Table<string, OS_Drive*>* drive_table = get_drive_table();
|
||||
|
||||
push_imgui_window("Control Panel");
|
||||
|
||||
// if (Button("Debug break")) { debug_break(); }
|
||||
if (/*Button("Discover drives") ||*/!table_is_valid(drive_table)) { Win32_Discover_Drives(); }
|
||||
|
||||
// Text("ntfs_workspace_files_loaded: %s", ntfs_workspace_files_loaded()? "true": "false");
|
||||
// if (ntfs_workspace_files_loaded()) {
|
||||
// Ex1_show_ntfs_workspace();
|
||||
// return;
|
||||
// }
|
||||
|
||||
bool all_drives_enumerated = stfe && stfe->thread_completed;
|
||||
push_allocator(temp());
|
||||
ArrayView<OS_Drive*> drives = os_get_available_drives(); // only includes drives that are ready.
|
||||
|
||||
|
||||
if (!USN_Journal_Monitoring_Ready(drives[0]) && Button("Enable USN Monitoring for all drives")) {
|
||||
Win32_Enable_USN_Journal_Monitoring(drives);
|
||||
}
|
||||
if (USN_Journal_Monitoring_Ready(drives[0]) && Button("Query USN Journal")) {
|
||||
Query_USN_Journal(drives);
|
||||
}
|
||||
|
||||
if (!all_drives_enumerated) {
|
||||
// Text("drive_table is valid: %d", table_is_valid(drive_table));
|
||||
for_each(i, drives) {
|
||||
OS_Drive* drive = drives[i];
|
||||
|
||||
Text(" > [%d] drive letter: %s (is_present: %d)", i + 1, drive->label.data, drive->is_present);
|
||||
if (drive->time_to_enumerate != 0) {
|
||||
SameLine();
|
||||
Text("Enumerated in %.2f seconds", drive->time_to_enumerate);
|
||||
}
|
||||
// SameLine();
|
||||
// if (Button(format_cstring("Read NTFS MFT Raw##%s", drive->label.data))) {
|
||||
// push_arena(thread_context()->arena);
|
||||
// Error* error = NTFS_MFT_read_raw(drive);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
s32 drives_enumerated = 0;
|
||||
for_each(d, drives) {
|
||||
OS_Drive* drive = drives[d];
|
||||
if (!drives[d]->time_to_enumerate) { continue; }
|
||||
if (!drives[d]->data) { continue; }
|
||||
|
||||
if (drives[d]->data->paths.offsets->count > 0) {
|
||||
drives_enumerated += 1;
|
||||
}
|
||||
}
|
||||
// bool all_drives_enumerated = !ex1_ntfs.threads_in_flight.count
|
||||
// && (drives_enumerated == drives.count);
|
||||
|
||||
// string file_path = format_string_temp("%s_DriveData.bin", os_get_machine_name().data);
|
||||
string file_path = "D:/Projects/Cpp/Musa-Cpp-Lib-V2/bin/MUSA-PC3_DriveData.bin";// FIXED path.
|
||||
Text("fixed file_path: %s", file_path.data);
|
||||
if (!all_drives_enumerated && file_exists(file_path)) { // #autoload
|
||||
Deserialize_ST_File_Enumeration(file_path);
|
||||
}
|
||||
if (drives.count > 0 && !all_drives_enumerated && file_exists(file_path) && Button("Load from file (this machine)")) {
|
||||
Deserialize_ST_File_Enumeration(file_path);
|
||||
// Deserialize_Win32_Drives(file_path);
|
||||
}
|
||||
|
||||
// if (file_enum_multithreading_started()) {
|
||||
// if (thread_is_done(drive_enumeration->master_thread)) {
|
||||
// push_allocator(GPAllocator());
|
||||
// // Thread* thread = drive_enumeration->master_thread;
|
||||
// // auto task = thread_task(Drive_Enumeration);
|
||||
// // Nothing to free?
|
||||
// thread_deinit(drive_enumeration->master_thread, true);
|
||||
// }
|
||||
// }
|
||||
|
||||
// #FileEnumerationST
|
||||
if (stfe && stfe->thread_started) {
|
||||
// print dirs enumerated, etc
|
||||
if (!stfe->thread_completed) Text("Enumeration Thread Active (elapsed: %s)", format_time_seconds(frame_time-stfe->start_time).data);
|
||||
if (stfe->dirs.offsets) {
|
||||
s64 dirs_enumerated = stfe->dirs.offsets->count;
|
||||
Text("Dirs enumerated: %lld", dirs_enumerated);
|
||||
// if (!stfe->thread_completed) Text("Current dir: %s", get_last_path_copy(stfe).data);
|
||||
}
|
||||
if (stfe->files.offsets) {
|
||||
s64 files_enumerated = stfe->files.offsets->count;
|
||||
Text("Files enumerated: %lld", files_enumerated);
|
||||
// if (!stfe->thread_completed) Text("Current file: %s", get_last_file_copy(stfe).data);
|
||||
}
|
||||
|
||||
if (stfe->thread_completed) {
|
||||
Text("String bytes stored: %s", format_bytes(stfe->dirs.strings->count + stfe->files.strings->count).data);
|
||||
Text("Elapsed time: %s", format_time_seconds(stfe->end_time-stfe->start_time).data);
|
||||
}
|
||||
}
|
||||
if (stfe && stfe->thread_started && !stfe->thread_completed) {
|
||||
Assert(stfe->master_thread != nullptr);
|
||||
if (thread_is_done(stfe->master_thread)) {
|
||||
thread_deinit(stfe->master_thread, true);
|
||||
stfe->thread_completed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (all_drives_enumerated && Button("Save enumerated data")) {
|
||||
if (!Serialize_ST_File_Enumeration(file_path)) {
|
||||
log_error("Failed to write enumerated files");
|
||||
os_log_error();
|
||||
}
|
||||
}
|
||||
|
||||
if (all_drives_enumerated && Button("Reset State")) {
|
||||
free_ex1_workspace_and_reset();
|
||||
free_stfe_and_reset();
|
||||
return;
|
||||
}
|
||||
|
||||
if (all_drives_enumerated) {
|
||||
Ex1_show_enumeration_workspace();
|
||||
}
|
||||
|
||||
if (drives.count > 0 && !all_drives_enumerated && Button("Enumerate all NTFS drives")) { // && ex1_ntfs.initialized
|
||||
os_run_file_enumeration_single_threaded();
|
||||
// os_run_file_enumeration_multithreaded(); // #disabled for now
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ImGui_Debug_Panel () { using namespace ImGui;
|
||||
push_allocator(temp());
|
||||
|
||||
Begin("Debug Panel");
|
||||
// #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");
|
||||
lock_guard(&arena_free_list->mutex);
|
||||
for (u8 i = 0; i < Arena_Reserve_Count; i += 1) {
|
||||
#if ARENA_DEBUG
|
||||
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
|
||||
);
|
||||
#else
|
||||
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],
|
||||
"disabled in release mode"
|
||||
);
|
||||
#endif
|
||||
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");
|
||||
SeparatorText("Errors");
|
||||
ArrayView<Error*> errors = get_all_errors(thread_context());
|
||||
if (errors.count && Button("Clear all errors")) {
|
||||
clear_errors(thread_context());
|
||||
errors.count = 0;
|
||||
}
|
||||
for_each(e, errors) {
|
||||
auto button_label = format_cstring("Clear##%d", e);
|
||||
if (Button(button_label)) {
|
||||
clear_error(thread_context(), errors[e]);
|
||||
continue;
|
||||
}
|
||||
SameLine();
|
||||
Text(" [%d] %s", e, to_string(errors[e]).data);
|
||||
}
|
||||
Spacing();
|
||||
if (Button("Push some error")) {
|
||||
log_warning("This is a warning.");
|
||||
log_error("... and this is an error.");
|
||||
}
|
||||
|
||||
End();
|
||||
}
|
||||
|
||||
void Explorer_ImGui_Application_Win32 () {
|
||||
{ // :Win32_Initialize_Extended
|
||||
|
||||
Loading…
Reference in New Issue
Block a user