tls.h & tls.c
This commit is contained in:
parent
2c3597646d
commit
7afa567ea0
25
src/app.c
25
src/app.c
@ -91,17 +91,23 @@ void app_entry_point(void)
|
|||||||
L.arena = arena_alloc(GIGABYTE(64));
|
L.arena = arena_alloc(GIGABYTE(64));
|
||||||
L.write_path = initialize_write_directory(&L.arena, STR(WRITE_DIR));
|
L.write_path = initialize_write_directory(&L.arena, STR(WRITE_DIR));
|
||||||
|
|
||||||
/* Startup logging */
|
|
||||||
{
|
{
|
||||||
struct temp_arena scratch = scratch_begin_no_conflict();
|
/* Startup base systems */
|
||||||
struct string logfile_path = app_write_path_cat(scratch.arena, STR("log.txt"));
|
|
||||||
log_startup(logfile_path);
|
|
||||||
scratch_end(scratch);
|
|
||||||
}
|
|
||||||
logf_info("Startup");
|
|
||||||
|
|
||||||
/* Startup console */
|
/* Startup logging */
|
||||||
struct console_startup_receipt console_sr = console_startup();
|
{
|
||||||
|
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 */
|
/* Create window */
|
||||||
struct sys_window window = sys_window_alloc();
|
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 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);
|
struct playback_startup_receipt playback_sr = playback_startup(&mixer_sr);
|
||||||
|
|
||||||
(UNUSED)console_sr;
|
|
||||||
(UNUSED)user_sr;
|
(UNUSED)user_sr;
|
||||||
(UNUSED)playback_sr;
|
(UNUSED)playback_sr;
|
||||||
|
|
||||||
|
|||||||
@ -3,11 +3,16 @@
|
|||||||
|
|
||||||
#include "arena.h"
|
#include "arena.h"
|
||||||
#include "sys.h"
|
#include "sys.h"
|
||||||
|
#include "tls.h"
|
||||||
|
|
||||||
#define SCRATCH_ARENAS_PER_THREAD 2
|
#define SCRATCH_ARENAS_PER_THREAD 2
|
||||||
#define SCRATCH_ARENA_RESERVE (GIGABYTE(64))
|
#define SCRATCH_ARENA_RESERVE (GIGABYTE(64))
|
||||||
|
|
||||||
struct scratch_context {
|
/* ========================== *
|
||||||
|
* Scratch TLS
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
|
struct scratch_tls {
|
||||||
struct arena arenas[SCRATCH_ARENAS_PER_THREAD];
|
struct arena arenas[SCRATCH_ARENAS_PER_THREAD];
|
||||||
|
|
||||||
#if RTC
|
#if RTC
|
||||||
@ -17,7 +22,25 @@ struct scratch_context {
|
|||||||
#endif
|
#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
|
/* 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
|
* 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 */
|
/* Use `scratch_begin_no_conflict` if no conflicts are present */
|
||||||
ASSERT(potential_conflict != NULL);
|
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];
|
struct arena *scratch = &ctx->arenas[0];
|
||||||
if (potential_conflict && scratch->base == potential_conflict->base) {
|
if (potential_conflict && scratch->base == potential_conflict->base) {
|
||||||
scratch = &ctx->arenas[1];
|
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)
|
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 arena *scratch = &ctx->arenas[0];
|
||||||
struct temp_arena temp = arena_temp_begin(scratch);
|
struct temp_arena temp = arena_temp_begin(scratch);
|
||||||
|
|
||||||
@ -84,10 +107,14 @@ INLINE struct temp_arena _scratch_begin_no_conflict(void)
|
|||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ========================== *
|
||||||
|
* End
|
||||||
|
* ========================== */
|
||||||
|
|
||||||
INLINE void scratch_end(struct temp_arena scratch_temp)
|
INLINE void scratch_end(struct temp_arena scratch_temp)
|
||||||
{
|
{
|
||||||
#if RTC
|
#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) {
|
if (ctx->scratch_id_stack_count > 0) {
|
||||||
u64 scratch_id = scratch_temp.scratch_id;
|
u64 scratch_id = scratch_temp.scratch_id;
|
||||||
u64 expected_id = ctx->scratch_id_stack[--ctx->scratch_id_stack_count];
|
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);
|
// 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
|
#endif
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
#ifndef SYS_H
|
#ifndef SYS_H
|
||||||
#define SYS_H
|
#define SYS_H
|
||||||
|
|
||||||
struct worker_context;
|
struct tls;
|
||||||
struct scratch_context;
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Events
|
* Events
|
||||||
@ -387,8 +386,7 @@ void sys_semaphore_signal(struct sys_semaphore *semaphore, u32 count);
|
|||||||
* Thread local storage
|
* Thread local storage
|
||||||
* ========================== */
|
* ========================== */
|
||||||
|
|
||||||
struct scratch_context *sys_thread_get_scratch_context(void);
|
struct tls *sys_thread_get_tls(void);
|
||||||
struct worker_context *sys_thread_get_worker_context(void);
|
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
* Threads
|
* Threads
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "math.h"
|
#include "math.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "tls.h"
|
||||||
|
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#include <windowsx.h>
|
#include <windowsx.h>
|
||||||
@ -1383,8 +1384,7 @@ void sys_semaphore_signal(struct sys_semaphore *semaphore, u32 count)
|
|||||||
|
|
||||||
struct win32_tls {
|
struct win32_tls {
|
||||||
HANDLE sleep_timer;
|
HANDLE sleep_timer;
|
||||||
struct scratch_context scratch_ctx;
|
struct tls app_tls;
|
||||||
struct worker_context worker_ctx;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
INTERNAL void win32_thread_set_tls(struct win32_tls *ctx)
|
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 };
|
struct win32_tls tls = { 0 };
|
||||||
tls.sleep_timer = CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
|
tls.sleep_timer = CreateWaitableTimerExW(NULL, NULL, CREATE_WAITABLE_TIMER_HIGH_RESOLUTION, TIMER_ALL_ACCESS);
|
||||||
tls.scratch_ctx = scratch_context_alloc();
|
tls.app_tls = tls_alloc();
|
||||||
tls.worker_ctx = worker_context_alloc();
|
|
||||||
return tls;
|
return tls;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERNAL void win32_tls_release(struct win32_tls *tls)
|
INTERNAL void win32_tls_release(struct win32_tls *tls)
|
||||||
{
|
{
|
||||||
worker_context_release(&tls->worker_ctx);
|
tls_release(&tls->app_tls);
|
||||||
scratch_context_release(&tls->scratch_ctx);
|
|
||||||
CloseHandle(tls->sleep_timer);
|
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();
|
struct win32_tls *thread_ctx = (struct win32_tls *)win32_thread_get_tls();
|
||||||
return &thread_ctx->scratch_ctx;
|
return &thread_ctx->app_tls;
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ========================== *
|
/* ========================== *
|
||||||
|
|||||||
60
src/tls.c
Normal file
60
src/tls.c
Normal 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
44
src/tls.h
Normal 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
|
||||||
21
src/work.c
21
src/work.c
@ -368,8 +368,8 @@ INTERNAL void worker_thread_entry_point(void *thread_data)
|
|||||||
{
|
{
|
||||||
(UNUSED)thread_data;
|
(UNUSED)thread_data;
|
||||||
|
|
||||||
struct worker_context *ctx = sys_thread_get_worker_context();
|
struct worker_tls *ctx = tls_get(WORKER_TLS);
|
||||||
*ctx = (struct worker_context) {
|
*ctx = (struct worker_tls) {
|
||||||
.is_worker = true
|
.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
|
* does not occur. However it is not ideal since it creates situations in
|
||||||
* which work is not done asynchronously.
|
* 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) {
|
if (ctx->is_worker) {
|
||||||
b32 more_tasks = true;
|
b32 more_tasks = true;
|
||||||
while (L.idle_worker_count == 0 && work->workers == 0 && more_tasks) {
|
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);
|
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;
|
|
||||||
}
|
|
||||||
|
|||||||
@ -31,7 +31,7 @@ struct work_slate {
|
|||||||
u32 num_tasks;
|
u32 num_tasks;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct worker_context {
|
struct worker_tls {
|
||||||
b32 is_worker;
|
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_wait(struct work_handle handle);
|
||||||
void work_help(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
|
#endif
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user