mruby-task: fix cooperative task yielding with Task.pass

this patch fixes several critical issues in the task scheduler:

1. vm integration for computed goto dispatch mode:
   - added task switching check in NEXT macro for computed goto
   - previous implementation only worked with switch dispatch mode
   - now Task.pass properly yields control to other tasks

2. task lifecycle tracking:
   - added 'started' flag to mrb_task structure
   - fixed first-run detection to avoid popping callinfo multiple times
   - vm overwrites context status during execution, making it unreliable

3. removed mrblib/task.rb:
   - empty Ruby method stubs were overriding C implementations
   - all task methods now properly implemented in C

4. cleaned up task scheduler loop:
   - proper task completion detection using switching flag
   - round-robin scheduling for tasks at same priority
   - clean scheduler exit when all tasks complete

tasks now cooperatively yield with Task.pass and complete cleanly.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-10-04 16:44:29 +09:00
parent b7b06a0857
commit 47dfb771cf
5 changed files with 66 additions and 140 deletions
+8 -3
View File
@@ -1523,7 +1523,7 @@ prepare_tagged_break(mrb_state *mrb, uint32_t tag, const mrb_callinfo *return_ci
#define JUMP NEXT
#ifdef MRB_USE_TASK_SCHEDULER
#define END_DISPATCH L_END_DISPATCH: \
if (mrb->task->switching || mrb->c->status == MRB_TASK_STOPPED) \
if (mrb->task.switching || mrb->c->status == MRB_TASK_STOPPED) \
return mrb_nil_value(); \
}}
#else
@@ -1534,12 +1534,17 @@ prepare_tagged_break(mrb_state *mrb, uint32_t tag, const mrb_callinfo *return_ci
#define INIT_DISPATCH JUMP; return mrb_nil_value();
#define CASE(insn,ops) L_ ## insn: { const mrb_code *pc = ci->pc+1; FETCH_ ## ops (); ci->pc = pc; } L_ ## insn ## _BODY:
#ifdef MRB_USE_TASK_SCHEDULER
#define NEXT if (mrb->task.switching || mrb->c->status == MRB_TASK_STOPPED) return mrb_nil_value(); \
insn=BYTECODE_DECODER(*ci->pc); CODE_FETCH_HOOK(mrb, irep, ci->pc, regs); goto *optable[insn]
#else
#define NEXT insn=BYTECODE_DECODER(*ci->pc); CODE_FETCH_HOOK(mrb, irep, ci->pc, regs); goto *optable[insn]
#endif
#define JUMP NEXT
#ifdef MRB_USE_TASK_SCHEDULER
#define END_DISPATCH \
if (mrb->task->switching || mrb->c->status == MRB_TASK_STOPPED) \
if (mrb->task.switching || mrb->c->status == MRB_TASK_STOPPED) \
return mrb_nil_value();
#else
#define END_DISPATCH
@@ -1549,7 +1554,7 @@ prepare_tagged_break(mrb_state *mrb, uint32_t tag, const mrb_callinfo *return_ci
#ifdef MRB_USE_TASK_SCHEDULER
#define TASK_STOP(mrb) \
if (mrb->c->status == MRB_TASK_CREATED) \
if (mrb->c->status != MRB_TASK_STOPPED) \
mrb->c->status = MRB_TASK_STOPPED;
#else
#define TASK_STOP(mrb)