root_function ThreadContext thread_context_alloc(void) { ThreadContext result = { 0 }; for (U64 arena_index = 0; arena_index < ArrayCount(result.arenas); arena_index += 1) { result.arenas[arena_index] = m_make_arena_reserve(Gigabytes(8)); } return result; } root_function void thread_context_release(ThreadContext *context) { for (U64 arena_index = 0; arena_index < ArrayCount(context->arenas); arena_index += 1) { m_arena_release(context->arenas[arena_index]); } } per_thread ThreadContext *tl_thread_context; no_name_mangle void thread_context_set(ThreadContext *context) { tl_thread_context = context; } no_name_mangle ThreadContext * thread_context_get(void) { return tl_thread_context; } root_function B32 is_main_thread(void) { ThreadContext *context = thread_context_get(); return context->is_main_thread; } root_function ArenaTemp scratch_get(Arena **conflicts, U64 conflict_count) { ArenaTemp scratch = { 0 }; ThreadContext *thread_context = thread_context_get(); for (U64 arena_index = 0; arena_index < ArrayCount(thread_context->arenas); arena_index += 1) { B32 is_conflicting = 0; for(Arena **conflict = conflicts; conflict < conflicts+conflict_count; conflict += 1) { if(*conflict == thread_context->arenas[arena_index]) { is_conflicting = 1; break; } } if(is_conflicting == 0) { scratch.arena = thread_context->arenas[arena_index]; scratch.pos = scratch.arena->pos; break; } } return scratch; } root_function void base_main_thread_entry(void (*entry)(void), U64 argument_count, char **arguments) { // Here we get memory for the thread arenas, and notify that it's a main thread. ThreadContext thread_context = thread_context_alloc(); thread_context.is_main_thread = 1; // Here we set it to the global thread context variable thread_context_set(&thread_context); // Then call the entry point function for our program entry(); thread_context_release(&thread_context); }