From c09196ca364558ef4fa7f99ee9e0566cbd8cfc35 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Thu, 28 May 2026 12:10:08 +0900 Subject: [PATCH] mruby-task: switch mrb_task_run to mrb_protect_error mruby/throw.h is documented as a core-internal header that should not be included from mrbgems or user code, and under MRB_USE_CXX_EXCEPTION or MRB_USE_CXX_ABI the MRB_TRY/MRB_CATCH macros expand to C++ exception syntax that does not compile in a C source file. The wrapping added in #6866 (commit ee82a7fcc6) accidentally tripped that constraint. Drop the throw.h include and use mrb_protect_error() from mruby/error.h instead. The helper takes a body function plus userdata, runs it under its own jmpbuf, and reports whether an exception was caught. We re-raise via mrb_exc_raise so the visible behavior matches the previous code: loop_running is cleared on both success and exception, and an exception propagates back out. Refs #6866. Co-authored-by: Claude --- mrbgems/mruby-task/src/task.c | 105 +++++++++++++++++----------------- 1 file changed, 53 insertions(+), 52 deletions(-) diff --git a/mrbgems/mruby-task/src/task.c b/mrbgems/mruby-task/src/task.c index 695f6f81c..a94241534 100644 --- a/mrbgems/mruby-task/src/task.c +++ b/mrbgems/mruby-task/src/task.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -440,67 +439,69 @@ mrb_tick(mrb_state *mrb) } } +/* Body of the main scheduler loop. Wrapped by mrb_task_run() under + mrb_protect_error so an exception raised from a task body unwinds + cleanly without leaving `loop_running` set. */ +static mrb_value +task_run_body(mrb_state *mrb, void *ud) +{ + mrb_task *t; + (void)ud; + + while (1) { + t = q_ready_; + + /* No task ready - check if all tasks are done */ + if (!t) { + mrb_task_disable_irq(); + mrb_bool exiting = !q_ready_ && !q_waiting_ && !q_suspended_; + mrb_task_enable_irq(); + if (exiting) { + /* All tasks are dormant - scheduler done */ + break; + } + /* If there are tasks waiting or suspended, idle */ + mrb_hal_task_idle_cpu(mrb); + continue; + } + + /* Safety check - don't execute terminated tasks */ + if (task_cleanup_if_stopped(mrb, t)) { + continue; + } + + /* Execute task using core logic */ + execute_task(mrb, t); + + /* Move to end of ready queue if still running (round-robin) */ + if (t->status == MRB_TASK_STATUS_READY) { + task_change_state(mrb, t, MRB_TASK_STATUS_READY); + } + + /* Run incremental GC if active */ + if (mrb->gc.state != MRB_GC_STATE_ROOT) { + mrb_incremental_gc(mrb); + } + } + return mrb_nil_value(); +} + /* Main scheduler loop */ MRB_API mrb_value mrb_task_run(mrb_state *mrb) { - struct mrb_jmpbuf *prev_jmp; - struct mrb_jmpbuf c_jmp; - mrb_task *t; - if (mrb->task.loop_running) { return mrb_nil_value(); } mrb->task.loop_running = TRUE; - prev_jmp = mrb->jmp; - MRB_TRY(&c_jmp) { - mrb->jmp = &c_jmp; - - while (1) { - t = q_ready_; - - /* No task ready - check if all tasks are done */ - if (!t) { - mrb_task_disable_irq(); - mrb_bool exiting = !q_ready_ && !q_waiting_ && !q_suspended_; - mrb_task_enable_irq(); - if (exiting) { - /* All tasks are dormant - scheduler done */ - break; - } - /* If there are tasks waiting or suspended, idle */ - mrb_hal_task_idle_cpu(mrb); - continue; - } - - /* Safety check - don't execute terminated tasks */ - if (task_cleanup_if_stopped(mrb, t)) { - continue; - } - - /* Execute task using core logic */ - execute_task(mrb, t); - - /* Move to end of ready queue if still running (round-robin) */ - if (t->status == MRB_TASK_STATUS_READY) { - task_change_state(mrb, t, MRB_TASK_STATUS_READY); - } - - /* Run incremental GC if active */ - if (mrb->gc.state != MRB_GC_STATE_ROOT) { - mrb_incremental_gc(mrb); - } - } - mrb->jmp = prev_jmp; - } MRB_CATCH(&c_jmp) { - mrb->task.loop_running = FALSE; - mrb->jmp = prev_jmp; - MRB_THROW(prev_jmp); - } MRB_END_EXC(&c_jmp); - + mrb_bool error = FALSE; + mrb_value result = mrb_protect_error(mrb, task_run_body, NULL, &error); mrb->task.loop_running = FALSE; - return mrb_nil_value(); + if (error) { + mrb_exc_raise(mrb, result); + } + return result; } /* Single-step task execution for WASM event loop integration */