From 2b082234727dcf51e8235213d96339c4ff0d3151 Mon Sep 17 00:00:00 2001 From: jacob Date: Sun, 6 Jul 2025 18:06:25 -0500 Subject: [PATCH] add SYS_PRIORITY_INHERIT --- src/app.c | 5 ++-- src/asset_cache.c | 14 +++++----- src/gp_dx12.c | 8 +++--- src/resource.c | 2 +- src/snc.c | 19 ++++--------- src/snc.h | 5 ++-- src/sprite.c | 2 +- src/sys.h | 11 ++++---- src/sys_win32.c | 68 ++++++++++++++++++++++++----------------------- 9 files changed, 65 insertions(+), 69 deletions(-) diff --git a/src/app.c b/src/app.c index 209bc4e5..a39aeda3 100644 --- a/src/app.c +++ b/src/app.c @@ -199,6 +199,7 @@ INTERNAL struct app_arg_list parse_args(struct arena *arena, struct string args_ void sys_app_entry(struct string args_str) { struct arena_temp scratch = scratch_begin_no_conflict(); + snc_counter_add(&G.exit_fence, 1); struct app_arg_list args = parse_args(scratch.arena, args_str); struct string logfile_name = LIT("log.log"); @@ -315,7 +316,7 @@ void sys_app_entry(struct string args_str) sys_window_show(window); /* Wait for app_exit() */ - snc_counter_wait_gtz(&G.exit_fence); + snc_counter_wait(&G.exit_fence); /* Run exit callbacks */ /* FIXME: Only wait on shutdown for a certain period of time before @@ -358,5 +359,5 @@ void sys_app_entry(struct string args_str) void app_exit(void) { - snc_counter_add(&G.exit_fence, 1); + snc_counter_add(&G.exit_fence, -1); } diff --git a/src/asset_cache.c b/src/asset_cache.c index 17ff5583..24d0580c 100644 --- a/src/asset_cache.c +++ b/src/asset_cache.c @@ -107,9 +107,6 @@ u64 asset_cache_hash(struct string key) struct asset *asset_cache_touch(struct string key, u64 hash, b32 *is_first_touch) { struct asset *asset = NULL; - if (is_first_touch) { - *is_first_touch = false; - } /* Lookup */ { @@ -119,7 +116,11 @@ struct asset *asset_cache_touch(struct string key, u64 hash, b32 *is_first_touch } /* Insert if not found */ - if (!asset->hash) { + if (asset->hash) { + if (is_first_touch) { + *is_first_touch = false; + } + } else { struct snc_lock lock = snc_lock_e(&G.lookup_mutex); /* Re-check asset presence in case it was inserted since lock */ @@ -143,6 +144,7 @@ struct asset *asset_cache_touch(struct string key, u64 hash, b32 *is_first_touch .hash = hash, .key = key_stored }; + snc_counter_add(&asset->counter, 1); if (is_first_touch) { *is_first_touch = true; } @@ -172,7 +174,7 @@ void asset_cache_mark_ready(struct asset *asset, void *store_data) { asset->store_data = store_data; asset->status = ASSET_STATUS_READY; - snc_counter_add(&asset->counter, 1); + snc_counter_add(&asset->counter, -1); } /* ========================== * @@ -181,7 +183,7 @@ void asset_cache_mark_ready(struct asset *asset, void *store_data) void asset_cache_wait(struct asset *asset) { - snc_counter_wait_gtz(&asset->counter); + snc_counter_wait(&asset->counter); } /* ========================== * diff --git a/src/gp_dx12.c b/src/gp_dx12.c index f679d157..d8128d0c 100644 --- a/src/gp_dx12.c +++ b/src/gp_dx12.c @@ -920,8 +920,8 @@ INTERNAL SYS_JOB_DEF(pipeline_init_job, job) struct shader_compile_job_param *params[] = { &vs, &ps }; struct shader_compile_job_sig comp_sig = { .params = params }; struct snc_counter counter = ZI; - sys_run(countof(params), shader_compile_job, &comp_sig, SYS_PRIORITY_HIGH, &counter); - snc_counter_wait_ltez(&counter); + sys_run(countof(params), shader_compile_job, &comp_sig, SYS_PRIORITY_INHERIT, &counter); + snc_counter_wait(&counter); success = vs.success && ps.success; } @@ -1114,8 +1114,8 @@ INTERNAL void pipeline_alloc(u64 num_pipelines, struct pipeline_desc *descs_in, __prof; struct pipeline_init_job_sig sig = { .descs_in = descs_in, .pipelines_out = pipelines_out }; struct snc_counter counter = ZI; - sys_run(num_pipelines, pipeline_init_job, &sig, SYS_PRIORITY_HIGH, &counter); - snc_counter_wait_ltez(&counter); + sys_run(num_pipelines, pipeline_init_job, &sig, SYS_PRIORITY_INHERIT, &counter); + snc_counter_wait(&counter); } INTERNAL void pipeline_release_now(struct pipeline *pipeline) diff --git a/src/resource.c b/src/resource.c index ff12df96..bcef2b00 100644 --- a/src/resource.c +++ b/src/resource.c @@ -287,7 +287,7 @@ INTERNAL SYS_THREAD_DEF(resource_watch_dispatcher_thread_entry_point, _) sig.callbacks = callbacks; struct snc_counter counter = ZI; sys_run(num_callbacks, resource_watch_callback_job, &sig, SYS_PRIORITY_BACKGROUND, &counter); - snc_counter_wait_ltez(&counter); + snc_counter_wait(&counter); } } } diff --git a/src/snc.c b/src/snc.c index 270381ab..c67f7428 100644 --- a/src/snc.c +++ b/src/snc.c @@ -129,16 +129,16 @@ void snc_cv_broadcast(struct snc_cv *cv) * Counter * ========================== */ -void snc_counter_add(struct snc_counter *counter, i64 amount) +void snc_counter_add(struct snc_counter *counter, i64 x) { - i64 old_v = atomic_i64_fetch_add(&counter->v, amount); - i64 new_v = old_v + amount; - if ((old_v > 0 && new_v <= 0) || (old_v <= 0 && new_v > 0)) { + i64 old_v = atomic_i64_fetch_add(&counter->v, x); + i64 new_v = old_v + x; + if (old_v > 0 && new_v <= 0) { sys_wake_all(&counter->v); } } -void snc_counter_wait_ltez(struct snc_counter *counter) +void snc_counter_wait(struct snc_counter *counter) { i64 v = atomic_i64_fetch(&counter->v); while (v > 0) { @@ -146,12 +146,3 @@ void snc_counter_wait_ltez(struct snc_counter *counter) v = atomic_i64_fetch(&counter->v); } } - -void snc_counter_wait_gtz(struct snc_counter *counter) -{ - i64 v = atomic_i64_fetch(&counter->v); - while (v <= 0) { - sys_wait(&counter->v, &v, sizeof(v)); - v = atomic_i64_fetch(&counter->v); - } -} diff --git a/src/snc.h b/src/snc.h index c4cfdce1..b160b6c7 100644 --- a/src/snc.h +++ b/src/snc.h @@ -51,8 +51,7 @@ struct snc_counter { struct atomic_i64 v; }; -void snc_counter_add(struct snc_counter *counter, i64 amount); -void snc_counter_wait_ltez(struct snc_counter *counter); -void snc_counter_wait_gtz(struct snc_counter *counter); +void snc_counter_add(struct snc_counter *counter, i64 x); +void snc_counter_wait(struct snc_counter *counter); #endif diff --git a/src/sprite.c b/src/sprite.c index 3d6c8366..3f31d320 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -1374,7 +1374,7 @@ INTERNAL SYS_THREAD_DEF(sprite_evictor_scheduler_thread_entry_point, arg) while (!G.evictor_scheduler_shutdown) { struct snc_counter counter = ZI; sys_run(1, sprite_evictor_job, NULL, SYS_PRIORITY_BACKGROUND, &counter); - snc_counter_wait_ltez(&counter); + snc_counter_wait(&counter); /* FIXME: Enable this */ #if 0 snc_cv_wait_time(G.evictor_scheduler_shutdown_cv, &evictor_lock, SECONDS_FROM_NS(EVICTOR_CYCLE_INTERVAL_NS)); diff --git a/src/sys.h b/src/sys.h index e91392e6..1efecaf4 100644 --- a/src/sys.h +++ b/src/sys.h @@ -459,16 +459,17 @@ void sys_wake_all(void *addr); #define SYS_MAX_FIBERS 4096 -i32 sys_current_fiber_id(void); +i16 sys_current_fiber_id(void); /* ========================== * * Job * ========================== */ enum sys_priority { - SYS_PRIORITY_HIGH = 0, - SYS_PRIORITY_NORMAL = 1, - SYS_PRIORITY_BACKGROUND = 2, + SYS_PRIORITY_INHERIT = -1, + SYS_PRIORITY_HIGH = 0, + SYS_PRIORITY_NORMAL = 1, + SYS_PRIORITY_BACKGROUND = 2, NUM_SYS_PRIORITIES }; @@ -494,7 +495,7 @@ struct sys_scratch_ctx { struct arena *arenas[SYS_SCRATCH_ARENAS_PER_CTX]; }; -struct sys_scratch_ctx *sys_scratch_ctx_from_fiber_id(i32 fiber_id); +struct sys_scratch_ctx *sys_scratch_ctx_from_fiber_id(i16 fiber_id); /* ========================== * * App entry point diff --git a/src/sys_win32.c b/src/sys_win32.c index 8bcfba64..6fbd848d 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -101,7 +101,7 @@ struct win32_window { }; -#define NUM_WAIT_BINS 4096 +#define NUM_WAIT_ADDR_BINS 4096 struct alignas(64) wait_list { /* =================================================== */ @@ -121,7 +121,7 @@ struct alignas(64) wait_list { /* =================================================== */ u8 _pad1[8]; /* 8 bytes (padding) */ }; -STATIC_ASSERT(sizeof(struct wait_list) == 64); /* Assume wait_list fits in one cache line (increase if necessary) */ +STATIC_ASSERT(sizeof(struct wait_list) == 64); /* Padding validation (increase if necessary) */ STATIC_ASSERT(alignof(struct wait_list) == 64); /* Avoid false sharing */ struct alignas(64) wait_bin { @@ -139,12 +139,13 @@ struct alignas(64) wait_bin { /* =================================================== */ u8 _pad1[24]; /* 24 bytes (padding) */ }; -STATIC_ASSERT(sizeof(struct wait_bin) == 64); /* Assume wait_bin fits in one cache line (increase if necessary) */ +STATIC_ASSERT(sizeof(struct wait_bin) == 64); /* Padding validation (increase if necessary) */ STATIC_ASSERT(alignof(struct wait_bin) == 64); /* Avoid false sharing */ struct alignas(64) yielder { /* =================================================== */ - i32 fiber_id; /* 4 bytes */ + i16 fiber_id; /* 2 bytes */ + u8 _pad0[2]; /* 2 bytes (padding) */ i32 job_queue_kind; /* 4 bytes */ /* =================================================== */ sys_job_func *job_func; /* 8 bytes */ @@ -158,11 +159,11 @@ struct alignas(64) yielder { struct yielder *prev; /* 8 bytes */ /* =================================================== */ i32 job_id; /* 4 bytes */ - u8 _pad0[4]; /* 4 bytes (padding) */ + u8 _pad1[4]; /* 4 bytes (padding) */ /* =================================================== */ - u8 _pad1[8]; /* 8 bytes (padding) */ + u8 _pad2[8]; /* 8 bytes (padding) */ }; -STATIC_ASSERT(sizeof(struct yielder) == 64); /* Assume yielder fits in one cache line (increase if necessary) */ +STATIC_ASSERT(sizeof(struct yielder) == 64); /* Padding validation (increase if necessary) */ STATIC_ASSERT(alignof(struct yielder) == 64); /* Avoid false sharing */ @@ -175,7 +176,7 @@ struct alignas(64) counter { /* =================================================== */ u8 _pad[48]; /* 56 bytes (padding) */ }; -STATIC_ASSERT(sizeof(struct counter) == 64); /* Assume counter fits in one cache line (increase if necessary) */ +STATIC_ASSERT(sizeof(struct counter) == 64); /* Padding validation (increase if necessary) */ STATIC_ASSERT(alignof(struct counter) == 64); /* Avoid false sharing */ @@ -211,8 +212,9 @@ struct alignas(64) fiber { /* =================================================== */ char *name_cstr; /* 8 bytes */ /* =================================================== */ - i32 id; /* 4 bytes */ - i32 parent_id; /* 4 bytes */ + i16 id; /* 2 bytes */ + i16 parent_id; /* 2 bytes */ + u8 _pad0[4]; /* 4 bytes (padding) */ /* =================================================== */ void *addr; /* 8 bytes */ /* =================================================== */ @@ -225,10 +227,11 @@ struct alignas(64) fiber { /* =================================================== */ struct yield_param *yield_param; /* 8 bytes */ /* =================================================== */ - u8 _pad0[8]; /* 8 bytes (padding) */ + u8 _pad1[8]; /* 8 bytes (padding) */ }; -STATIC_ASSERT(sizeof(struct fiber) == 64); /* Assume fiber fits in one cache line (increase if necessary) */ +STATIC_ASSERT(sizeof(struct fiber) == 64); /* Padding validation (increase if necessary) */ STATIC_ASSERT(alignof(struct fiber) == 64); /* Avoid false sharing */ +STATIC_ASSERT(SYS_MAX_FIBERS < I16_MAX); /* Max fibers should fit in fiber id */ struct alignas(64) fiber_ctx { /* ==================================================== */ @@ -244,7 +247,7 @@ struct alignas(64) fiber_ctx { /* ==================================================== */ u8 _pad4[8]; /* 8 bytes (padding) */ }; -STATIC_ASSERT(sizeof(struct fiber_ctx) == 64); /* Assume ctx fits in one cache line (increase if necessary) */ +STATIC_ASSERT(sizeof(struct fiber_ctx) == 64); /* Padding validation (increase if necessary) */ STATIC_ASSERT(alignof(struct fiber_ctx) == 64); /* Avoid false sharing */ @@ -264,7 +267,7 @@ struct job_info { void *sig; struct snc_counter *counter; - i32 fiber_id; /* If the job is being resumed from a yield */ + i16 fiber_id; /* If the job is being resumed from a yield */ struct job_info *next; }; @@ -340,11 +343,11 @@ GLOBAL struct { struct arena *wait_lists_arena; /* Wait table */ - struct wait_bin wait_bins[NUM_WAIT_BINS]; + struct wait_bin wait_bins[NUM_WAIT_ADDR_BINS]; /* Fibers */ - i32 num_fibers; - i32 first_free_fiber_id; + i16 num_fibers; + i16 first_free_fiber_id; struct arena *fiber_names_arena; struct atomic_i32 fibers_lock; /* TODO: Prevent false sharing */ struct fiber fibers[SYS_MAX_FIBERS]; @@ -365,7 +368,7 @@ GLOBAL struct { -INTERNAL struct fiber *fiber_from_id(i32 id); +INTERNAL struct fiber *fiber_from_id(i16 id); INTERNAL void job_fiber_yield(struct fiber *fiber, struct fiber *parent_fiber); @@ -394,7 +397,7 @@ void sys_wait(void *addr, void *cmp, u32 size) WaitOnAddress(addr, cmp, size, INFINITE); #else struct fiber *fiber = fiber_from_id(sys_current_fiber_id()); - i32 parent_fiber_id = fiber->parent_id; + i16 parent_fiber_id = fiber->parent_id; /* Yield if job fiber, otherwise fall back to windows blocking function */ if (parent_fiber_id > 0) { /* Yield if job fiber */ @@ -422,7 +425,7 @@ void sys_wake_single(void *addr) void sys_wake_all(void *addr) { - u64 wait_bin_index = (u64)addr % NUM_WAIT_BINS; + u64 wait_bin_index = (u64)addr % NUM_WAIT_ADDR_BINS; struct wait_bin *bin = &G.wait_bins[wait_bin_index]; while (atomic_i32_fetch_test_set(&bin->lock, 0, 1) != 0) ix_pause(); @@ -514,7 +517,7 @@ INTERNAL void job_fiber_entry(void *id_ptr); INTERNAL struct fiber *fiber_alloc(enum fiber_kind kind) { - i32 fiber_id = 0; + i16 fiber_id = 0; struct fiber *fiber = NULL; char *new_name_cstr = NULL; { @@ -583,7 +586,7 @@ INTERNAL struct fiber *fiber_alloc(enum fiber_kind kind) return fiber; } -INTERNAL void fiber_release(struct fiber *fiber, i32 fiber_id) +INTERNAL void fiber_release(struct fiber *fiber, i16 fiber_id) { while (atomic_i32_fetch_test_set(&G.fibers_lock, 0, 1) != 0) ix_pause(); { @@ -593,13 +596,13 @@ INTERNAL void fiber_release(struct fiber *fiber, i32 fiber_id) atomic_i32_fetch_set(&G.fibers_lock, 0); } -INTERNAL struct fiber *fiber_from_id(i32 id) +INTERNAL struct fiber *fiber_from_id(i16 id) { ASSERT(id >= 0 && id < SYS_MAX_FIBERS); return &G.fibers[id]; } -INTERNAL struct fiber_ctx *fiber_ctx_from_id(i32 id) +INTERNAL struct fiber_ctx *fiber_ctx_from_id(i16 id) { ASSERT(id >= 0 && id < SYS_MAX_FIBERS); return &G.fiber_contexts[id]; @@ -609,9 +612,9 @@ INTERNAL struct fiber_ctx *fiber_ctx_from_id(i32 id) * Test job * ========================== */ -i32 sys_current_fiber_id(void) +i16 sys_current_fiber_id(void) { - return (i32)(i64)GetFiberData(); + return (i16)(i64)GetFiberData(); } void sys_run(i32 count, sys_job_func *func, void *sig, enum sys_priority priority, struct snc_counter *counter) @@ -682,7 +685,7 @@ INTERNAL void job_fiber_resume(struct fiber *fiber) INTERNAL void job_fiber_entry(void *id_ptr) { - i32 id = (i32)(i64)id_ptr; + i16 id = (i32)(i64)id_ptr; struct fiber *fiber = fiber_from_id(id); __prof_fiber_enter(fiber->name_cstr, PROF_THREAD_GROUP_FIBERS + fiber->id); while (true) { @@ -846,7 +849,7 @@ INTERNAL SYS_THREAD_DEF(worker_entry, worker_ctx_arg) void *wait_cmp = yield.wait.cmp; u32 wait_size = yield.wait.size; - u64 wait_bin_index = (u64)wait_addr % NUM_WAIT_BINS; + u64 wait_bin_index = (u64)wait_addr % NUM_WAIT_ADDR_BINS; struct wait_bin *bin = &G.wait_bins[wait_bin_index]; while (atomic_i32_fetch_test_set(&bin->lock, 0, 1) != 0) ix_pause(); @@ -986,7 +989,7 @@ INTERNAL SYS_THREAD_DEF(test_entry, _) * Scratch context * ========================== */ -struct sys_scratch_ctx *sys_scratch_ctx_from_fiber_id(i32 id) +struct sys_scratch_ctx *sys_scratch_ctx_from_fiber_id(i16 id) { struct fiber_ctx *fiber_ctx = fiber_ctx_from_id(id); struct sys_scratch_ctx *scratch_ctx = &fiber_ctx->scratch_ctx; @@ -1810,7 +1813,7 @@ INTERNAL SYS_THREAD_DEF(window_thread_entry_point, arg) win32_update_window_from_system(window); BringWindowToTop(window->hwnd); - snc_counter_add(&window->ready_fence, 1); + snc_counter_add(&window->ready_fence, -1); while (!atomic_i32_fetch(&window->event_thread_shutdown)) { MSG msg = ZI; @@ -1902,10 +1905,9 @@ INTERNAL struct win32_window *win32_window_alloc(void) MEMZERO_STRUCT(window); /* Start window thread for processing events */ + snc_counter_add(&window->ready_fence, 1); window->event_thread = sys_thread_alloc(&window_thread_entry_point, window, LIT("Window thread"), PROF_THREAD_GROUP_WINDOW); - - /* Wait for event thread to create actual window */ - snc_counter_wait_gtz(&window->ready_fence); + snc_counter_wait(&window->ready_fence); return window; }