tls.h & tls.c

This commit is contained in:
jacob 2024-03-28 18:19:26 -05:00
parent 2c3597646d
commit 7afa567ea0
8 changed files with 162 additions and 74 deletions

View File

@ -91,17 +91,23 @@ void app_entry_point(void)
L.arena = arena_alloc(GIGABYTE(64));
L.write_path = initialize_write_directory(&L.arena, STR(WRITE_DIR));
/* Startup logging */
{
struct temp_arena scratch = scratch_begin_no_conflict();
struct string logfile_path = app_write_path_cat(scratch.arena, STR("log.txt"));
log_startup(logfile_path);
scratch_end(scratch);
}
logf_info("Startup");
/* Startup base systems */
/* Startup console */
struct console_startup_receipt console_sr = console_startup();
/* Startup logging */
{
struct temp_arena scratch = scratch_begin_no_conflict();
struct string logfile_path = app_write_path_cat(scratch.arena, STR("log.txt"));
struct log_startup_receipt log_sr = log_startup(logfile_path);
(UNUSED)log_sr;
scratch_end(scratch);
logf_info("Start of logs");
}
/* Startup console */
struct console_startup_receipt console_sr = console_startup();
(UNUSED)console_sr;
}
/* Create window */
struct sys_window window = sys_window_alloc();
@ -128,7 +134,6 @@ void app_entry_point(void)
struct user_startup_receipt user_sr = user_startup(&work_sr, &renderer_sr, &font_sr, &texture_sr, &draw_sr, &game_sr, &asset_cache_sr, &mixer_sr, &window);
struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr);
(UNUSED)console_sr;
(UNUSED)user_sr;
(UNUSED)playback_sr;

View File

@ -3,11 +3,16 @@
#include "arena.h"
#include "sys.h"
#include "tls.h"
#define SCRATCH_ARENAS_PER_THREAD 2
#define SCRATCH_ARENA_RESERVE (GIGABYTE(64))
struct scratch_context {
/* ========================== *
* Scratch TLS
* ========================== */
struct scratch_tls {
struct arena arenas[SCRATCH_ARENAS_PER_THREAD];
#if RTC
@ -17,7 +22,25 @@ struct scratch_context {
#endif
};
INLINE TLS_ALLOC_FUNC_DEF(scratch_tls_alloc, vctx)
{
struct scratch_tls *ctx = (struct scratch_tls *)vctx;
for (u32 i = 0; i < ARRAY_COUNT(ctx->arenas); ++i) {
ctx->arenas[i] = arena_alloc(SCRATCH_ARENA_RESERVE);
}
}
INLINE TLS_RELEASE_FUNC_DEF(scratch_tls_release, vctx)
{
struct scratch_tls *ctx = (struct scratch_tls *)vctx;
for (u32 i = 0; i < ARRAY_COUNT(ctx->arenas); ++i) {
arena_release(&ctx->arenas[i]);
}
}
/* ========================== *
* Begin
* ========================== */
/* Any arena parameters in the calling function's context should be passed into this
* function as a potential `conflict`. This is to prevent conflicts when the
@ -36,7 +59,7 @@ INLINE struct temp_arena _scratch_begin(struct arena *potential_conflict)
/* Use `scratch_begin_no_conflict` if no conflicts are present */
ASSERT(potential_conflict != NULL);
struct scratch_context *ctx = sys_thread_get_scratch_context();
struct scratch_tls *ctx = (struct scratch_tls *)tls_get(SCRATCH_TLS);
struct arena *scratch = &ctx->arenas[0];
if (potential_conflict && scratch->base == potential_conflict->base) {
scratch = &ctx->arenas[1];
@ -69,7 +92,7 @@ INLINE struct temp_arena _scratch_begin(struct arena *potential_conflict)
INLINE struct temp_arena _scratch_begin_no_conflict(void)
{
struct scratch_context *ctx = sys_thread_get_scratch_context();
struct scratch_tls *ctx = (struct scratch_tls *)tls_get(SCRATCH_TLS);
struct arena *scratch = &ctx->arenas[0];
struct temp_arena temp = arena_temp_begin(scratch);
@ -84,10 +107,14 @@ INLINE struct temp_arena _scratch_begin_no_conflict(void)
return temp;
}
/* ========================== *
* End
* ========================== */
INLINE void scratch_end(struct temp_arena scratch_temp)
{
#if RTC
struct scratch_context *ctx = sys_thread_get_scratch_context();
struct scratch_tls *ctx = (struct scratch_tls *)tls_get(SCRATCH_TLS);
if (ctx->scratch_id_stack_count > 0) {
u64 scratch_id = scratch_temp.scratch_id;
u64 expected_id = ctx->scratch_id_stack[--ctx->scratch_id_stack_count];
@ -111,24 +138,4 @@ INLINE void scratch_end_and_decommit(struct temp_arena scratch_temp)
// arena_decommit_unused_blocks(scratch_temp.arena);
}
/* ========================== *
* Scratch context
* ========================== */
INLINE struct scratch_context scratch_context_alloc(void)
{
struct scratch_context ctx = { 0 };
for (u32 i = 0; i < ARRAY_COUNT(ctx.arenas); ++i) {
ctx.arenas[i] = arena_alloc(SCRATCH_ARENA_RESERVE);
}
return ctx;
}
INLINE void scratch_context_release(struct scratch_context *ctx)
{
for (u32 i = 0; i < ARRAY_COUNT(ctx->arenas); ++i) {
arena_release(&ctx->arenas[i]);
}
}
#endif

View File

@ -1,8 +1,7 @@
#ifndef SYS_H
#define SYS_H
struct worker_context;
struct scratch_context;
struct tls;
/* ========================== *
* Events
@ -387,8 +386,7 @@ void sys_semaphore_signal(struct sys_semaphore *semaphore, u32 count);
* Thread local storage
* ========================== */
struct scratch_context *sys_thread_get_scratch_context(void);
struct worker_context *sys_thread_get_worker_context(void);
struct tls *sys_thread_get_tls(void);
/* ========================== *
* Threads

View File

@ -9,6 +9,7 @@
#include "log.h"
#include "math.h"
#include "util.h"
#include "tls.h"
#include <Windows.h>
#include <windowsx.h>
@ -1383,8 +1384,7 @@ void sys_semaphore_signal(struct sys_semaphore *semaphore, u32 count)
struct win32_tls {
HANDLE sleep_timer;
struct scratch_context scratch_ctx;
struct worker_context worker_ctx;
struct tls app_tls;
};
INTERNAL void win32_thread_set_tls(struct win32_tls *ctx)
@ -1403,28 +1403,20 @@ INTERNAL struct win32_tls win32_tls_alloc(void)
{
struct win32_tls tls = { 0 };
tls.sleep_timer = CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
tls.scratch_ctx = scratch_context_alloc();
tls.worker_ctx = worker_context_alloc();
tls.app_tls = tls_alloc();
return tls;
}
INTERNAL void win32_tls_release(struct win32_tls *tls)
{
worker_context_release(&tls->worker_ctx);
scratch_context_release(&tls->scratch_ctx);
tls_release(&tls->app_tls);
CloseHandle(tls->sleep_timer);
}
struct scratch_context *sys_thread_get_scratch_context(void)
struct tls *sys_thread_get_tls(void)
{
struct win32_tls *thread_ctx = (struct win32_tls *)win32_thread_get_tls();
return &thread_ctx->scratch_ctx;
}
struct worker_context *sys_thread_get_worker_context(void)
{
struct win32_tls *thread_ctx = (struct win32_tls *)win32_thread_get_tls();
return &thread_ctx->worker_ctx;
return &thread_ctx->app_tls;
}
/* ========================== *

60
src/tls.c Normal file
View File

@ -0,0 +1,60 @@
#include "tls.h"
#include "arena.h"
#include "scratch.h"
#include "work.h"
#define TLS_TABLE_RESERVE (GIGABYTE(1))
struct tls_info {
u64 size;
u64 align;
tls_alloc_func *alloc;
tls_release_func *release;
};
#define X(tls_name, tls_struct, tls_alloc_func_type, tls_release_func_type) { .size = sizeof(tls_struct), .align = ALIGNOF(tls_struct), .alloc = tls_alloc_func_type, .release = tls_release_func_type },
GLOBAL READONLY struct tls_info g_tls_info_table[TLS_IDENTIFIER_COUNT] = {
TLS_TABLE(X)
};
#undef X
struct tls tls_alloc(void)
{
struct tls t = { 0 };
t.arena = arena_alloc(TLS_TABLE_RESERVE);
/* Build lookup table */
for (u64 i = 0; i < TLS_IDENTIFIER_COUNT; ++i) {
struct tls_info *info = &g_tls_info_table[i];
arena_align(&t.arena, info->align);
void *ptr = arena_push_array_zero(&t.arena, u8, info->size);
t.lookup[i] = ptr;
}
/* Call alloc functions */
for (u64 i = 0; i < TLS_IDENTIFIER_COUNT; ++i) {
tls_alloc_func *alloc = g_tls_info_table[i].alloc;
if (alloc) {
void *ptr = t.lookup[i];
alloc(ptr);
}
}
return t;
}
void tls_release(struct tls *t)
{
/* Call release functions in reverse order */
for (u64 i = (TLS_IDENTIFIER_COUNT - 1); i <= 0; --i) {
tls_alloc_func *release = g_tls_info_table[i].release;
if (release) {
void *ptr = t->lookup[i];
release(ptr);
}
}
arena_release(&t->arena);
}

44
src/tls.h Normal file
View File

@ -0,0 +1,44 @@
#ifndef TLS_H
#define TLS_H
/* ========================================================================== */
/* TLS table (X macro table) */
/* ========================================================================== */
#define TLS_TABLE(X) \
X(SCRATCH_TLS, struct scratch_tls, &scratch_tls_alloc, &scratch_tls_release) \
X(WORKER_TLS, struct worker_tls, NULL, NULL )
/* ========================================================================== */
/* ========================================================================== */
/* ========================================================================== */
#include "sys.h"
#define X(identifier, tls_struct, tls_alloc_func_type, tls_release_func_type) identifier,
enum tls_identifier {
TLS_TABLE(X)
TLS_IDENTIFIER_COUNT
};
#undef X
#define TLS_ALLOC_FUNC_DEF(name, arg_name) void name(void *arg_name)
typedef TLS_ALLOC_FUNC_DEF(tls_alloc_func, tls_struct);
#define TLS_RELEASE_FUNC_DEF(name, arg_name) void name(void *arg_name)
typedef TLS_RELEASE_FUNC_DEF(tls_release_func, tls_struct);
struct tls {
struct arena arena;
void *lookup[TLS_IDENTIFIER_COUNT];
};
struct tls tls_alloc(void);
void tls_release(struct tls *t);
INLINE void *tls_get(enum tls_identifier identifier)
{
return sys_thread_get_tls()->lookup[identifier];
}
#endif

View File

@ -368,8 +368,8 @@ INTERNAL void worker_thread_entry_point(void *thread_data)
{
(UNUSED)thread_data;
struct worker_context *ctx = sys_thread_get_worker_context();
*ctx = (struct worker_context) {
struct worker_tls *ctx = tls_get(WORKER_TLS);
*ctx = (struct worker_tls) {
.is_worker = true
};
@ -434,7 +434,7 @@ INTERNAL struct work_handle work_push_from_slate_assume_locked(struct work_slate
* does not occur. However it is not ideal since it creates situations in
* which work is not done asynchronously.
*/
struct worker_context *ctx = sys_thread_get_worker_context();
struct worker_tls *ctx = tls_get(WORKER_TLS);
if (ctx->is_worker) {
b32 more_tasks = true;
while (L.idle_worker_count == 0 && work->workers == 0 && more_tasks) {
@ -591,18 +591,3 @@ void work_help(struct work_handle handle)
sys_mutex_unlock(&L.mutex);
}
/* ========================== *
* Worker context interface
* ========================== */
struct worker_context worker_context_alloc(void)
{
return (struct worker_context) { 0 };
}
void worker_context_release(struct worker_context *ctx)
{
/* Do nothing */
(UNUSED)ctx;
}

View File

@ -31,7 +31,7 @@ struct work_slate {
u32 num_tasks;
};
struct worker_context {
struct worker_tls {
b32 is_worker;
};
@ -50,7 +50,4 @@ void work_slate_push_task(struct work_slate *ws, work_task_func *func, void *dat
void work_wait(struct work_handle handle);
void work_help(struct work_handle handle);
struct worker_context worker_context_alloc(void);
void worker_context_release(struct worker_context *ctx);
#endif