From 7afa567ea0ba57a2319d2cd3b32ec18a2ba692f3 Mon Sep 17 00:00:00 2001 From: jacob Date: Thu, 28 Mar 2024 18:19:26 -0500 Subject: [PATCH] tls.h & tls.c --- src/app.c | 25 ++++++++++++--------- src/scratch.h | 55 +++++++++++++++++++++++++-------------------- src/sys.h | 6 ++--- src/sys_win32.c | 20 +++++------------ src/tls.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ src/tls.h | 44 ++++++++++++++++++++++++++++++++++++ src/work.c | 21 +++-------------- src/work.h | 5 +---- 8 files changed, 162 insertions(+), 74 deletions(-) create mode 100644 src/tls.c create mode 100644 src/tls.h diff --git a/src/app.c b/src/app.c index 53512f77..bcff3943 100644 --- a/src/app.c +++ b/src/app.c @@ -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; diff --git a/src/scratch.h b/src/scratch.h index eb680822..c103f481 100644 --- a/src/scratch.h +++ b/src/scratch.h @@ -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 diff --git a/src/sys.h b/src/sys.h index 965cc30e..2b6ab0dd 100644 --- a/src/sys.h +++ b/src/sys.h @@ -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 diff --git a/src/sys_win32.c b/src/sys_win32.c index 44bc1ef3..3ac259f6 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -9,6 +9,7 @@ #include "log.h" #include "math.h" #include "util.h" +#include "tls.h" #include #include @@ -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; } /* ========================== * diff --git a/src/tls.c b/src/tls.c new file mode 100644 index 00000000..4bd5bf2c --- /dev/null +++ b/src/tls.c @@ -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); +} diff --git a/src/tls.h b/src/tls.h new file mode 100644 index 00000000..070f40aa --- /dev/null +++ b/src/tls.h @@ -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 diff --git a/src/work.c b/src/work.c index e74a1132..f8bf6e50 100644 --- a/src/work.c +++ b/src/work.c @@ -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; -} diff --git a/src/work.h b/src/work.h index 51bf95d5..a4faf4a0 100644 --- a/src/work.h +++ b/src/work.h @@ -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