Musa-Cpp-Lib-V2/lib/Base/Base_Thread_Context.h
Musa 55ce432097 Replace build scripts with cmake (#3)
Reviewed-on: #3
Co-authored-by: Musa <musasmahmood@gmail.com>
Co-committed-by: Musa <musasmahmood@gmail.com>
2025-12-19 02:28:51 +00:00

176 lines
5.1 KiB
C++

// #hacky fwd declares
struct Source_Code_Location {
string file_name;
string function_name;
s32 line_number;
};
struct Stack_Trace_Node {
Stack_Trace_Node* next;
// Information
Source_Code_Location data;
s32 call_depth;
};
struct Error;
struct Graphics;
struct Thread_Context {
ExpandableArena* temp; // Used for temporary allocations, scratch space.
ExpandableArena* arena; // general purpose local arena
Allocator allocator;
s32 thread_idx;
// u16 _padding0;
u16 default_allocator_alignment = 16;
Logger logger = {nullptr, nullptr};
String_Builder* log_builder; // String builder used by log() and log_error_internal()
String_Builder* string_builder; // Secondary builder just for convenience!
Stack_Trace_Node* stack_trace; // use `list(stack_trace)` in watch window of raddbg to view as array!
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 = default_allocator();
Error* first_error = nullptr;
Error* current_error = nullptr;
Arena* error_arena;
// Graphics stuff:
Graphics* graphics;
void* userdata; // for appending other arenas, etc.
};
// C_LINKAGE thread_static TCTX* tctx_thread_local;
thread_static Thread_Context* thread_local_context;
// #TODO #NewContext void create_thread_context (Thread_Context** context, string thread_name, bool is_main_thread);
// Thread-context #Errors:
internal void Bootstrap_Main_Thread_Context ();
struct Push_Allocator {
Thread_Context* context;
Allocator old_allocator;
Push_Allocator (Allocator new_allocator) {
context = thread_context();
if (this->context != nullptr) {
old_allocator = context->allocator;
context->allocator = new_allocator;
} else {
old_allocator = default_allocator();
}
}
~Push_Allocator () {
if (this->context != nullptr) {
context->allocator = old_allocator;
}
}
};
// #stack_trace
#define ENABLE_STACK_TRACE BUILD_DEBUG
void push_stack_trace_internal (Thread_Context* context, string file_name, string function_name, s32 line_number) {
if (context == nullptr) return;
Assert(context != nullptr);
// #no_context allocation
Stack_Trace_Node* new_node = (Stack_Trace_Node*)default_allocator_new(sizeof(Stack_Trace_Node));
new_node->data.file_name = file_name;
new_node->data.function_name = function_name;
new_node->data.line_number = line_number;
new_node->next = nullptr;
if (context->stack_trace == nullptr) {
new_node->call_depth = 1;
} else {
new_node->call_depth = context->stack_trace->call_depth + 1;
new_node->next = context->stack_trace;
}
context->stack_trace = new_node;
}
void pop_stack_trace_internal (Thread_Context* context) {
if (context == nullptr) return;
Stack_Trace_Node* old_node = context->stack_trace;
context->stack_trace = old_node->next;
default_allocator_free(old_node);
}
#if ENABLE_STACK_TRACE
#define stack_trace() \
Push_Stack_Trace Concat(_push_stack_trace_guard_, __LINE__)(__FILE__, __FUNCTION__, __LINE__)
#else
#define stack_trace()
#endif
struct Push_Stack_Trace {
Thread_Context* context;
Push_Stack_Trace (string file_name, string function_name, s32 line_number) {
context = thread_context();
push_stack_trace_internal(context, file_name, function_name, line_number);
}
~Push_Stack_Trace () {
pop_stack_trace_internal(context);
}
};
// #TODO: precede with something like: os_write_string_unsynchronized("Fatal Error!\n\nStack trace:", true);
string generate_stack_trace (Thread_Context* context) {
// #no_context - we want this to work even if context is utterly broken.
String_Builder* sb = new_string_builder(Arena_Reserve::Size_64K);
Stack_Trace_Node* node = context->stack_trace;
print_to_builder(sb, "Thread index: %d, thread name: %s\n\n", context->thread_idx, context->thread_name.data);
while (node) {
append(sb, format_string("%s:%d: %s\n", node->data.file_name.data, node->data.line_number, node->data.function_name.data));
node = node->next;
}
append(sb, "\n");
push_allocator(default_allocator());
string stack_trace_copy = builder_to_string(sb);
free_string_builder(sb);
return stack_trace_copy;
}
// We don't want to use context logger here!
void print_stack_trace () {
Thread_Context* context = thread_context();
Stack_Trace_Node* node = context->stack_trace;
constexpr bool TO_STANDARD_ERROR = true;
os_write_string_unsynchronized(generate_stack_trace(context), TO_STANDARD_ERROR);
// while (node) {
// os_write_string_unsynchronized(node->data.file_name, TO_STANDARD_ERROR);
// string line_number_str = format_string(":%d: ", node->data.line_number); // maybe I shouldn't do this?
// os_write_string_unsynchronized(line_number_str, TO_STANDARD_ERROR);
// // os_write_string_unsynchronized("'", TO_STANDARD_ERROR);
// os_write_string_unsynchronized(node->data.function_name, TO_STANDARD_ERROR);
// os_write_string_unsynchronized("\n", TO_STANDARD_ERROR);
// node = node->next;
// }
}