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 <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2026-05-28 12:10:08 +09:00
parent dfc542dbc5
commit c09196ca36
+53 -52
View File
@@ -14,7 +14,6 @@
#include <mruby/internal.h> #include <mruby/internal.h>
#include <mruby/proc.h> #include <mruby/proc.h>
#include <mruby/string.h> #include <mruby/string.h>
#include <mruby/throw.h>
#include <mruby/variable.h> #include <mruby/variable.h>
#include <string.h> #include <string.h>
#include <stdint.h> #include <stdint.h>
@@ -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 */ /* Main scheduler loop */
MRB_API mrb_value MRB_API mrb_value
mrb_task_run(mrb_state *mrb) mrb_task_run(mrb_state *mrb)
{ {
struct mrb_jmpbuf *prev_jmp;
struct mrb_jmpbuf c_jmp;
mrb_task *t;
if (mrb->task.loop_running) { if (mrb->task.loop_running) {
return mrb_nil_value(); return mrb_nil_value();
} }
mrb->task.loop_running = TRUE; mrb->task.loop_running = TRUE;
prev_jmp = mrb->jmp; mrb_bool error = FALSE;
MRB_TRY(&c_jmp) { mrb_value result = mrb_protect_error(mrb, task_run_body, NULL, &error);
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->task.loop_running = FALSE; 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 */ /* Single-step task execution for WASM event loop integration */