// See Context_Base in jai, and TCTX in raddebugger: struct Push_Allocator_Label { string old_label; Push_Allocator_Label(string new_label) { old_label = thread_context()->allocator_label; thread_context()->allocator_label = copy_string_untracked(new_label); } ~Push_Allocator_Label() { string_free_untracked(thread_context()->allocator_label); thread_context()->allocator_label = old_label; } }; internal void Bootstrap_Main_Thread_Context () { Timed_Block_Print_No_Context("Bootstrap_Main_Thread_Context"); // 0. Setup general allocator default_allocator_initialize_tracking(); // 1. Setup arena free list // #note: the arena free list is disabled because I'm not convinced it's a good idea. // It would allow us to cache arenas to load address space very quickly (much faster than calling VirtualAlloc), but // it adds complexity and makes it difficult to know when you're doing something stupid, because memory is still writeable // and readable after it's "freed" with `release_arena`. So for prototyping purposes, we just release the whole arena. // arena_free_list = (Arena_Free_List*)default_allocator_new(sizeof(Arena_Free_List), 64, true); // permanent allocation. // memset(arena_free_list, 0, sizeof(Arena_Free_List)); // initialize_arena_free_list(default_allocator()); // 1b. Setup arena in-use list: initialize_arenas_in_use_list(); // 2. #NewContext Setup thread local context ExpandableArena* arena_ex = bootstrap_expandable_arena(Arena_Reserve::Size_64M, "Main Thread Arena"); thread_local_context = New(allocator(arena_ex)); push_allocator_label("Main Thread Initialization"); thread_local_context->temp = bootstrap_expandable_arena(Arena_Reserve::Size_2M, "Main Thread Temp"); thread_local_context->arena = arena_ex; thread_local_context->allocator = allocator(arena_ex); thread_local_context->thread_idx = 0; thread_local_context->thread_name = "Main Thread"; // #TODO (Low priority) This is redundant! There should just be one string_builder! thread_local_context->log_builder = new_string_builder(Arena_Reserve::Size_64M, "Main Thread Log Builder"); thread_local_context->string_builder = new_string_builder(Arena_Reserve::Size_2M, "Main Thread String Builder"); thread_local_context->error_arena = bootstrap_arena(Arena_Reserve::Size_64M, "Main Thread Error Arena"); default_logger_initialize(); thread_local_context->logger = {default_logger_proc, &default_logger}; } struct Push_Arena { Thread_Context* context; Allocator original_allocator; Push_Arena(ExpandableArena* arena_ex) { Assert(is_valid(arena_ex)); context = thread_context(); Assert(context != nullptr); original_allocator = context->allocator; context->allocator = allocator(arena_ex); } Push_Arena(Arena* arena) { Assert(is_valid(arena)); context = thread_context(); Assert(context != nullptr); original_allocator = context->allocator; context->allocator = allocator(arena); } Push_Arena(FixedArena* arena) { Assert(is_valid(arena)); context = thread_context(); Assert(context != nullptr); original_allocator = context->allocator; context->allocator = allocator(arena); } ~Push_Arena() { context->allocator = original_allocator; } }; force_inline void set_thread_context (Thread_Context* new_context) { thread_local_context = new_context; } // #Note: Both functions will free next arenas, we only worry about keeping memory in the first arena (typically 64MB). void temp_reset_keeping_memory() { Thread_Context* context = thread_context(); arena_reset(context->temp, false); } void temp_reset() { // alias: reset_temporary_storage. Thread_Context* context = thread_context(); arena_reset(context->temp, true); }