fibers test wip
This commit is contained in:
parent
b017a9a477
commit
fe40690871
@ -83,7 +83,7 @@
|
||||
|
||||
|
||||
|
||||
#define FIBERS_TEST 0
|
||||
#define FIBERS_TEST 1
|
||||
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
* ========================== */
|
||||
|
||||
300
src/sys_win32.c
300
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);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user