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