[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)
|
if (MSVC)
|
||||||
# Suppress warning: C++ exception handler used, but unwind semantics are not enabled.
|
# Suppress warning: C++ exception handler used, but unwind semantics are not enabled.
|
||||||
add_compile_options(/wd4530)
|
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()
|
endif()
|
||||||
|
|
||||||
SET (EXE_NAME "mexplore_v2")
|
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_dx11.cpp
|
||||||
lib/third_party/dear-imgui/imgui_impl_win32.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
|
SET (INCLUDE_DIRS
|
||||||
${PROJECT_SOURCE_DIR}/src
|
${PROJECT_SOURCE_DIR}/src
|
||||||
${PROJECT_SOURCE_DIR}/lib
|
${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
|
${PROJECT_SOURCE_DIR}/lib/third_party
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -49,6 +81,7 @@ endif()
|
|||||||
SET (SYSTEM_LIBRARIES
|
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_include_directories(${EXE_NAME} PRIVATE ${INCLUDE_DIRS})
|
||||||
target_link_libraries(${EXE_NAME} PRIVATE ${LINK_LIBS_DIRS} ${SYSTEM_LIBRARIES})
|
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) {
|
void* internal_alloc (s64 size) {
|
||||||
Allocator allocator = context_allocator();
|
Allocator allocator = context_allocator();
|
||||||
void* result = allocator.proc(Allocator_Mode::ALLOCATE, size, 0, nullptr, allocator.data);
|
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);
|
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
|
#pragma once
|
||||||
|
|
||||||
|
#include "Base.h"
|
||||||
|
|
||||||
#define ALLOCATOR_DEBUG_MODE 1
|
#define ALLOCATOR_DEBUG_MODE 1
|
||||||
#define ALLOCATOR_POISON_MEMORY_ON_ALLOCATION \
|
#define ALLOCATOR_POISON_MEMORY_ON_ALLOCATION \
|
||||||
(BUILD_DEBUG && ALLOCATOR_DEBUG_MODE)
|
(BUILD_DEBUG && ALLOCATOR_DEBUG_MODE)
|
||||||
@ -120,6 +122,4 @@ template <typename T> T* copy_struct (T* src) {
|
|||||||
memcpy(dst, src, sizeof(T));
|
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 ();
|
|
||||||
|
|||||||
@ -310,3 +310,114 @@ void* fixed_arena_allocator_proc (Allocator_Mode mode, s64 requested_size, s64 o
|
|||||||
|
|
||||||
return nullptr;
|
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
|
#pragma once
|
||||||
|
|
||||||
|
#include "Base.h"
|
||||||
|
#include "Array.h"
|
||||||
|
#include "Allocator.h"
|
||||||
|
|
||||||
struct ExpandableArena; // fwd declare #temp
|
struct ExpandableArena; // fwd declare #temp
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Arena.h"
|
||||||
|
|
||||||
constexpr s64 ARRAY_ARENA_START_OFFSET = 64;
|
constexpr s64 ARRAY_ARENA_START_OFFSET = 64;
|
||||||
|
|
||||||
template <typename T>
|
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.
|
// Strongly influenced by Array.jai in Basic module.
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Allocator.h"
|
||||||
|
|
||||||
// For Arena-Backed arrays use ArenaArray
|
// For Arena-Backed arrays use ArenaArray
|
||||||
|
|
||||||
MSVC_RUNTIME_CHECKS_OFF
|
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;
|
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:
|
// Helper macros for raw arrays:
|
||||||
#define ArrayCount(array) sizeof(array) / sizeof(array[0])
|
#define ArrayCount(array) sizeof(array) / sizeof(array[0])
|
||||||
// For-loop construct macros
|
// For-loop construct macros
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
// See Context_Base in jai, and TCTX in raddebugger:
|
// See Context_Base in jai, and TCTX in raddebugger:
|
||||||
|
#include "Base_Thread_Context.h"
|
||||||
|
|
||||||
internal void Bootstrap_Main_Thread_Context () {
|
internal void Bootstrap_Main_Thread_Context () {
|
||||||
// Timed_Block_Print_No_Context("Bootstrap_Main_Thread_Context");
|
// Timed_Block_Print_No_Context("Bootstrap_Main_Thread_Context");
|
||||||
|
|||||||
@ -1,31 +1,37 @@
|
|||||||
// #hacky fwd declares
|
#pragma once
|
||||||
struct Error;
|
|
||||||
struct Graphics;
|
#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 {
|
struct Thread_Context {
|
||||||
ExpandableArena* temp; // Used for temporary allocations, scratch space.
|
// ExpandableArena* temp; // Used for temporary allocations, scratch space.
|
||||||
ExpandableArena* arena; // general purpose local arena
|
// ExpandableArena* arena; // general purpose local arena
|
||||||
|
|
||||||
Allocator allocator;
|
Allocator allocator;
|
||||||
s32 thread_idx;
|
s32 thread_idx;
|
||||||
// u16 _padding0;
|
// u16 _padding0;
|
||||||
u16 GPAllocator_alignment = 16;
|
u16 GPAllocator_alignment = 16;
|
||||||
Logger logger = {nullptr, nullptr};
|
// Logger logger = {nullptr, nullptr};
|
||||||
String_Builder* log_builder;
|
// String_Builder* log_builder;
|
||||||
// Stack_Trace* stack_trace;
|
// 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
|
Thread_Context* parent_thread_context = nullptr; // so we can remove from above array
|
||||||
|
|
||||||
string thread_name;
|
string thread_name;
|
||||||
|
|
||||||
Allocator error_allocator = GPAllocator();
|
Allocator error_allocator = GPAllocator();
|
||||||
Error* first_error = nullptr;
|
// Error* first_error = nullptr;
|
||||||
Error* current_error = nullptr;
|
// Error* current_error = nullptr;
|
||||||
Arena* error_arena;
|
// Arena* error_arena;
|
||||||
|
|
||||||
// Graphics stuff:
|
// Graphics stuff:
|
||||||
Graphics* graphics;
|
// Graphics* graphics;
|
||||||
|
|
||||||
void* userdata; // for appending other arenas, etc.
|
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
|
#if GP_ALLOCATOR_TRACK_ALLOCATIONS
|
||||||
global General_Allocator gAllocator; // @Shared
|
global General_Allocator gAllocator; // @Shared
|
||||||
global Mutex allocator_mutex;
|
global Mutex allocator_mutex;
|
||||||
|
|||||||
@ -1,5 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Base.h"
|
||||||
|
#include "Allocator.h"
|
||||||
|
#include "Array.h"
|
||||||
|
|
||||||
#define GP_ALLOCATOR_TRACK_ALLOCATIONS BUILD_DEBUG
|
#define GP_ALLOCATOR_TRACK_ALLOCATIONS BUILD_DEBUG
|
||||||
#define GP_ALLOCATOR_VERY_DEBUG BUILD_DEBUG && 0
|
#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_Realloc(old_sz, ptr, sz, align) gp_aligned_realloc(old_sz, ptr, sz, align)
|
||||||
#define Aligned_Free(ptr) std::free(ptr)
|
#define Aligned_Free(ptr) std::free(ptr)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct Allocation {
|
struct Allocation {
|
||||||
s64 size;
|
s64 size;
|
||||||
void* memory;
|
void* memory;
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
#include "MString.h"
|
||||||
|
|
||||||
constexpr u32 HASH_INIT = 5381;
|
constexpr u32 HASH_INIT = 5381;
|
||||||
u32 sdbm_hash (void* data, s64 size) {
|
u32 sdbm_hash (void* data, s64 size) {
|
||||||
u32 h = HASH_INIT;
|
u32 h = HASH_INIT;
|
||||||
|
|||||||
@ -1,4 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Base.h"
|
||||||
|
#include "Array.h"
|
||||||
|
#include "Arena_Array.h"
|
||||||
|
|
||||||
// #TODO: #strings:
|
// #TODO: #strings:
|
||||||
// [ ] see: #Parsing stuff:
|
// [ ] see: #Parsing stuff:
|
||||||
// [?] How do I accept variadic arguments of any type to my print function?
|
// [?] 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
|
// #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!
|
// strings for backwards compatibility reasons. #FIX if something doesn't follow this rule!
|
||||||
bool is_valid (string s) {
|
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:
|
// #Timing API:
|
||||||
#define System_Timed_Block_Print(name) \
|
#define System_Timed_Block_Print(name) \
|
||||||
system_timed_block_print Concat(_sys_timed_block_print_guard, __LINE__)(name)
|
system_timed_block_print Concat(_sys_timed_block_print_guard, __LINE__)(name)
|
||||||
|
|||||||
@ -5,6 +5,8 @@
|
|||||||
// before terminating.
|
// before terminating.
|
||||||
// Or we can move child threads up to the parent?
|
// Or we can move child threads up to the parent?
|
||||||
|
|
||||||
|
#include "OS_Win32.h"
|
||||||
|
|
||||||
constexpr s64 FILETIME_TO_UNIX = 116444736000000000i64;
|
constexpr s64 FILETIME_TO_UNIX = 116444736000000000i64;
|
||||||
f64 GetUnixTimestamp () {
|
f64 GetUnixTimestamp () {
|
||||||
FILETIME fileTime;
|
FILETIME fileTime;
|
||||||
|
|||||||
@ -1,6 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Base.h"
|
||||||
|
#include "Array.h"
|
||||||
|
#include "Threads.h"
|
||||||
|
|
||||||
#pragma comment(lib, "user32")
|
#pragma comment(lib, "user32")
|
||||||
#pragma comment(lib, "shell32")
|
#pragma comment(lib, "shell32")
|
||||||
#include <shellapi.h>
|
#include <shellapi.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <d3d11.h>
|
||||||
|
#include <dwmapi.h>
|
||||||
|
|
||||||
f64 GetUnixTimestamp ();
|
f64 GetUnixTimestamp ();
|
||||||
s64 GetUnixTimestampNanoseconds ();
|
s64 GetUnixTimestampNanoseconds ();
|
||||||
|
|||||||
@ -49,7 +49,6 @@
|
|||||||
// OS-Abstraction Layer
|
// OS-Abstraction Layer
|
||||||
#include "lib/Base/Threads.cpp"
|
#include "lib/Base/Threads.cpp"
|
||||||
#include "lib/OS/OS_Filesystem.cpp"
|
#include "lib/OS/OS_Filesystem.cpp"
|
||||||
|
|
||||||
#include "lib/Base/Thread_Group.cpp"
|
#include "lib/Base/Thread_Group.cpp"
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#if OS_WINDOWS
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
|
#include "Base_Entry_Point.h"
|
||||||
|
#include "Timing.h"
|
||||||
|
|
||||||
internal void Main_Entry_Point (int argc, WCHAR **argv);
|
internal void Main_Entry_Point (int argc, WCHAR **argv);
|
||||||
|
|
||||||
#if OS_WINDOWS
|
#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 () {
|
void Explorer_ImGui_Application_Win32 () {
|
||||||
{ // :Win32_Initialize_Extended
|
{ // :Win32_Initialize_Extended
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user