Dqn/dqn_tls.cpp

127 lines
4.0 KiB
C++
Raw Permalink Normal View History

2024-08-01 03:34:36 +00:00
#pragma once
#include "dqn.h"
/*
////////////////////////////////////////////////////////////////////////////////////////////////////
//
// $$$$$$$$\ $$\ $$$$$$\
// \__$$ __|$$ | $$ __$$\
// $$ | $$ | $$ / \__|
// $$ | $$ | \$$$$$$\
// $$ | $$ | \____$$\
// $$ | $$ | $$\ $$ |
// $$ | $$$$$$$$\\$$$$$$ |
// \__| \________|\______/
//
// dqn_tls.cpp
//
////////////////////////////////////////////////////////////////////////////////////////////////////
*/
// NOTE: [$TCTX] Dqn_TLS /////////////////////////////////////////////////////////////////
Dqn_TLSTMem::Dqn_TLSTMem(Dqn_TLS *tls, uint8_t arena_index, Dqn_TLSPushTMem push_tmem)
{
DQN_ASSERT(arena_index == Dqn_TLSArena_TMem0 || arena_index == Dqn_TLSArena_TMem1);
arena = tls->arenas + arena_index;
temp_mem = Dqn_Arena_TempMemBegin(arena);
destructed = false;
push_arena = push_tmem;
if (push_arena)
Dqn_TLS_PushArena(arena);
}
Dqn_TLSTMem::~Dqn_TLSTMem()
{
DQN_ASSERT(destructed == false);
Dqn_Arena_TempMemEnd(temp_mem);
destructed = true;
if (push_arena)
Dqn_TLS_PopArena();
}
DQN_API void Dqn_TLS_Init(Dqn_TLS *tls)
{
DQN_CHECK(tls);
if (tls->init)
return;
DQN_FOR_UINDEX (index, Dqn_TLSArena_Count) {
Dqn_Arena *arena = tls->arenas + index;
switch (DQN_CAST(Dqn_TLSArena)index) {
default: *arena = Dqn_Arena_InitSize(DQN_MEGABYTES(4), DQN_KILOBYTES(4), Dqn_ArenaFlag_AllocCanLeak); break;
case Dqn_TLSArena_ErrorSink: *arena = Dqn_Arena_InitSize(DQN_KILOBYTES(64), DQN_KILOBYTES(4), Dqn_ArenaFlag_AllocCanLeak); break;
case Dqn_TLSArena_Count: DQN_INVALID_CODE_PATH; break;
}
}
tls->thread_id = Dqn_OS_ThreadID();
tls->error_sink.arena = tls->arenas + Dqn_TLSArena_ErrorSink;
tls->init = true;
}
DQN_API Dqn_TLS *Dqn_TLS_Get()
{
Dqn_TLS *result = g_dqn_os_thread_tls;
// TODO(doyle): Fix stack-trace infinite loop with requiring the TLS that is not initialised
// yet.
DQN_ASSERT(
g_dqn_library->lib_init &&
"Library context must be be initialised first by calling Dqn_Library_Init. This "
"initialises the main thread's TLS for you (no need to call Dqn_OS_ThreadSetTLS on main)");
DQN_ASSERT(result &&
"Thread must be assigned the TLS with Dqn_OS_ThreadSetTLS. If the library is "
"initialised, then, this thread was created without calling the set TLS function "
"for the spawned thread.");
return result;
}
DQN_API Dqn_Arena *Dqn_TLS_Arena()
{
Dqn_TLS *tls = Dqn_TLS_Get();
Dqn_Arena *result = tls->arenas + Dqn_TLSArena_Main;
return result;
}
// TODO: Is there a way to handle conflict arenas without the user needing to
// manually pass it in?
DQN_API Dqn_TLSTMem Dqn_TLS_GetTMem(void const *conflict_arena, Dqn_TLSPushTMem push_tmem)
{
Dqn_TLS *tls = Dqn_TLS_Get();
uint8_t tls_index = (uint8_t)-1;
for (uint8_t index = Dqn_TLSArena_TMem0; index <= Dqn_TLSArena_TMem1; index++) {
Dqn_Arena *arena = tls->arenas + index;
if (!conflict_arena || arena != conflict_arena) {
tls_index = index;
break;
}
}
DQN_ASSERT(tls_index != (uint8_t)-1);
return Dqn_TLSTMem(tls, tls_index, push_tmem);
}
DQN_API void Dqn_TLS_PushArena(Dqn_Arena *arena)
{
DQN_ASSERT(arena);
Dqn_TLS *tls = Dqn_TLS_Get();
DQN_ASSERT(tls->arena_stack_index < DQN_ARRAY_UCOUNT(tls->arena_stack));
tls->arena_stack[tls->arena_stack_index++] = arena;
}
DQN_API void Dqn_TLS_PopArena()
{
Dqn_TLS *tls = Dqn_TLS_Get();
DQN_ASSERT(tls->arena_stack_index > 0);
tls->arena_stack_index--;
}
DQN_API Dqn_Arena *Dqn_TLS_TopArena()
{
Dqn_TLS *tls = Dqn_TLS_Get();
Dqn_Arena *result = nullptr;
if (tls->arena_stack_index)
result = tls->arena_stack[tls->arena_stack_index - 1];
return result;
}