
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);
}