mruby-task: support multiple concurrent mrb_states

replace global_mrb with vm_list to support up to 8 concurrent mrb_state
instances. sigalrm handler now ticks all registered VMs. first VM
initializes timer, last VM stops timer. proper cleanup in hal_final.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-10-06 23:27:30 +09:00
parent fab6ccc794
commit 4e7b6babe8
2 changed files with 97 additions and 18 deletions
+1
View File
@@ -85,6 +85,7 @@ typedef struct mrb_task {
* Platform-specific implementations must provide these
*/
void mrb_task_hal_init(mrb_state *mrb);
void mrb_task_hal_final(mrb_state *mrb);
void mrb_task_enable_irq(void);
void mrb_task_disable_irq(void);
void mrb_task_hal_idle_cpu(mrb_state *mrb);
+96 -18
View File
@@ -477,15 +477,25 @@ mrb_f_usleep(mrb_state *mrb, mrb_value self)
#include <sys/time.h>
#include <unistd.h>
static mrb_state *global_mrb = NULL;
/* Maximum number of concurrent mrb_states with task scheduler */
#ifndef MRB_TASK_MAX_VMS
#define MRB_TASK_MAX_VMS 8
#endif
static mrb_state *vm_list[MRB_TASK_MAX_VMS];
static volatile sig_atomic_t vm_count = 0;
static sigset_t alarm_mask;
static void
sigalrm_handler(int sig)
{
int i;
(void)sig;
if (global_mrb) {
mrb_tick(global_mrb);
/* Tick all registered VMs */
for (i = 0; i < vm_count; i++) {
if (vm_list[i]) {
mrb_tick(vm_list[i]);
}
}
}
@@ -495,6 +505,7 @@ mrb_task_hal_init(mrb_state *mrb)
struct sigaction sa;
struct itimerval timer;
int i;
int vm_index = -1;
/* Initialize task state */
for (i = 0; i < 4; i++) {
@@ -504,24 +515,49 @@ mrb_task_hal_init(mrb_state *mrb)
mrb->task.wakeup_tick = UINT32_MAX;
mrb->task.switching = FALSE;
global_mrb = mrb;
/* Set up SIGALRM mask for interrupt control */
/* Block SIGALRM during registration to avoid race */
sigemptyset(&alarm_mask);
sigaddset(&alarm_mask, SIGALRM);
sigprocmask(SIG_BLOCK, &alarm_mask, NULL);
/* Set up signal handler */
sa.sa_handler = sigalrm_handler;
sa.sa_flags = SA_RESTART; /* Restart interrupted syscalls */
sigemptyset(&sa.sa_mask);
sigaction(SIGALRM, &sa, NULL);
/* Check if this VM is already registered */
for (i = 0; i < vm_count; i++) {
if (vm_list[i] == mrb) {
vm_index = i;
break;
}
}
/* Set up periodic timer (MRB_TICK_UNIT ms) */
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = MRB_TICK_UNIT * 1000;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = MRB_TICK_UNIT * 1000;
setitimer(ITIMER_REAL, &timer, NULL);
/* Register new VM if not already present */
if (vm_index < 0) {
if (vm_count >= MRB_TASK_MAX_VMS) {
sigprocmask(SIG_UNBLOCK, &alarm_mask, NULL);
mrb_raisef(mrb, E_RUNTIME_ERROR,
"too many mrb_states with task scheduler (max: %d)",
MRB_TASK_MAX_VMS);
}
vm_list[vm_count] = mrb;
vm_count++;
}
/* Set up signal handler and timer only for first VM */
if (vm_count == 1) {
/* Set up signal handler */
sa.sa_handler = sigalrm_handler;
sa.sa_flags = SA_RESTART; /* Restart interrupted syscalls */
sigemptyset(&sa.sa_mask);
sigaction(SIGALRM, &sa, NULL);
/* Set up periodic timer (MRB_TICK_UNIT ms) */
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = MRB_TICK_UNIT * 1000;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = MRB_TICK_UNIT * 1000;
setitimer(ITIMER_REAL, &timer, NULL);
}
/* Unblock SIGALRM */
sigprocmask(SIG_UNBLOCK, &alarm_mask, NULL);
}
void
@@ -544,6 +580,41 @@ mrb_task_hal_idle_cpu(mrb_state *mrb)
usleep(MRB_TICK_UNIT * 1000);
}
void
mrb_task_hal_final(mrb_state *mrb)
{
struct itimerval timer;
int i, j;
/* Block SIGALRM during unregistration */
sigprocmask(SIG_BLOCK, &alarm_mask, NULL);
/* Find and remove this VM from the list */
for (i = 0; i < vm_count; i++) {
if (vm_list[i] == mrb) {
/* Shift remaining VMs down */
for (j = i; j < vm_count - 1; j++) {
vm_list[j] = vm_list[j + 1];
}
vm_list[vm_count - 1] = NULL;
vm_count--;
break;
}
}
/* Stop the timer if this was the last VM */
if (vm_count == 0) {
timer.it_value.tv_sec = 0;
timer.it_value.tv_usec = 0;
timer.it_interval.tv_sec = 0;
timer.it_interval.tv_usec = 0;
setitimer(ITIMER_REAL, &timer, NULL);
}
/* Unblock SIGALRM */
sigprocmask(SIG_UNBLOCK, &alarm_mask, NULL);
}
#else
/* Stub implementation for non-POSIX platforms */
@@ -581,6 +652,13 @@ mrb_task_hal_idle_cpu(mrb_state *mrb)
(void)mrb;
/* TODO: Platform-specific idle/sleep */
}
void
mrb_task_hal_final(mrb_state *mrb)
{
(void)mrb;
/* TODO: Platform-specific cleanup */
}
#endif
/*
@@ -1037,7 +1115,7 @@ mrb_mruby_task_gem_init(mrb_state *mrb)
void
mrb_mruby_task_gem_final(mrb_state *mrb)
{
/* Cleanup if needed */
mrb_task_hal_final(mrb);
}
#else