remove threads outside of system layer

This commit is contained in:
jacob 2025-07-14 17:59:28 -05:00
parent 0948e357c6
commit a5582f098f
5 changed files with 113 additions and 155 deletions

View File

@ -678,10 +678,8 @@ INLINE f64 clamp_f64(f64 v, f64 min, f64 max) { return v < min ? min : v > max ?
#include "prof_tracy.h" #include "prof_tracy.h"
#define PROF_THREAD_GROUP_FIBERS -GIBI(1) #define PROF_THREAD_GROUP_FIBERS -GIBI(1)
#define PROF_THREAD_GROUP_SCHEDULER -MEBI(5) #define PROF_THREAD_GROUP_SCHEDULER -MEBI(3)
#define PROF_THREAD_GROUP_IO -MEBI(4) #define PROF_THREAD_GROUP_WINDOW -MEBI(2)
#define PROF_THREAD_GROUP_WINDOW -MEBI(3)
#define PROF_THREAD_GROUP_APP -MEBI(2)
#define PROF_THREAD_GROUP_MAIN -MEBI(1) #define PROF_THREAD_GROUP_MAIN -MEBI(1)
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -148,7 +148,7 @@ void _log(i32 level, struct string msg)
struct sys_datetime datetime = sys_local_time(); struct sys_datetime datetime = sys_local_time();
i64 time_ns = sys_time_ns(); i64 time_ns = sys_time_ns();
u32 tid = sys_thread_id(); u32 tid = sys_current_thread_id();
struct log_level_settings settings = g_log_level_settings[level]; struct log_level_settings settings = g_log_level_settings[level];
struct string shorthand = settings.shorthand; struct string shorthand = settings.shorthand;

View File

@ -326,7 +326,7 @@ INTERNAL void push_load_job(struct cache_ref ref, struct sprite_tag tag)
} }
/* Push work */ /* Push work */
sys_run(1, sprite_load_job, cmd, SYS_POOL_BACKGROUND, SYS_PRIORITY_LOW, 0); sys_run(1, sprite_load_job, cmd, SYS_POOL_BACKGROUND, SYS_PRIORITY_INHERIT, 0);
} }
INTERNAL void cache_entry_load_texture(struct cache_ref ref, struct sprite_tag tag) INTERNAL void cache_entry_load_texture(struct cache_ref ref, struct sprite_tag tag)

View File

@ -497,7 +497,7 @@ void sys_window_cursor_enable_clip(struct sys_window *sys_window, struct rect bo
void sys_window_cursor_disable_clip(struct sys_window *sys_window); void sys_window_cursor_disable_clip(struct sys_window *sys_window);
/* ========================== * /* ========================== *
* Threads * Thread
* ========================== */ * ========================== */
#define SYS_THREAD_DEF(name, arg_name) void name(void *arg_name) #define SYS_THREAD_DEF(name, arg_name) void name(void *arg_name)
@ -517,15 +517,7 @@ b32 sys_thread_try_release(struct sys_thread *thread, f32 timeout_seconds); /*
void sys_thread_force_release(struct sys_thread *thread); void sys_thread_force_release(struct sys_thread *thread);
/* Gets the current executing thread's ID */ u32 sys_current_thread_id(void);
u32 sys_thread_id(void);
/* Asserts that the current thread matches the supplied thread id (tid) */
#if RTC
void sys_thread_assert(u32 tid);
#else
# define sys_thread_assert(tid)
#endif
/* ========================== * /* ========================== *
* Address * Address

View File

@ -91,7 +91,6 @@ struct win32_window {
u32 flags; u32 flags;
HWND hwnd; HWND hwnd;
u32 tid;
struct snc_counter ready_fence; struct snc_counter ready_fence;
u16 utf16_high_surrogate_last_input; u16 utf16_high_surrogate_last_input;
@ -181,10 +180,9 @@ struct alignas(64) fiber {
/* ==================================================== */ /* ==================================================== */
char *name_cstr; /* 08 bytes */ char *name_cstr; /* 08 bytes */
/* ==================================================== */ /* ==================================================== */
struct atomic16 wake_lock; /* 02 bytes (4 byte alignment) */ struct atomic32 wake_lock; /* 04 bytes (4 byte alignment) */
i16 id; /* 02 bytes */ i16 id; /* 02 bytes */
i16 parent_id; /* 02 bytes */ i16 parent_id; /* 02 bytes */
i16 unyielding; /* 02 bytes */
/* ==================================================== */ /* ==================================================== */
u64 wait_addr; /* 08 bytes */ u64 wait_addr; /* 08 bytes */
/* ==================================================== */ /* ==================================================== */
@ -470,7 +468,7 @@ void sys_wait(void *addr, void *cmp, u32 size, i64 timeout_ns)
{ {
struct fiber *fiber = fiber_from_id(sys_current_fiber_id()); struct fiber *fiber = fiber_from_id(sys_current_fiber_id());
i16 parent_id = fiber->parent_id; i16 parent_id = fiber->parent_id;
if (parent_id != 0 && !fiber->unyielding) { if (parent_id != 0) {
*fiber->yield_param = (struct yield_param) { *fiber->yield_param = (struct yield_param) {
.kind = YIELD_KIND_WAIT, .kind = YIELD_KIND_WAIT,
.wait = { .wait = {
@ -604,7 +602,7 @@ INTERNAL void wake_fibers_locked(i32 num_fibers, struct fiber **fibers)
fiber->next_time_waiter = 0; fiber->next_time_waiter = 0;
} }
/* Unlock fiber */ /* Unlock fiber */
atomic16_fetch_set(&fiber->wake_lock, 0); atomic32_fetch_set(&fiber->wake_lock, 0);
} }
/* Unlock wait bins */ /* Unlock wait bins */
if (wait_time_bin != 0) tm_unlock(&wait_time_bin->lock); if (wait_time_bin != 0) tm_unlock(&wait_time_bin->lock);
@ -636,13 +634,13 @@ INTERNAL void wake_fibers_locked(i32 num_fibers, struct fiber **fibers)
info->sig = fiber->job_sig; info->sig = fiber->job_sig;
info->counter = fiber->job_counter; info->counter = fiber->job_counter;
info->fiber_id = fiber->id; info->fiber_id = fiber->id;
if (queue->last) { if (queue->first) {
queue->last->next = info; info->next = queue->first;
} else { } else {
queue->first = info;
}
queue->last = info; queue->last = info;
} }
queue->first = info;
}
tm_unlock(&queue->lock); tm_unlock(&queue->lock);
} }
@ -688,7 +686,7 @@ INTERNAL void wake_address(void *addr, i32 count)
if (wait_addr_list) { if (wait_addr_list) {
fibers = arena_push_array_no_zero(scratch.arena, struct fiber *, wait_addr_list->num_waiters); fibers = arena_push_array_no_zero(scratch.arena, struct fiber *, wait_addr_list->num_waiters);
for (struct fiber *fiber = fiber_from_id(wait_addr_list->first_waiter); fiber && num_fibers < count; fiber = fiber_from_id(fiber->next_addr_waiter)) { for (struct fiber *fiber = fiber_from_id(wait_addr_list->first_waiter); fiber && num_fibers < count; fiber = fiber_from_id(fiber->next_addr_waiter)) {
if (atomic16_fetch_test_set(&fiber->wake_lock, 0, 1) == 0) { if (atomic32_fetch_test_set(&fiber->wake_lock, 0, 1) == 0) {
fibers[num_fibers] = fiber; fibers[num_fibers] = fiber;
++num_fibers; ++num_fibers;
} }
@ -739,7 +737,7 @@ INTERNAL void wake_time(u64 time)
/* Set waiter wake status & build fibers list */ /* Set waiter wake status & build fibers list */
fibers = arena_push_array_no_zero(scratch.arena, struct fiber *, wait_time_list->num_waiters); fibers = arena_push_array_no_zero(scratch.arena, struct fiber *, wait_time_list->num_waiters);
for (struct fiber *fiber = fiber_from_id(wait_time_list->first_waiter); fiber; fiber = fiber_from_id(fiber->next_time_waiter)) { for (struct fiber *fiber = fiber_from_id(wait_time_list->first_waiter); fiber; fiber = fiber_from_id(fiber->next_time_waiter)) {
if (atomic16_fetch_test_set(&fiber->wake_lock, 0, 1) == 0) { if (atomic32_fetch_test_set(&fiber->wake_lock, 0, 1) == 0) {
fibers[num_fibers] = fiber; fibers[num_fibers] = fiber;
++num_fibers; ++num_fibers;
} }
@ -1119,7 +1117,6 @@ INTERNAL SYS_THREAD_DEF(job_worker_entry, worker_ctx_arg)
job_fiber->job_priority = job_priority; job_fiber->job_priority = job_priority;
job_fiber->job_counter = job_counter; job_fiber->job_counter = job_counter;
job_fiber->yield_param = &yield; job_fiber->yield_param = &yield;
job_fiber->unyielding = 0;
b32 done = 0; b32 done = 0;
while (!done) { while (!done) {
job_fiber_resume(job_fiber); job_fiber_resume(job_fiber);
@ -1361,99 +1358,6 @@ INTERNAL SYS_THREAD_DEF(job_scheduler_entry, _)
} }
} }
/* ========================== *
* Test thread
* ========================== */
INTERNAL SYS_THREAD_DEF(test_entry, _)
{
struct arena_temp scratch = scratch_begin_no_conflict();
(UNUSED)_;
/* Start scheduler */
atomic64_fetch_set(&G.current_scheduler_cycle_period_ns.v, DEFAULT_SCHEDULER_CYCLE_PERIOD_NS);
struct sys_thread *scheduler_thread = sys_thread_alloc(job_scheduler_entry, 0, LIT("Scheduler thread"), PROF_THREAD_GROUP_SCHEDULER);
/* Start workers */
/* TODO: Heuristic worker counts & affinities */
for (enum sys_pool pool_kind = 0; pool_kind < (i32)countof(G.job_pools); ++pool_kind) {
struct job_pool *pool = &G.job_pools[pool_kind];
struct string name_fmt = ZI;
i32 prof_group = PROF_THREAD_GROUP_FIBERS - MEBI(pool_kind);
switch (pool_kind) {
default: ASSERT(0); break;
case SYS_POOL_SIM:
{
name_fmt = LIT("Sim worker #%F");
pool->num_worker_threads = 4;
pool->thread_affinity_mask = 0x000000000000000Full;
pool->thread_priority = THREAD_PRIORITY_TIME_CRITICAL;
} break;
case SYS_POOL_USER:
{
name_fmt = LIT("User worker #%F");
pool->num_worker_threads = 4;
pool->thread_affinity_mask = 0x00000000000000F0ull;
pool->thread_priority = THREAD_PRIORITY_TIME_CRITICAL;
} break;
case SYS_POOL_AUDIO:
{
name_fmt = LIT("Audio worker #%F");
pool->num_worker_threads = 2;
pool->thread_affinity_mask = 0x0000000000000300ull;
pool->thread_priority = THREAD_PRIORITY_TIME_CRITICAL;
pool->thread_is_audio = 1;
} break;
case SYS_POOL_BACKGROUND:
{
name_fmt = LIT("Background worker #%F");
pool->num_worker_threads = 2;
pool->thread_affinity_mask = 0x0000000000000C00ull;
} break;
case SYS_POOL_FLOATING:
{
name_fmt = LIT("Floating worker #%F");
pool->num_worker_threads = 8;
pool->thread_affinity_mask = 0x0000000000000FFFull;
} break;
}
pool->worker_threads_arena = arena_alloc(GIBI(64));
pool->worker_threads = arena_push_array(pool->worker_threads_arena, struct sys_thread *, pool->num_worker_threads);
pool->worker_contexts = arena_push_array(pool->worker_threads_arena, struct worker_ctx, pool->num_worker_threads);
for (i32 i = 0; i < pool->num_worker_threads; ++i) {
struct worker_ctx *ctx = &pool->worker_contexts[i];
ctx->pool_kind = pool_kind;
ctx->id = i;
struct string name = string_format(scratch.arena, name_fmt, FMT_SINT(i));
pool->worker_threads[i] = sys_thread_alloc(job_worker_entry, ctx, name, prof_group + i);
}
}
/* Wait on workers */
for (enum sys_pool pool_kind = 0; pool_kind < (i32)countof(G.job_pools); ++pool_kind) {
struct job_pool *pool = &G.job_pools[pool_kind];
for (i32 i = 0; i < pool->num_worker_threads; ++i) {
struct sys_thread *worker_thread = pool->worker_threads[i];
sys_thread_wait_release(worker_thread);
}
}
/* Wait on scheduler */
sys_thread_wait_release(scheduler_thread);
scratch_end(scratch);
}
@ -2286,7 +2190,6 @@ INTERNAL SYS_THREAD_DEF(window_thread, arg)
/* Win32 limitation: Window must be initialized on same thread that processes events */ /* Win32 limitation: Window must be initialized on same thread that processes events */
window->hwnd = win32_window_init(window); window->hwnd = win32_window_init(window);
window->tid = sys_thread_id();
win32_update_window_from_system(window); win32_update_window_from_system(window);
BringWindowToTop(window->hwnd); BringWindowToTop(window->hwnd);
snc_counter_add(&window->ready_fence, -1); snc_counter_add(&window->ready_fence, -1);
@ -2332,7 +2235,7 @@ INTERNAL struct win32_window *win32_window_alloc(void)
* created and receive a HWND, because on Windows a the event proc must run on * created and receive a HWND, because on Windows a the event proc must run on
* the same thread that created the window. */ * the same thread that created the window. */
snc_counter_add(&window->ready_fence, 1); snc_counter_add(&window->ready_fence, 1);
window->window_thread = sys_thread_alloc(&window_thread, window, LIT("Win32 window thread"), PROF_THREAD_GROUP_WINDOW); window->window_thread = sys_thread_alloc(&window_thread, window, LIT("Window thread"), PROF_THREAD_GROUP_WINDOW);
snc_counter_wait(&window->ready_fence); snc_counter_wait(&window->ready_fence);
return window; return window;
@ -2951,7 +2854,7 @@ INTERNAL DWORD WINAPI win32_thread_proc(LPVOID vt)
SetThreadDescription(GetCurrentThread(), t->thread_name_wstr); SetThreadDescription(GetCurrentThread(), t->thread_name_wstr);
} }
logf_info("New thread \"%F\" created with ID %F", FMT_STR(string_from_cstr_no_limit(t->thread_name_cstr)), FMT_UINT(sys_thread_id())); logf_info("New thread \"%F\" created with ID %F", FMT_STR(string_from_cstr_no_limit(t->thread_name_cstr)), FMT_UINT(sys_current_thread_id()));
/* Enter thread entry point */ /* Enter thread entry point */
t->entry_point(t->thread_data); t->entry_point(t->thread_data);
@ -3055,18 +2958,11 @@ void sys_thread_force_release(struct sys_thread *thread)
win32_thread_release(t); win32_thread_release(t);
} }
u32 sys_thread_id(void) u32 sys_current_thread_id(void)
{ {
return GetCurrentThreadId(); return GetCurrentThreadId();
} }
#if RTC
void sys_thread_assert(u32 tid)
{
ASSERT(sys_thread_id() == tid);
}
#endif
/* ========================== * /* ========================== *
* Address * Address
* ========================== */ * ========================== */
@ -3640,19 +3536,6 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
/* Query system info */ /* Query system info */
GetSystemInfo(&G.info); GetSystemInfo(&G.info);
/* Init threads pool */
G.threads_arena = arena_alloc(GIBI(64));
/* Init watches pool */
G.watches_arena = arena_alloc(GIBI(64));
/* Init windows pool */
G.windows_arena = arena_alloc(GIBI(64));
/* Init winsock */
WSAStartup(MAKEWORD(2, 2), &G.wsa_data);
G.socks_arena = arena_alloc(GIBI(64));
/* Initialize vk table */ /* Initialize vk table */
win32_init_vk_btn_table(); win32_init_vk_btn_table();
@ -3691,10 +3574,84 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
(UNUSED)success; (UNUSED)success;
} }
/* Start test thread */ /* Init threads pool */
struct sys_thread *test_thread = 0; G.threads_arena = arena_alloc(GIBI(64));
if (!atomic32_fetch(&G.panicking)) {
test_thread = sys_thread_alloc(test_entry, 0, LIT("Test thread"), PROF_THREAD_GROUP_APP); /* Init watches pool */
G.watches_arena = arena_alloc(GIBI(64));
/* Init windows pool */
G.windows_arena = arena_alloc(GIBI(64));
/* Init winsock */
WSAStartup(MAKEWORD(2, 2), &G.wsa_data);
G.socks_arena = arena_alloc(GIBI(64));
/* Start job scheduler */
atomic64_fetch_set(&G.current_scheduler_cycle_period_ns.v, DEFAULT_SCHEDULER_CYCLE_PERIOD_NS);
struct sys_thread *scheduler_thread = sys_thread_alloc(job_scheduler_entry, 0, LIT("Scheduler thread"), PROF_THREAD_GROUP_SCHEDULER);
/* Start job workers */
/* TODO: Heuristic worker counts & affinities */
{
__profn("Start job workers");
for (enum sys_pool pool_kind = 0; pool_kind < (i32)countof(G.job_pools); ++pool_kind) {
struct job_pool *pool = &G.job_pools[pool_kind];
struct string name_fmt = ZI;
i32 prof_group = PROF_THREAD_GROUP_FIBERS - MEBI(pool_kind);
switch (pool_kind) {
default: ASSERT(0); break;
case SYS_POOL_SIM:
{
name_fmt = LIT("Sim worker #%F");
pool->num_worker_threads = 4;
pool->thread_affinity_mask = 0x000000000000000Full;
pool->thread_priority = THREAD_PRIORITY_TIME_CRITICAL;
} break;
case SYS_POOL_USER:
{
name_fmt = LIT("User worker #%F");
pool->num_worker_threads = 4;
pool->thread_affinity_mask = 0x00000000000000F0ull;
pool->thread_priority = THREAD_PRIORITY_TIME_CRITICAL;
} break;
case SYS_POOL_AUDIO:
{
name_fmt = LIT("Audio worker #%F");
pool->num_worker_threads = 2;
pool->thread_affinity_mask = 0x0000000000000300ull;
pool->thread_priority = THREAD_PRIORITY_TIME_CRITICAL;
pool->thread_is_audio = 1;
} break;
case SYS_POOL_BACKGROUND:
{
name_fmt = LIT("Background worker #%F");
pool->num_worker_threads = 2;
pool->thread_affinity_mask = 0x0000000000000C00ull;
} break;
case SYS_POOL_FLOATING:
{
name_fmt = LIT("Floating worker #%F");
pool->num_worker_threads = 8;
pool->thread_affinity_mask = 0x0000000000000FFFull;
} break;
}
pool->worker_threads_arena = arena_alloc(GIBI(64));
pool->worker_threads = arena_push_array(pool->worker_threads_arena, struct sys_thread *, pool->num_worker_threads);
pool->worker_contexts = arena_push_array(pool->worker_threads_arena, struct worker_ctx, pool->num_worker_threads);
for (i32 i = 0; i < pool->num_worker_threads; ++i) {
struct worker_ctx *ctx = &pool->worker_contexts[i];
ctx->pool_kind = pool_kind;
ctx->id = i;
struct string name = string_format(pool->worker_threads_arena, name_fmt, FMT_SINT(i));
pool->worker_threads[i] = sys_thread_alloc(job_worker_entry, ctx, name, prof_group + i);
}
}
} }
/* ========================== * /* ========================== *
@ -3746,13 +3703,9 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
WaitForMultipleObjects(countof(handles), handles, 0, INFINITE); WaitForMultipleObjects(countof(handles), handles, 0, INFINITE);
} }
/* Signal sys shutdown */ /* Signal shutdown */
if (!atomic32_fetch(&G.panicking)) { if (!atomic32_fetch(&G.panicking)) {
atomic32_fetch_set(&G.shutdown, 1); atomic32_fetch_set(&G.shutdown, 1);
}
/* Shutdown test thread */
if (!atomic32_fetch(&G.panicking)) {
for (enum sys_pool pool_kind = 0; pool_kind < (i32)countof(G.job_pools); ++pool_kind) { for (enum sys_pool pool_kind = 0; pool_kind < (i32)countof(G.job_pools); ++pool_kind) {
struct job_pool *pool = &G.job_pools[pool_kind]; struct job_pool *pool = &G.job_pools[pool_kind];
struct snc_lock lock = snc_lock_e(&pool->workers_wake_mutex); struct snc_lock lock = snc_lock_e(&pool->workers_wake_mutex);
@ -3762,7 +3715,22 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
} }
snc_unlock(&lock); snc_unlock(&lock);
} }
sys_thread_wait_release(test_thread); }
/* Wait on worker threads */
if (!atomic32_fetch(&G.panicking)) {
for (enum sys_pool pool_kind = 0; pool_kind < (i32)countof(G.job_pools); ++pool_kind) {
struct job_pool *pool = &G.job_pools[pool_kind];
for (i32 i = 0; i < pool->num_worker_threads; ++i) {
struct sys_thread *worker_thread = pool->worker_threads[i];
sys_thread_wait_release(worker_thread);
}
}
}
/* Wait on scheduler thread */
if (!atomic32_fetch(&G.panicking)) {
sys_thread_wait_release(scheduler_thread);
} }
/* Find any dangling threads that haven't exited gracefully by now */ /* Find any dangling threads that haven't exited gracefully by now */