diff --git a/src/config.h b/src/config.h index 5743bb01..ced28b19 100644 --- a/src/config.h +++ b/src/config.h @@ -83,7 +83,7 @@ -#define FIBERS_TEST 0 +#define FIBERS_TEST 1 diff --git a/src/sys_win32-old.c b/src/sys_win32-old.c index 4dbeed08..19eb661f 100644 --- a/src/sys_win32-old.c +++ b/src/sys_win32-old.c @@ -2339,6 +2339,310 @@ b32 sys_run_command(struct string cmd) return success; } + + + + + + + + + + + + + + + + + + + + + + +#if 0 + +/* ========================== * + * Testing + * ========================== */ + +#define FIBER_STACK_SIZE MEGABYTE(4) + +#define TJOB_DEF(name, arg) void name(void *arg) +typedef TJOB_DEF(tjob_func, arg); + +enum fiber_yield_reason { + FIBER_YIELD_REASON_NONE, + + FIBER_YIELD_REASON_SLEEP, + + FIBER_YIELD_REASON_DONE +}; + +struct fiber { + const char *name; + void *addr; + + struct tjob *current_job; + + enum fiber_yield_reason yield_reason; +}; + +struct tjob { + tjob_func *func; + void *arg; + + struct tjob *next; +}; + + +#define NUM_RUNNERS 6 +GLOBAL struct { + + struct atomic_i32 fibers_lock; + struct arena *fibers_arena; + + + + + + void *runner_fiber_addr; + struct fiber f1; + + struct arena *arena; + b32 shutdown; + struct atomic_i32 lock; + struct tjob *first_free_job; + struct tjob *first_job; + struct tjob *last_job; +} g_test; + + + +INTERNAL void atomic_lock(void) +{ + while (atomic_i32_fetch_test_set(&g_test.lock, 0, 1) != 0) { + ix_pause(); + } +} + +INTERNAL void atomic_unlock(void) +{ + atomic_i32_fetch_set(&g_test.lock, 0); +} + +INTERNAL void push_job(tjob_func *func, void *arg) +{ + atomic_lock(); + { + struct tjob *job = NULL; + if (g_test.first_free_job) { + job = g_test.first_free_job; + g_test.first_free_job = job->next; + } else { + job = arena_push_no_zero(g_test.arena, struct tjob); + } + *job = (struct tjob) { .func = func, .arg = arg }; + if (g_test.last_job) { + g_test.last_job->next = job; + } else { + g_test.first_job = job; + } + g_test.last_job = job; + } + atomic_unlock(); +} + + + + + + +INTERNAL void yield(struct fiber *fiber, enum fiber_yield_reason reason) +{ + fiber->yield_reason = reason; + __prof_fiber_leave; + SwitchToFiber(g_test.runner_fiber_addr); + __prof_fiber_enter(fiber->name); +} + +INTERNAL TJOB_DEF(test_job, arg) +{ + __prof; + struct fiber *fiber = arg; + (UNUSED)fiber; + (UNUSED)yield; + +#if 1 + Sleep(50); + yield(fiber, FIBER_YIELD_REASON_SLEEP); + Sleep(50); +#else + Sleep(50); +#endif +} + + + + + + + +INTERNAL void fiber_proc(void *vfiber) +{ + DEBUGBREAKABLE; + struct fiber *fiber = vfiber; + (UNUSED)fiber; + while (true) { + __prof_fiber_enter(fiber->name); + { + fiber->yield_reason = FIBER_YIELD_REASON_NONE; + fiber->current_job->func(fiber->current_job->arg); + fiber->yield_reason = FIBER_YIELD_REASON_DONE; + } + __prof_fiber_leave; + SwitchToFiber(g_test.runner_fiber_addr); + } +} + +struct runner_thread_param { + i32 id; +}; + +INTERNAL DWORD WINAPI runner_thread_proc(LPVOID tparam) +{ + __prof; + struct runner_thread_param *param = tparam; + struct arena *arena = arena_alloc(GIGABYTE(64)); + + /* Set thread name */ + { + struct string id_str = string_from_int(arena, param->id, 10, 1); + struct string name = string_format(arena, LIT("Runner thread %F"), FMT_STR(id_str)); + wchar_t *name_wstr = wstr_from_string(arena, name); + SetThreadDescription(GetCurrentThread(), name_wstr); + } + + g_test.runner_fiber_addr = ConvertThreadToFiber(NULL); + g_test.f1.name = "Fiber 1"; + g_test.f1.addr = CreateFiber(FIBER_STACK_SIZE, fiber_proc, &g_test.f1); + + b32 shutdown = false; + while (!shutdown) { + Sleep(100); + struct arena_temp temp = arena_temp_begin(arena); + + atomic_lock(); + shutdown = g_test.shutdown; + if (!shutdown && g_test.first_job) { + /* Pull job */ + struct tjob local_job = ZI; + { + struct tjob *job = g_test.first_job; + local_job = *job; + struct tjob *next = job->next; + g_test.first_job = next; + if (!next) { + g_test.last_job = NULL; + } + } + /* Run job */ + atomic_unlock(); + { + __profscope(Run job); + struct fiber *fiber = &g_test.f1; + fiber->current_job = &local_job; + fiber->yield_reason = FIBER_YIELD_REASON_NONE; + b32 done = false; + while (!done) { + SwitchToFiber(fiber->addr); + enum fiber_yield_reason yield_reason = fiber->yield_reason; + switch (yield_reason) { + default: break; + + case FIBER_YIELD_REASON_SLEEP: + { + __profscope(Sleep); + Sleep(100); + } break; + + case FIBER_YIELD_REASON_DONE: + { + done = true; + } break; + } + } + } + atomic_lock(); + } + atomic_unlock(); + arena_temp_end(temp); + } + + arena_release(arena); + return 0; +} + +INTERNAL void test_main(struct string cmdline) +{ + __prof; + (UNUSED)cmdline; + struct arena *arena = arena_alloc(GIGABYTE(64)); + { + g_test.arena = arena_alloc(GIGABYTE(64)); + + Sleep(1000); + for (u32 i = 0; i < 50; ++i) { + push_job(test_job, &g_test.f1); + } + + u32 num_runners = NUM_RUNNERS; + HANDLE *runner_thread_handles = arena_push_array(arena, HANDLE, num_runners); + struct runner_thread_param *tparams = arena_push_array(arena, struct runner_thread_param, num_runners); + for (u32 i = 0; i < num_runners; ++i) { + struct runner_thread_param *tparam = &tparams[i]; + tparam->id = i; + runner_thread_handles[i] = CreateThread(NULL, MEGABYTE(1), runner_thread_proc, tparam, 0, NULL); + //SetThreadDescription(GetCurrentThread(), t->thread_name_wstr); + } + + struct sys_thread *runner_thread = sys_thread_alloc(runner_thread_entry_point, NULL, LIT("Runner thread")); + Sleep(5000); + + { + atomic_lock(); + g_test.shutdown = true; + atomic_unlock(); + } + + for (u32 i = 0; i < num_runners; ++i) { + HANDLE handle = runner_thread_handles[i]; + DWORD wait_res = WaitForSingleObject(handle, INFINITE); + if (wait_res == WAIT_OBJECT_0) { + CloseHandle(handle); + } + } + } + arena_release(arena); +} + +#endif + + + + + + + + + + + + + + + /* ========================== * * Entry point * ========================== */ diff --git a/src/sys_win32.c b/src/sys_win32.c index e293bb65..8b70b00a 100644 --- a/src/sys_win32.c +++ b/src/sys_win32.c @@ -2338,301 +2338,6 @@ b32 sys_run_command(struct string cmd) } return success; } - - - - - - - - - - - - - -/* ========================== * - * Testing - * ========================== */ - -#define FIBER_STACK_SIZE MEGABYTE(4) - -#define TJOB_DEF(name, arg) void name(void *arg) -typedef TJOB_DEF(tjob_func, arg); - -enum fiber_yield_reason { - FIBER_YIELD_REASON_NONE, - - FIBER_YIELD_REASON_SLEEP, - - FIBER_YIELD_REASON_DONE -}; - -struct fiber { - const char *name; - void *addr; - - struct tjob *current_job; - - enum fiber_yield_reason yield_reason; -}; - -struct tjob { - tjob_func *func; - void *arg; - - struct tjob *next; -}; - - - -GLOBAL struct { - void *runner_fiber_addr; - struct fiber f1; - - struct arena *arena; - b32 shutdown; - struct atomic_i32 lock; - struct tjob *first_free_job; - struct tjob *first_job; - struct tjob *last_job; -} g_test; - - - -INTERNAL void atomic_lock(void) -{ - while (atomic_i32_fetch_test_set(&g_test.lock, 0, 1) != 0) { - ix_pause(); - } -} - -INTERNAL void atomic_unlock(void) -{ - atomic_i32_fetch_set(&g_test.lock, 0); -} - -INTERNAL void push_job(tjob_func *func, void *arg) -{ - atomic_lock(); - { - struct tjob *job = NULL; - if (g_test.first_free_job) { - job = g_test.first_free_job; - g_test.first_free_job = job->next; - } else { - job = arena_push_no_zero(g_test.arena, struct tjob); - } - *job = (struct tjob) { .func = func, .arg = arg }; - if (g_test.last_job) { - g_test.last_job->next = job; - } else { - g_test.first_job = job; - } - g_test.last_job = job; - } - atomic_unlock(); -} - - - - - - -INTERNAL void yield(struct fiber *fiber, enum fiber_yield_reason reason) -{ - fiber->yield_reason = reason; - __prof_fiber_leave; - SwitchToFiber(g_test.runner_fiber_addr); - __prof_fiber_enter(fiber->name); -} - -INTERNAL TJOB_DEF(test_job, arg) -{ - __prof; - struct fiber *fiber = arg; - (UNUSED)fiber; - (UNUSED)yield; - -#if 1 - Sleep(50); - yield(fiber, FIBER_YIELD_REASON_SLEEP); - Sleep(50); -#else - Sleep(50); -#endif -} - - - - - - - -INTERNAL void fiber_proc(void *vfiber) -{ - DEBUGBREAKABLE; - struct fiber *fiber = vfiber; - (UNUSED)fiber; - while (true) { - __prof_fiber_enter(fiber->name); - { - fiber->yield_reason = FIBER_YIELD_REASON_NONE; - fiber->current_job->func(fiber->current_job->arg); - fiber->yield_reason = FIBER_YIELD_REASON_DONE; - } - __prof_fiber_leave; - SwitchToFiber(g_test.runner_fiber_addr); - } -} - -struct runner_thread_param { - i32 id; -}; - -INTERNAL DWORD WINAPI runner_thread_proc(LPVOID tparam) -{ - __prof; - struct runner_thread_param *param = tparam; - struct arena *arena = arena_alloc(GIGABYTE(64)); - - /* Set thread name */ - { - struct string id_str = string_from_int(arena, param->id, 10, 1); - struct string name = string_format(arena, LIT("Runner thread %F"), FMT_STR(id_str)); - wchar_t *name_wstr = wstr_from_string(arena, name); - SetThreadDescription(GetCurrentThread(), name_wstr); - } - - g_test.runner_fiber_addr = ConvertThreadToFiber(NULL); - g_test.f1.name = "Fiber 1"; - g_test.f1.addr = CreateFiber(FIBER_STACK_SIZE, fiber_proc, &g_test.f1); - - b32 shutdown = false; - while (!shutdown) { - Sleep(100); - struct arena_temp temp = arena_temp_begin(arena); - - atomic_lock(); - shutdown = g_test.shutdown; - if (!shutdown && g_test.first_job) { - /* Pull job */ - struct tjob local_job = ZI; - { - struct tjob *job = g_test.first_job; - local_job = *job; - struct tjob *next = job->next; - g_test.first_job = next; - if (!next) { - g_test.last_job = NULL; - } - } - /* Run job */ - atomic_unlock(); - { - __profscope(Run job); - struct fiber *fiber = &g_test.f1; - fiber->current_job = &local_job; - fiber->yield_reason = FIBER_YIELD_REASON_NONE; - b32 done = false; - while (!done) { - SwitchToFiber(fiber->addr); - enum fiber_yield_reason yield_reason = fiber->yield_reason; - switch (yield_reason) { - default: break; - - case FIBER_YIELD_REASON_SLEEP: - { - __profscope(Sleep); - Sleep(100); - } break; - - case FIBER_YIELD_REASON_DONE: - { - done = true; - } break; - } - } - } - atomic_lock(); - } - atomic_unlock(); - arena_temp_end(temp); - } - - arena_release(arena); -} - -INTERNAL void test_main(struct string cmdline) -{ - __prof; - (UNUSED)cmdline; - struct arena *arena = arena_alloc(GIGABYTE(64)); - { - g_test.arena = arena_alloc(GIGABYTE(64)); - - Sleep(1000); - for (u32 i = 0; i < 50; ++i) { - push_job(test_job, &g_test.f1); - } - - u32 num_runners = NUM_RUNNERS; - HANDLE *runner_thread_handles = arena_push_array(arena, HANDLE, num_runners); - struct runner_thread_param *tparams = arena_push_array(arena, struct runner_thread_param, num_runners); - for (u32 i = 0; i < num_runners; ++i) { - struct runner_thread_param *tparam = &tparams[i]; - tparam->id = i; - runner_thread_handles[i] = CreateThread(NULL, MEGABYTE(1), runner_thread_proc, tparam, 0, NULL); - //SetThreadDescription(GetCurrentThread(), t->thread_name_wstr); - } - - struct sys_thread *runner_thread = sys_thread_alloc(runner_thread_entry_point, NULL, LIT("Runner thread")); - Sleep(5000); - - { - atomic_lock(); - g_test.shutdown = true; - atomic_unlock(); - } - - for (u32 i = 0; i < num_runners; ++i) { - HANDLE handle = runner_thread_handles[i]; - DWORD wait_res = WaitForSingleObject(handle, INFINITE); - if (wait_res == WAIT_OBJECT_0) { - CloseHandle(handle); - } - } - } - arena_release(arena); -} - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* ========================== * * Entry point @@ -2643,12 +2348,7 @@ INTERNAL SYS_THREAD_DEF(win32_app_thread_entry_point, arg) (UNUSED)arg; struct arena_temp scratch = scratch_begin_no_conflict(); struct string cmdline_args = string_from_wstr(scratch.arena, G.cmdline_args_wstr, ARRAY_COUNT(G.cmdline_args_wstr)); -#if 0 - (UNUSED)test_main; app_entry_point(cmdline_args); -#else - test_main(cmdline_args); -#endif scratch_end(scratch); }