diff --git a/src/common.h b/src/common.h index 38cd9cbe..d44ca8d0 100644 --- a/src/common.h +++ b/src/common.h @@ -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 diff --git a/src/log.c b/src/log.c index 4d8b3b7f..143b4e67 100644 --- a/src/log.c +++ b/src/log.c @@ -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; diff --git a/src/sprite.c b/src/sprite.c index d2528eae..0822f7e7 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -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) diff --git a/src/sys.h b/src/sys.h index 43bf8a51..6573e02c 100644 --- a/src/sys.h +++ b/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 diff --git a/src/sys_win32.c b/src/sys_win32.c index 10fcb82a..ad2bfb7d 100644 --- a/src/sys_win32.c +++ b/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,12 +634,12 @@ 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->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 */