test: add green thread integration test
Also fix runtime scheduler bugs: - g_task_creating was thread-local but set on main thread and read on worker - g_scheduler_context was global shared by all workers instead of per-thread
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
[package]
|
||||||
|
name = "green_threads_test"
|
||||||
|
version = "0.1.0"
|
||||||
|
pkgType = "bin"
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
import Std::Task;
|
||||||
|
import Std::String;
|
||||||
|
|
||||||
|
func Worker(id: int) {
|
||||||
|
PrintLine(String_Concat(String_Concat("Worker ", String_FromInt(id)), " starting"));
|
||||||
|
Task_Sleep(50);
|
||||||
|
PrintLine(String_Concat(String_Concat("Worker ", String_FromInt(id)), " done"));
|
||||||
|
}
|
||||||
|
|
||||||
|
func Main() -> int {
|
||||||
|
PrintLine("=== Green Thread Test ===");
|
||||||
|
|
||||||
|
Task_Init(4);
|
||||||
|
|
||||||
|
let h1: TaskHandle = Task_Spawn(Worker as *void, 1 as *void);
|
||||||
|
let h2: TaskHandle = Task_Spawn(Worker as *void, 2 as *void);
|
||||||
|
let h3: TaskHandle = Task_Spawn(Worker as *void, 3 as *void);
|
||||||
|
|
||||||
|
PrintLine("Waiting for tasks...");
|
||||||
|
|
||||||
|
Task_Wait(h1);
|
||||||
|
Task_Wait(h2);
|
||||||
|
Task_Wait(h3);
|
||||||
|
|
||||||
|
Task_Shutdown();
|
||||||
|
|
||||||
|
PrintLine("=== All tasks complete ===");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
+6
-5
@@ -829,8 +829,7 @@ typedef struct {
|
|||||||
|
|
||||||
static BuxTaskPool g_task_pool = {0};
|
static BuxTaskPool g_task_pool = {0};
|
||||||
static __thread BuxScheduler *g_scheduler = NULL;
|
static __thread BuxScheduler *g_scheduler = NULL;
|
||||||
static __thread BuxTask *g_task_creating = NULL;
|
static __thread ucontext_t g_scheduler_context;
|
||||||
static ucontext_t g_scheduler_context;
|
|
||||||
static volatile int g_scheduler_active = 0;
|
static volatile int g_scheduler_active = 0;
|
||||||
|
|
||||||
static int64_t bux_now_ms(void);
|
static int64_t bux_now_ms(void);
|
||||||
@@ -901,7 +900,11 @@ static BuxTask* bux_find_task(BuxScheduler *sched) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void bux_task_entry(void) {
|
static void bux_task_entry(void) {
|
||||||
BuxTask *t = g_task_creating;
|
BuxTask *t = g_scheduler->current;
|
||||||
|
if (!t) {
|
||||||
|
fprintf(stderr, "bux runtime: task entry with NULL task\n");
|
||||||
|
abort();
|
||||||
|
}
|
||||||
t->func(t->arg);
|
t->func(t->arg);
|
||||||
t->state = BUX_TASK_FINISHED;
|
t->state = BUX_TASK_FINISHED;
|
||||||
swapcontext(&t->ctx, &g_scheduler_context);
|
swapcontext(&t->ctx, &g_scheduler_context);
|
||||||
@@ -987,9 +990,7 @@ void* bux_task_spawn(void* (*func)(void*), void* arg) {
|
|||||||
task->ctx.uc_stack.ss_sp = task->stack;
|
task->ctx.uc_stack.ss_sp = task->stack;
|
||||||
task->ctx.uc_stack.ss_size = task->stack_size;
|
task->ctx.uc_stack.ss_size = task->stack_size;
|
||||||
task->ctx.uc_link = &g_scheduler_context;
|
task->ctx.uc_link = &g_scheduler_context;
|
||||||
g_task_creating = task;
|
|
||||||
makecontext(&task->ctx, bux_task_entry, 0);
|
makecontext(&task->ctx, bux_task_entry, 0);
|
||||||
g_task_creating = NULL;
|
|
||||||
int worker = rand() % g_task_pool.num_workers;
|
int worker = rand() % g_task_pool.num_workers;
|
||||||
bux_queue_push(g_task_pool.schedulers[worker], task);
|
bux_queue_push(g_task_pool.schedulers[worker], task);
|
||||||
return task;
|
return task;
|
||||||
|
|||||||
Reference in New Issue
Block a user