diff --git a/mrbgems/mruby-task/include/task.h b/mrbgems/mruby-task/include/task.h index 9fd36b842..082bb2319 100644 --- a/mrbgems/mruby-task/include/task.h +++ b/mrbgems/mruby-task/include/task.h @@ -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); diff --git a/mrbgems/mruby-task/src/task.c b/mrbgems/mruby-task/src/task.c index 28c7bcb6e..5fbfc2cf0 100644 --- a/mrbgems/mruby-task/src/task.c +++ b/mrbgems/mruby-task/src/task.c @@ -477,15 +477,25 @@ mrb_f_usleep(mrb_state *mrb, mrb_value self) #include #include -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