remove threads outside of system layer
This commit is contained in:
parent
0948e357c6
commit
a5582f098f
@ -678,10 +678,8 @@ INLINE f64 clamp_f64(f64 v, f64 min, f64 max) { return v < min ? min : v > max ?
|
||||
#include "prof_tracy.h"
|
||||
|
||||
#define PROF_THREAD_GROUP_FIBERS -GIBI(1)
|
||||
#define PROF_THREAD_GROUP_SCHEDULER -MEBI(5)
|
||||
#define PROF_THREAD_GROUP_IO -MEBI(4)
|
||||
#define PROF_THREAD_GROUP_WINDOW -MEBI(3)
|
||||
#define PROF_THREAD_GROUP_APP -MEBI(2)
|
||||
#define PROF_THREAD_GROUP_SCHEDULER -MEBI(3)
|
||||
#define PROF_THREAD_GROUP_WINDOW -MEBI(2)
|
||||
#define PROF_THREAD_GROUP_MAIN -MEBI(1)
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
@ -148,7 +148,7 @@ void _log(i32 level, struct string msg)
|
||||
struct sys_datetime datetime = sys_local_time();
|
||||
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 string shorthand = settings.shorthand;
|
||||
|
||||
@ -326,7 +326,7 @@ INTERNAL void push_load_job(struct cache_ref ref, struct sprite_tag tag)
|
||||
}
|
||||
|
||||
/* 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)
|
||||
|
||||
12
src/sys.h
12
src/sys.h
@ -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);
|
||||
|
||||
/* ========================== *
|
||||
* Threads
|
||||
* Thread
|
||||
* ========================== */
|
||||
|
||||
#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);
|
||||
|
||||
/* Gets the current executing thread's ID */
|
||||
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
|
||||
u32 sys_current_thread_id(void);
|
||||
|
||||
/* ========================== *
|
||||
* Address
|
||||
|
||||
246
src/sys_win32.c
246
src/sys_win32.c
@ -91,7 +91,6 @@ struct win32_window {
|
||||
u32 flags;
|
||||
|
||||
HWND hwnd;
|
||||
u32 tid;
|
||||
struct snc_counter ready_fence;
|
||||
|
||||
u16 utf16_high_surrogate_last_input;
|
||||
@ -181,10 +180,9 @@ struct alignas(64) fiber {
|
||||
/* ==================================================== */
|
||||
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 parent_id; /* 02 bytes */
|
||||
i16 unyielding; /* 02 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());
|
||||
i16 parent_id = fiber->parent_id;
|
||||
if (parent_id != 0 && !fiber->unyielding) {
|
||||
if (parent_id != 0) {
|
||||
*fiber->yield_param = (struct yield_param) {
|
||||
.kind = YIELD_KIND_WAIT,
|
||||
.wait = {
|
||||
@ -604,7 +602,7 @@ INTERNAL void wake_fibers_locked(i32 num_fibers, struct fiber **fibers)
|
||||
fiber->next_time_waiter = 0;
|
||||
}
|
||||
/* Unlock fiber */
|
||||
atomic16_fetch_set(&fiber->wake_lock, 0);
|
||||
atomic32_fetch_set(&fiber->wake_lock, 0);
|
||||
}
|
||||
/* Unlock wait bins */
|
||||
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->counter = fiber->job_counter;
|
||||
info->fiber_id = fiber->id;
|
||||
if (queue->last) {
|
||||
queue->last->next = info;
|
||||
if (queue->first) {
|
||||
info->next = queue->first;
|
||||
} else {
|
||||
queue->first = info;
|
||||
}
|
||||
queue->last = info;
|
||||
}
|
||||
queue->first = info;
|
||||
}
|
||||
tm_unlock(&queue->lock);
|
||||
}
|
||||
|
||||
@ -688,7 +686,7 @@ INTERNAL void wake_address(void *addr, i32 count)
|
||||
if (wait_addr_list) {
|
||||
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)) {
|
||||
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;
|
||||
++num_fibers;
|
||||
}
|
||||
@ -739,7 +737,7 @@ INTERNAL void wake_time(u64 time)
|
||||
/* Set waiter wake status & build fibers list */
|
||||
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)) {
|
||||
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;
|
||||
++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_counter = job_counter;
|
||||
job_fiber->yield_param = &yield;
|
||||
job_fiber->unyielding = 0;
|
||||
b32 done = 0;
|
||||
while (!done) {
|
||||
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 */
|
||||
window->hwnd = win32_window_init(window);
|
||||
window->tid = sys_thread_id();
|
||||
win32_update_window_from_system(window);
|
||||
BringWindowToTop(window->hwnd);
|
||||
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
|
||||
* the same thread that created the window. */
|
||||
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);
|
||||
|
||||
return window;
|
||||
@ -2951,7 +2854,7 @@ INTERNAL DWORD WINAPI win32_thread_proc(LPVOID vt)
|
||||
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 */
|
||||
t->entry_point(t->thread_data);
|
||||
@ -3055,18 +2958,11 @@ void sys_thread_force_release(struct sys_thread *thread)
|
||||
win32_thread_release(t);
|
||||
}
|
||||
|
||||
u32 sys_thread_id(void)
|
||||
u32 sys_current_thread_id(void)
|
||||
{
|
||||
return GetCurrentThreadId();
|
||||
}
|
||||
|
||||
#if RTC
|
||||
void sys_thread_assert(u32 tid)
|
||||
{
|
||||
ASSERT(sys_thread_id() == tid);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* ========================== *
|
||||
* Address
|
||||
* ========================== */
|
||||
@ -3640,19 +3536,6 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
|
||||
/* Query system 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 */
|
||||
win32_init_vk_btn_table();
|
||||
|
||||
@ -3691,10 +3574,84 @@ int CALLBACK wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev_instance,
|
||||
(UNUSED)success;
|
||||
}
|
||||
|
||||
/* Start test thread */
|
||||
struct sys_thread *test_thread = 0;
|
||||
if (!atomic32_fetch(&G.panicking)) {
|
||||
test_thread = sys_thread_alloc(test_entry, 0, LIT("Test thread"), PROF_THREAD_GROUP_APP);
|
||||
/* 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));
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Signal sys shutdown */
|
||||
/* Signal shutdown */
|
||||
if (!atomic32_fetch(&G.panicking)) {
|
||||
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) {
|
||||
struct job_pool *pool = &G.job_pools[pool_kind];
|
||||
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);
|
||||
}
|
||||
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 */
|
||||
|
||||
Loading…
Reference in New Issue
Block a user