mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
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:
@@ -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 */
|
||||||
|
|||||||
Reference in New Issue
Block a user