Show main thread errors in UI.
This commit is contained in:
parent
7013ca673f
commit
7755ef9225
@ -21,6 +21,7 @@
|
|||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#undef ERROR // why...
|
#undef ERROR // why...
|
||||||
|
#undef NO_ERROR // ugh...
|
||||||
#else
|
#else
|
||||||
#error "This configuration is NOT supported. Only Windows with MSVC is currently supported."
|
#error "This configuration is NOT supported. Only Windows with MSVC is currently supported."
|
||||||
#endif
|
#endif
|
||||||
@ -324,5 +325,6 @@ struct Mutex_Lock_Guard {
|
|||||||
#define for_each_index(_idx_, _until_) for (s64 _idx_ = 0; _idx_ < _until_; ++_idx_)
|
#define for_each_index(_idx_, _until_) for (s64 _idx_ = 0; _idx_ < _until_; ++_idx_)
|
||||||
// For-loops for ArrayView<> compatible types
|
// For-loops for ArrayView<> compatible types
|
||||||
#define for_each(_idx_, _array_) for (s64 _idx_ = 0; _idx_ < (_array_).count; ++_idx_)
|
#define for_each(_idx_, _array_) for (s64 _idx_ = 0; _idx_ < (_array_).count; ++_idx_)
|
||||||
|
#define for_each_reverse(_idx_, _array_) for (s64 _idx_ = (_array_).count-1; _idx_ >= 0; _idx_--)
|
||||||
// #define for_each_starting_at(_it_, _array_, _start_) for (s64 _it_ = _start_; _it_ < (_array_).count; _it_ += 1)
|
// #define for_each_starting_at(_it_, _array_, _start_) for (s64 _it_ = _start_; _it_ < (_array_).count; _it_ += 1)
|
||||||
|
|
||||||
|
|||||||
@ -16,7 +16,7 @@ struct Thread_Context {
|
|||||||
// 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* thread_that_created_me = 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;
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
// #NOTE: To keep things simple, all allocations for Error should be via GPAllocator.
|
// #NOTE: To keep things simple, all allocations for Error should be via GPAllocator.
|
||||||
// We really allocate two things: the Error struct and the error string copy.
|
// We really allocate two things: the Error struct and the error string copy.
|
||||||
|
|
||||||
|
#define NO_ERROR nullptr
|
||||||
|
|
||||||
enum class ErrorClass: s32 {
|
enum class ErrorClass: s32 {
|
||||||
NONE = 0, // should not be used, just to avoid a default value being assigned.
|
NONE = 0, // should not be used, just to avoid a default value being assigned.
|
||||||
WARNING = 1,
|
WARNING = 1,
|
||||||
@ -26,6 +28,7 @@ struct Error {
|
|||||||
char* error_severity (ErrorClass severity) {
|
char* error_severity (ErrorClass severity) {
|
||||||
switch (severity) {
|
switch (severity) {
|
||||||
case ErrorClass::NONE: {
|
case ErrorClass::NONE: {
|
||||||
|
return "[NONE]";
|
||||||
} break;
|
} break;
|
||||||
case ErrorClass::WARNING: {
|
case ErrorClass::WARNING: {
|
||||||
return "[WARNING]";
|
return "[WARNING]";
|
||||||
@ -40,7 +43,7 @@ char* error_severity (ErrorClass severity) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_error (Error* new_error);
|
void push_error (Thread_Context* tctx, Error* new_error);
|
||||||
|
|
||||||
string to_string (Error* error) {
|
string to_string (Error* error) {
|
||||||
return { error->count, error->data };
|
return { error->count, error->data };
|
||||||
@ -55,6 +58,9 @@ string to_string (Error* error) {
|
|||||||
#define log_warning(fmt, ...) \
|
#define log_warning(fmt, ...) \
|
||||||
Log_Error_2(__FILE__, __FUNCTION__, __LINE__, ErrorClass::WARNING, fmt, ##__VA_ARGS__)
|
Log_Error_2(__FILE__, __FUNCTION__, __LINE__, ErrorClass::WARNING, fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
|
#define log_none(fmt, ...) \
|
||||||
|
Log_Error_2(__FILE__, __FUNCTION__, __LINE__, ErrorClass::NONE, fmt, ##__VA_ARGS__)
|
||||||
|
|
||||||
Error* new_error (ErrorClass severity, string error_string) {
|
Error* new_error (ErrorClass severity, string error_string) {
|
||||||
Error* error = New<Error>();
|
Error* error = New<Error>();
|
||||||
error->count = error_string.count;
|
error->count = error_string.count;
|
||||||
@ -69,11 +75,12 @@ Error* new_error (ErrorClass severity, string error_string) {
|
|||||||
//
|
//
|
||||||
|
|
||||||
void Log_Error_2 (string file_path, string function_name, s32 line_number, ErrorClass severity, string fmt, ...) {
|
void Log_Error_2 (string file_path, string function_name, s32 line_number, ErrorClass severity, string fmt, ...) {
|
||||||
Assert(thread_context() != nullptr);
|
auto tctx = thread_context();
|
||||||
push_arena(thread_context()->error_arena);
|
Assert(tctx != nullptr);
|
||||||
|
push_arena(tctx->error_arena);
|
||||||
|
|
||||||
String_Builder* sb = new_string_builder(Arena_Reserve::Size_64K);
|
String_Builder* sb = new_string_builder(Arena_Reserve::Size_64K);
|
||||||
// #TODO: prepend severity, other information
|
|
||||||
print_to_builder(sb, "%s ", error_severity(severity));
|
print_to_builder(sb, "%s ", error_severity(severity));
|
||||||
|
|
||||||
va_list args;
|
va_list args;
|
||||||
@ -86,7 +93,7 @@ void Log_Error_2 (string file_path, string function_name, s32 line_number, Error
|
|||||||
string error_string = builder_to_string(sb);
|
string error_string = builder_to_string(sb);
|
||||||
Error* error = new_error(severity, error_string);
|
Error* error = new_error(severity, error_string);
|
||||||
// Additional information
|
// Additional information
|
||||||
error->thread_id = thread_context()->thread_idx;
|
error->thread_id = tctx->thread_idx;
|
||||||
error->source_line = line_number;
|
error->source_line = line_number;
|
||||||
error->file_path = copy_string(file_path);
|
error->file_path = copy_string(file_path);
|
||||||
error->function_name = copy_string(function_name);
|
error->function_name = copy_string(function_name);
|
||||||
@ -94,21 +101,22 @@ void Log_Error_2 (string file_path, string function_name, s32 line_number, Error
|
|||||||
error->previous_error = nullptr;
|
error->previous_error = nullptr;
|
||||||
error->next_error = nullptr;
|
error->next_error = nullptr;
|
||||||
|
|
||||||
push_error(error);
|
push_error(tctx, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_error (Error* new_error) {
|
void push_error (Thread_Context* tctx, Error* new_error) {
|
||||||
|
Assert(tctx == thread_context()); // Not a real assert, just wondering if we'll ever call this with a non-local context?
|
||||||
Assert(new_error != nullptr);
|
Assert(new_error != nullptr);
|
||||||
if (new_error == nullptr) return;
|
if (new_error == nullptr) return;
|
||||||
Error* current_error = thread_context()->current_error;
|
Error* current_error = tctx->current_error;
|
||||||
if (current_error) {
|
if (current_error) {
|
||||||
current_error->next_error = new_error;
|
current_error->next_error = new_error;
|
||||||
new_error->previous_error = current_error;
|
new_error->previous_error = current_error;
|
||||||
} else {
|
} else {
|
||||||
thread_context()->first_error = new_error;
|
tctx->first_error = new_error;
|
||||||
new_error->previous_error = nullptr;
|
new_error->previous_error = nullptr;
|
||||||
}
|
}
|
||||||
thread_context()->current_error = new_error;
|
tctx->current_error = new_error;
|
||||||
|
|
||||||
switch (new_error->severity) {
|
switch (new_error->severity) {
|
||||||
case ErrorClass::NONE:
|
case ErrorClass::NONE:
|
||||||
@ -122,19 +130,32 @@ void push_error (Error* new_error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_errors () { // Reset pointers and reset error_arena
|
// push error to a context without back-linking to previous context
|
||||||
arena_reset(thread_context()->error_arena); // maybe overwrite memory?
|
void push_error_no_context (Thread_Context* tctx, Error* new_error) {
|
||||||
thread_context()->first_error = nullptr;
|
Assert(new_error != nullptr);
|
||||||
thread_context()->current_error = nullptr;
|
if (new_error == nullptr) return;
|
||||||
|
Error* current_error = tctx->current_error;
|
||||||
|
if (current_error) {
|
||||||
|
current_error->next_error = new_error;
|
||||||
|
} else {
|
||||||
|
tctx->first_error = new_error;
|
||||||
|
}
|
||||||
|
tctx->current_error = new_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clear_error (Error* error) {
|
void clear_errors (Thread_Context* tctx) { // Reset pointers and reset error_arena
|
||||||
|
arena_reset(tctx->error_arena); // maybe overwrite memory?
|
||||||
|
tctx->first_error = nullptr;
|
||||||
|
tctx->current_error = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_error (Thread_Context* tctx, Error* error) {
|
||||||
// If we want to clear a specific error (simply remove from the list)
|
// If we want to clear a specific error (simply remove from the list)
|
||||||
Assert(error != nullptr);
|
Assert(error != nullptr);
|
||||||
bool is_current_error = (thread_context()->current_error == error);
|
bool is_current_error = (tctx->current_error == error);
|
||||||
bool is_first_error = (thread_context()->first_error == error);
|
bool is_first_error = (tctx->first_error == error);
|
||||||
|
|
||||||
Error* current_error = thread_context()->first_error;
|
Error* current_error = tctx->first_error;
|
||||||
if (current_error == nullptr) return; // no errors in linked list.
|
if (current_error == nullptr) return; // no errors in linked list.
|
||||||
|
|
||||||
while (current_error != error && current_error != nullptr) {
|
while (current_error != error && current_error != nullptr) {
|
||||||
@ -145,23 +166,52 @@ void clear_error (Error* error) {
|
|||||||
Error* the_previous_error = current_error->previous_error;
|
Error* the_previous_error = current_error->previous_error;
|
||||||
Error* the_next_error = current_error->next_error;
|
Error* the_next_error = current_error->next_error;
|
||||||
// Remove current_node from linked list:
|
// Remove current_node from linked list:
|
||||||
|
if (the_previous_error) {
|
||||||
the_previous_error->next_error = the_next_error;
|
the_previous_error->next_error = the_next_error;
|
||||||
|
}
|
||||||
|
if (the_next_error) {
|
||||||
the_next_error->previous_error = the_previous_error;
|
the_next_error->previous_error = the_previous_error;
|
||||||
|
}
|
||||||
if (is_first_error && is_current_error) { // It matches the only item in the list, just empty the list:
|
if (is_first_error && is_current_error) { // It matches the only item in the list, just empty the list:
|
||||||
clear_errors();
|
clear_errors(tctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (is_first_error) {
|
if (is_first_error) {
|
||||||
// the_next_error becomes new first error.
|
// the_next_error becomes new first error.
|
||||||
thread_context()->first_error = the_next_error;
|
tctx->first_error = the_next_error;
|
||||||
}
|
}
|
||||||
if (is_current_error) {
|
if (is_current_error) {
|
||||||
// the current_error becomes the previous error
|
// the current_error becomes the previous error
|
||||||
thread_context()->current_error = the_previous_error;
|
tctx->current_error = the_previous_error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void push_errors_to_parent_thread (Thread_Context* tctx) {
|
||||||
|
if (!tctx->first_error) return;
|
||||||
|
Assert(tctx->parent_thread_context);
|
||||||
|
|
||||||
|
while (tctx->first_error) {
|
||||||
|
push_error_no_context(tctx->parent_thread_context, tctx->first_error);
|
||||||
|
clear_error(tctx, tctx->first_error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayView<Error*> get_all_errors (Thread_Context* tctx) {
|
||||||
|
Array<Error*> error_array;
|
||||||
|
// call with temp() recommended.
|
||||||
|
Error* current_error = tctx->first_error;
|
||||||
|
while (current_error) {
|
||||||
|
array_add(error_array, current_error);
|
||||||
|
current_error = current_error->next_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for_each(t, tctx->child_threads) {
|
||||||
|
// #TODO: also recurse through child threads?
|
||||||
|
}
|
||||||
|
|
||||||
|
return error_array;
|
||||||
|
}
|
||||||
|
|
||||||
// Will need to use __FILE__ and __LINE__ macros
|
// Will need to use __FILE__ and __LINE__ macros
|
||||||
|
|
||||||
|
|||||||
@ -97,7 +97,8 @@ Allocator allocator (ExpandableArena* arena_ex) {
|
|||||||
// #TODO: currently this keeps the final arena's memory. Fix this!
|
// #TODO: currently this keeps the final arena's memory. Fix this!
|
||||||
void arena_reset_to (ExpandableArena* arena_ex, Arena* last_arena, u8* starting_point) {
|
void arena_reset_to (ExpandableArena* arena_ex, Arena* last_arena, u8* starting_point) {
|
||||||
// going backwards from end of arena list
|
// going backwards from end of arena list
|
||||||
for (s64 i = arena_ex->next_arenas.count-1; i > 0; i -= 1) {
|
// for (s64 i = arena_ex->next_arenas.count-1; i >= 0; i -= 1) {
|
||||||
|
for_each_reverse(i, arena_ex->next_arenas) {
|
||||||
Arena* arena = arena_ex->next_arenas[i];
|
Arena* arena = arena_ex->next_arenas[i];
|
||||||
if (arena == last_arena) { // return to starting_point
|
if (arena == last_arena) { // return to starting_point
|
||||||
arena_ex->current = arena;
|
arena_ex->current = arena;
|
||||||
|
|||||||
@ -285,3 +285,28 @@ string to_lower_copy (string s_orig) {
|
|||||||
|
|
||||||
#define format_cstring(fmt, ...) \
|
#define format_cstring(fmt, ...) \
|
||||||
(char*)format_string(fmt, ##__VA_ARGS__).data
|
(char*)format_string(fmt, ##__VA_ARGS__).data
|
||||||
|
|
||||||
|
bool is_any (u8 c, string chars) {
|
||||||
|
for_each(i, chars) {
|
||||||
|
if (chars.data[i] == c) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string trim_right (string s, string chars, bool replace_with_zeros) {
|
||||||
|
s64 count = s.count;
|
||||||
|
|
||||||
|
for_each_reverse(i, s) {
|
||||||
|
if (is_any(s.data[i], chars)) {
|
||||||
|
if (replace_with_zeros) {
|
||||||
|
s.data[i] = 0;
|
||||||
|
}
|
||||||
|
count -= 1;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return string_view(s, 0, count);
|
||||||
|
}
|
||||||
@ -91,6 +91,9 @@ string format_string_no_context (char* format, ...);
|
|||||||
|
|
||||||
string to_lower_copy (string s_orig);
|
string to_lower_copy (string s_orig);
|
||||||
|
|
||||||
|
string DEFAULT_SPACES = "\r\t\n";
|
||||||
|
string trim_right (string s, string chars=DEFAULT_SPACES, bool replace_with_zeros=true);
|
||||||
|
|
||||||
// #TODO #Parsing stuff:
|
// #TODO #Parsing stuff:
|
||||||
// is_white_space(char: u8)
|
// is_white_space(char: u8)
|
||||||
// advance
|
// advance
|
||||||
|
|||||||
@ -276,22 +276,29 @@ internal bool thread_init (Thread* thread, Thread_Proc proc, string thread_name=
|
|||||||
thread->context->error_arena = next_arena(Arena_Reserve::Size_64M);
|
thread->context->error_arena = next_arena(Arena_Reserve::Size_64M);
|
||||||
thread->context->logger = {default_logger_proc, &default_logger};
|
thread->context->logger = {default_logger_proc, &default_logger};
|
||||||
|
|
||||||
|
thread->context->parent_thread_context = thread_context();
|
||||||
|
|
||||||
thread->os_thread.windows_thread = windows_thread;
|
thread->os_thread.windows_thread = windows_thread;
|
||||||
thread->os_thread.windows_thread_id = windows_thread_id;
|
thread->os_thread.windows_thread_id = windows_thread_id;
|
||||||
|
|
||||||
thread->proc = proc;
|
thread->proc = proc;
|
||||||
thread->index = this_thread_index;
|
thread->index = this_thread_index;
|
||||||
|
|
||||||
|
thread_context()->child_threads.allocator = allocator(thread_context()->arena);
|
||||||
|
array_add(thread_context()->child_threads, thread);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void thread_deinit (Thread* thread, bool zero_thread=false) {
|
internal void thread_deinit (Thread* thread, bool zero_thread=false) {
|
||||||
|
// Move errors from thread to parent thread
|
||||||
|
push_errors_to_parent_thread(thread->context);
|
||||||
|
|
||||||
if (thread->os_thread.windows_thread) {
|
if (thread->os_thread.windows_thread) {
|
||||||
CloseHandle(thread->os_thread.windows_thread);
|
CloseHandle(thread->os_thread.windows_thread);
|
||||||
}
|
}
|
||||||
thread->os_thread.windows_thread = nullptr;
|
thread->os_thread.windows_thread = nullptr;
|
||||||
|
|
||||||
// #TODO: before releasing arena, force-delete extra pages?
|
|
||||||
array_reset(*thread->context->log_builder);
|
array_reset(*thread->context->log_builder);
|
||||||
free_string_builder(thread->context->log_builder);
|
free_string_builder(thread->context->log_builder);
|
||||||
release_arena(thread->context->error_arena);
|
release_arena(thread->context->error_arena);
|
||||||
@ -382,12 +389,12 @@ internal string get_error_string (OS_Error_Code error_code) {
|
|||||||
|
|
||||||
LocalFree(lpMsgBuf);
|
LocalFree(lpMsgBuf);
|
||||||
|
|
||||||
return result; // trim_right(result, "\r\n");
|
return trim_right(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void log_error_code_and_string () { // #TODO: replace with call to log_error_with_code
|
internal void log_error_code_and_string () { // #TODO: replace with call to log_error_with_code
|
||||||
OS_Error_Code error_code = GetLastError();
|
OS_Error_Code error_code = GetLastError();
|
||||||
log_error(" > GetLastError code: %d, %s\n", error_code, get_error_string(error_code).data);
|
log_error(" > GetLastError code: %d, %s", error_code, get_error_string(error_code).data);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool file_is_valid (File file) {
|
internal bool file_is_valid (File file) {
|
||||||
@ -437,7 +444,7 @@ internal void file_close (File* file) {
|
|||||||
internal bool file_read (File file, u8* data, s64 bytes_to_read_count, s64* bytes_read_count) {
|
internal bool file_read (File file, u8* data, s64 bytes_to_read_count, s64* bytes_read_count) {
|
||||||
// ignore bytes_read_count if null.
|
// ignore bytes_read_count if null.
|
||||||
if (data == nullptr) {
|
if (data == nullptr) {
|
||||||
log_error("file_read called with null destination pointer.\n");
|
log_error("file_read called with null destination pointer.");
|
||||||
log_error_code_and_string();
|
log_error_code_and_string();
|
||||||
if (bytes_read_count) (*bytes_read_count) = 0;
|
if (bytes_read_count) (*bytes_read_count) = 0;
|
||||||
return false;
|
return false;
|
||||||
@ -1040,7 +1047,7 @@ bool Win32_Discover_Drives () {
|
|||||||
log(" - volume name: %s", drive->volume_name.data);
|
log(" - volume name: %s", drive->volume_name.data);
|
||||||
log(" - file_system: %s", wide_to_utf8(file_system_name).data);
|
log(" - file_system: %s", wide_to_utf8(file_system_name).data);
|
||||||
} else {
|
} else {
|
||||||
log_error("GetVolumeInformationW failed!");
|
log_error("GetVolumeInformationW failed! (drive label: %s)", drive_label.data);
|
||||||
log_error_code_and_string();
|
log_error_code_and_string();
|
||||||
drive->is_present = false;
|
drive->is_present = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -143,7 +143,7 @@ bool NTFS_read_internal (NTFS_MFT_Internal* mft, void* buffer, u64 from, u64 cou
|
|||||||
|
|
||||||
// #TODO: Release resources if we face an early return!
|
// #TODO: Release resources if we face an early return!
|
||||||
// #TODO: Maybe this doesn't need to return a value? Return an Error* instead.
|
// #TODO: Maybe this doesn't need to return a value? Return an Error* instead.
|
||||||
Dense_FS* NTFS_MFT_read_raw (OS_Drive* drive) {
|
Error* NTFS_MFT_read_raw (OS_Drive* drive) {
|
||||||
auto start_time = GetUnixTimestamp();
|
auto start_time = GetUnixTimestamp();
|
||||||
|
|
||||||
Assert(drive != nullptr);
|
Assert(drive != nullptr);
|
||||||
@ -298,7 +298,7 @@ Dense_FS* NTFS_MFT_read_raw (OS_Drive* drive) {
|
|||||||
drive->bytes_accessed = mft->bytes_accessed;
|
drive->bytes_accessed = mft->bytes_accessed;
|
||||||
drive->time_to_enumerate = (f32)(GetUnixTimestamp() - start_time);
|
drive->time_to_enumerate = (f32)(GetUnixTimestamp() - start_time);
|
||||||
|
|
||||||
return drive->data;
|
return NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct NTFS_Enumeration_Task {
|
struct NTFS_Enumeration_Task {
|
||||||
@ -306,6 +306,8 @@ struct NTFS_Enumeration_Task {
|
|||||||
|
|
||||||
ArrayView<OS_Drive*> drives;
|
ArrayView<OS_Drive*> drives;
|
||||||
// Should be part of OS_Drive!
|
// Should be part of OS_Drive!
|
||||||
|
|
||||||
|
Error* error;
|
||||||
};
|
};
|
||||||
|
|
||||||
s64 ntfs_enumeration_thread_proc (Thread* thread) {
|
s64 ntfs_enumeration_thread_proc (Thread* thread) {
|
||||||
@ -314,8 +316,9 @@ s64 ntfs_enumeration_thread_proc (Thread* thread) {
|
|||||||
log("[ntfs_enumeration_thread_proc] (Thread index: %lld) Task pointer: %p", thread->index, task);
|
log("[ntfs_enumeration_thread_proc] (Thread index: %lld) Task pointer: %p", thread->index, task);
|
||||||
|
|
||||||
for_each(d, task->drives) {
|
for_each(d, task->drives) {
|
||||||
auto result = NTFS_MFT_read_raw(task->drives[d]);
|
task->error = NTFS_MFT_read_raw(task->drives[d]);
|
||||||
if (result == nullptr) return 1;
|
// What we actually want to do here is push all our errors to return to the main thread.
|
||||||
|
if (task->error) return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
34
src/Ex1.cpp
34
src/Ex1.cpp
@ -83,15 +83,11 @@ void Ex1_Control_Panel () { using namespace ImGui;
|
|||||||
SameLine();
|
SameLine();
|
||||||
Text("Enumerated in %.2f seconds", drive->time_to_enumerate);
|
Text("Enumerated in %.2f seconds", drive->time_to_enumerate);
|
||||||
}
|
}
|
||||||
SameLine();
|
// SameLine();
|
||||||
if (Button(format_cstring("Read NTFS MFT Raw##%s", drive->label.data))) {
|
// if (Button(format_cstring("Read NTFS MFT Raw##%s", drive->label.data))) {
|
||||||
push_arena(thread_context()->arena);
|
// push_arena(thread_context()->arena);
|
||||||
// auto_release(thread_context()->arena);
|
// Error* error = NTFS_MFT_read_raw(drive);
|
||||||
auto dfs = NTFS_MFT_read_raw(drive);
|
// }
|
||||||
if (dfs == nullptr) {
|
|
||||||
log("[NTFS_MFT_read_raw] operation failed");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (drives.count > 0) {
|
if (drives.count > 0) {
|
||||||
@ -113,6 +109,7 @@ void Ex1_Control_Panel () { using namespace ImGui;
|
|||||||
// if drive count exceeds the number of threads, we need to group them so each thread
|
// if drive count exceeds the number of threads, we need to group them so each thread
|
||||||
// can enumerate multiple drives.
|
// can enumerate multiple drives.
|
||||||
// We need to distribute the drives across our available threads:
|
// We need to distribute the drives across our available threads:
|
||||||
|
// #TODO #is_present - drive_count should only include if `drive->is_present`.
|
||||||
Array<ArrayView<OS_Drive*>> drive_split;
|
Array<ArrayView<OS_Drive*>> drive_split;
|
||||||
s32 thread_count = (s32)ex1_ntfs.threads.count;
|
s32 thread_count = (s32)ex1_ntfs.threads.count;
|
||||||
drive_split.allocator = GPAllocator();
|
drive_split.allocator = GPAllocator();
|
||||||
@ -171,6 +168,9 @@ void Ex1_Control_Panel () { using namespace ImGui;
|
|||||||
auto task = thread_task(NTFS_Enumeration_Task);
|
auto task = thread_task(NTFS_Enumeration_Task);
|
||||||
release_arena(task->pool);
|
release_arena(task->pool);
|
||||||
|
|
||||||
|
// #TODO Before #deiniting thread we SHOULD copy the errors from the
|
||||||
|
// thread before it's deleted forever.
|
||||||
|
|
||||||
thread_deinit(ex1_ntfs.threads_in_flight[t], true);
|
thread_deinit(ex1_ntfs.threads_in_flight[t], true);
|
||||||
array_unordered_remove_by_index(ex1_ntfs.threads_in_flight, t);
|
array_unordered_remove_by_index(ex1_ntfs.threads_in_flight, t);
|
||||||
t -= 1; // check this element index again!
|
t -= 1; // check this element index again!
|
||||||
@ -212,6 +212,22 @@ void ImGui_Debug_Panel () { using namespace ImGui;
|
|||||||
Text(t);
|
Text(t);
|
||||||
}
|
}
|
||||||
SeparatorText("Child Threads");
|
SeparatorText("Child Threads");
|
||||||
|
SeparatorText("Errors");
|
||||||
|
ArrayView<Error*> errors = get_all_errors(thread_context());
|
||||||
|
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();
|
End();
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user