From 1b69b33a4e2ffbb4fb6229c6a6521c7bc299c076 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Sat, 4 Oct 2025 13:18:31 +0900 Subject: [PATCH] mruby-task: implement scheduler algorithm and sleep operations implement core scheduling components: - mrb_tick: tick handler for timeslice countdown and sleep wakeup - mrb_tasks_run: main scheduler loop with context switching - sleep operations: sleep_ms_impl, sleep, sleep_ms - hal stub implementations for compilation (temporary) the scheduler uses tick-based preemption with round-robin at same priority. sleeping tasks wake when their tick count expires. completed tasks move to dormant queue and wake any waiting joiners. Co-authored-by: Claude --- mrbgems/mruby-task/src/task.c | 227 ++++++++++++++++++++++++++++++---- 1 file changed, 206 insertions(+), 21 deletions(-) diff --git a/mrbgems/mruby-task/src/task.c b/mrbgems/mruby-task/src/task.c index 319382bb1..7dd336c6b 100644 --- a/mrbgems/mruby-task/src/task.c +++ b/mrbgems/mruby-task/src/task.c @@ -12,9 +12,12 @@ #include #include #include +#include #include #include #include +#include +#include #include "../include/task.h" /* @@ -214,25 +217,124 @@ task_init_context(mrb_state *mrb, mrb_task *t, const struct RProc *proc) void mrb_tick(mrb_state *mrb) { - /* TODO: Implement tick handler - * - Increment tick counter - * - Decrease current task timeslice - * - Wake up sleeping tasks - * - Set switching flag if needed - */ + mrb_task *t; + + /* Increment global tick counter */ + tick_++; + + /* Decrease timeslice for running task */ + t = q_ready_; + if (t && t->status == MRB_TASKSTATUS_RUNNING && t->timeslice > 0) { + t->timeslice--; + if (t->timeslice == 0) { + switching_ = TRUE; /* Trigger context switch */ + } + } + + /* Wake up sleeping tasks whose wakeup time has passed */ + if ((int32_t)(wakeup_tick_ - tick_) <= 0) { + mrb_task *curr = q_waiting_; + mrb_task *next; + uint32_t next_wakeup = UINT32_MAX; + + while (curr != NULL) { + next = curr->next; + + if (curr->reason == MRB_TASKREASON_SLEEP) { + if ((int32_t)(curr->wakeup_tick - tick_) <= 0) { + /* Time to wake up */ + q_delete_task(mrb, curr); + curr->status = MRB_TASKSTATUS_READY; + curr->reason = MRB_TASKREASON_NONE; + q_insert_task(mrb, curr); + switching_ = TRUE; + } + else if (curr->wakeup_tick < next_wakeup) { + next_wakeup = curr->wakeup_tick; + } + } + + curr = next; + } + + wakeup_tick_ = next_wakeup; + } } /* Main scheduler loop */ mrb_value mrb_tasks_run(mrb_state *mrb) { - /* TODO: Implement main scheduler loop - * - Get next ready task - * - Switch context - * - Execute via mrb_vm_exec() - * - Handle completion/switching - * - Run incremental GC - */ + mrb_task *t; + struct mrb_context *prev_c; + + while (1) { + t = q_ready_; + + /* No task ready - idle */ + if (!t) { + mrb_task_hal_idle_cpu(mrb); + continue; + } + + /* Set task as running */ + t->status = MRB_TASKSTATUS_RUNNING; + t->timeslice = MRB_TIMESLICE_TICK_COUNT; + + /* Switch to task context */ + prev_c = mrb->c; + mrb->c = &t->c; + + /* Clear switching flag */ + switching_ = FALSE; + + /* Execute task */ + t->result = mrb_vm_exec(mrb, t->c.ci->proc, t->c.ci->pc); + + /* Restore context */ + mrb->c = prev_c; + + /* Check if task finished */ + if (t->c.status == MRB_TASK_STOPPED) { + /* Move to dormant queue */ + mrb_task_disable_irq(); + q_delete_task(mrb, t); + t->status = MRB_TASKSTATUS_DORMANT; + q_insert_task(mrb, t); + mrb_task_enable_irq(); + + /* Wake up tasks waiting on join */ + mrb_task *curr = q_waiting_; + while (curr != NULL) { + mrb_task *next = curr->next; + if (curr->reason == MRB_TASKREASON_JOIN && curr->join == t) { + mrb_task_disable_irq(); + q_delete_task(mrb, curr); + curr->status = MRB_TASKSTATUS_READY; + curr->reason = MRB_TASKREASON_NONE; + curr->join = NULL; + q_insert_task(mrb, curr); + mrb_task_enable_irq(); + } + curr = next; + } + } + /* Context switch requested or task still running */ + else if (t->status == MRB_TASKSTATUS_RUNNING) { + /* Move to end of ready queue (round-robin) */ + mrb_task_disable_irq(); + q_delete_task(mrb, t); + t->status = MRB_TASKSTATUS_READY; + q_insert_task(mrb, t); + mrb_task_enable_irq(); + } + + /* Run incremental GC if active */ + if (mrb->gc.state != MRB_GC_STATE_ROOT) { + mrb_incremental_gc(mrb); + } + } + return mrb_nil_value(); } @@ -243,27 +345,110 @@ mrb_tasks_run(mrb_state *mrb) static void sleep_ms_impl(mrb_state *mrb, mrb_int ms) { - /* TODO: Implement sleep - * - Move current task to waiting queue - * - Set wakeup tick - * - Trigger context switch - */ + mrb_task *t = q_ready_; /* Current running task */ + + if (!t) return; /* No task to sleep */ + + mrb_task_disable_irq(); + + /* Remove from ready queue */ + q_delete_task(mrb, t); + + /* Move to waiting queue */ + t->status = MRB_TASKSTATUS_WAITING; + t->reason = MRB_TASKREASON_SLEEP; + t->wakeup_tick = tick_ + (ms / MRB_TICK_UNIT); + + /* Update next wakeup time if this task wakes earlier */ + if (t->wakeup_tick < wakeup_tick_) { + wakeup_tick_ = t->wakeup_tick; + } + + q_insert_task(mrb, t); + + mrb_task_enable_irq(); + + /* Trigger context switch */ + switching_ = TRUE; } static mrb_value mrb_f_sleep(mrb_state *mrb, mrb_value self) { - /* TODO: Implement Kernel#sleep */ - return mrb_nil_value(); + mrb_float sec = 0; + mrb_int n; + + n = mrb_get_args(mrb, "|f", &sec); + + if (n == 0) { + /* No argument - suspend indefinitely */ + mrb_task *t = q_ready_; + if (t) { + mrb_task_disable_irq(); + q_delete_task(mrb, t); + t->status = MRB_TASKSTATUS_SUSPENDED; + q_insert_task(mrb, t); + mrb_task_enable_irq(); + switching_ = TRUE; + } + return mrb_nil_value(); + } + + if (sec < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must be positive"); + } + + mrb_int ms = (mrb_int)(sec * 1000); + sleep_ms_impl(mrb, ms); + + return mrb_fixnum_value((mrb_int)sec); } static mrb_value mrb_f_sleep_ms(mrb_state *mrb, mrb_value self) { - /* TODO: Implement Kernel#sleep_ms */ + mrb_int ms; + + mrb_get_args(mrb, "i", &ms); + + if (ms < 0) { + mrb_raise(mrb, E_ARGUMENT_ERROR, "time interval must be positive"); + } + + sleep_ms_impl(mrb, ms); + return mrb_nil_value(); } +/* + * HAL stub implementations (temporary) + * These will be replaced with real implementations in Phase 6 + */ + +void +mrb_task_hal_init(mrb_state *mrb) +{ + /* TODO: Initialize hardware timer */ +} + +void +mrb_task_enable_irq(void) +{ + /* TODO: Enable interrupts */ +} + +void +mrb_task_disable_irq(void) +{ + /* TODO: Disable interrupts */ +} + +void +mrb_task_hal_idle_cpu(mrb_state *mrb) +{ + /* TODO: Put CPU in idle state */ +} + /* * Task class methods */