mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
be6413f0d8
Move hal-posix-task and hal-win-task into mruby-task/ports/posix/ and mruby-task/ports/win/. Remove HAL auto-detection logic from mrbgem.rake. Update cosmopolitan.rb to use conf.ports :posix instead of explicit hal-* gem references. Co-authored-by: Claude <noreply@anthropic.com>
170 lines
3.6 KiB
C
170 lines
3.6 KiB
C
/*
|
|
** task_hal.c - Windows HAL implementation for mruby-task
|
|
**
|
|
** See Copyright Notice in mruby.h
|
|
**
|
|
** Windows implementation using multimedia timer (timeSetEvent/timeKillEvent)
|
|
** for periodic timer, and CRITICAL_SECTION for interrupt protection.
|
|
**
|
|
** Supported platforms: Windows (all versions with multimedia timer support)
|
|
*/
|
|
|
|
#include <mruby.h>
|
|
#include "task_hal.h"
|
|
#include <windows.h>
|
|
#include <timeapi.h>
|
|
#include <stdint.h>
|
|
|
|
/* Multi-VM support */
|
|
static mrb_state *vm_list[MRB_TASK_MAX_VMS];
|
|
static volatile LONG vm_count = 0;
|
|
static CRITICAL_SECTION irq_lock;
|
|
static MMRESULT timer_id = 0;
|
|
|
|
/* Multimedia timer callback - called periodically by Windows */
|
|
static void CALLBACK
|
|
timer_callback(UINT uID, UINT uMsg, DWORD_PTR dwUser, DWORD_PTR dw1, DWORD_PTR dw2)
|
|
{
|
|
int i;
|
|
(void)uID; (void)uMsg; (void)dwUser; (void)dw1; (void)dw2;
|
|
|
|
/* Tick all registered VMs */
|
|
EnterCriticalSection(&irq_lock);
|
|
for (i = 0; i < vm_count; i++) {
|
|
if (vm_list[i]) {
|
|
mrb_tick(vm_list[i]);
|
|
}
|
|
}
|
|
LeaveCriticalSection(&irq_lock);
|
|
}
|
|
|
|
/*
|
|
* HAL Interface Implementation
|
|
*/
|
|
|
|
void
|
|
mrb_hal_task_init(mrb_state *mrb)
|
|
{
|
|
int i;
|
|
LONG idx;
|
|
|
|
/* Initialize task state */
|
|
for (i = 0; i < 4; i++) {
|
|
mrb->task.queues[i] = NULL;
|
|
}
|
|
mrb->task.tick = 0;
|
|
mrb->task.wakeup_tick = UINT32_MAX;
|
|
mrb->task.switching = FALSE;
|
|
|
|
/* Initialize critical section on first VM */
|
|
if (vm_count == 0) {
|
|
InitializeCriticalSection(&irq_lock);
|
|
}
|
|
|
|
EnterCriticalSection(&irq_lock);
|
|
|
|
/* Check if this VM is already registered */
|
|
idx = -1;
|
|
for (i = 0; i < vm_count; i++) {
|
|
if (vm_list[i] == mrb) {
|
|
idx = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Register new VM if not already present */
|
|
if (idx < 0) {
|
|
if (vm_count >= MRB_TASK_MAX_VMS) {
|
|
LeaveCriticalSection(&irq_lock);
|
|
mrb_raisef(mrb, E_RUNTIME_ERROR,
|
|
"too many mrb_states with task scheduler (max: %d)",
|
|
MRB_TASK_MAX_VMS);
|
|
}
|
|
vm_list[vm_count] = mrb;
|
|
InterlockedIncrement(&vm_count);
|
|
}
|
|
|
|
/* Start timer for first VM */
|
|
if (vm_count == 1) {
|
|
/* Request 1ms timer resolution */
|
|
timeBeginPeriod(1);
|
|
|
|
/* Create periodic timer with MRB_TICK_UNIT interval */
|
|
timer_id = timeSetEvent(
|
|
MRB_TICK_UNIT, /* interval in milliseconds */
|
|
1, /* resolution in milliseconds */
|
|
timer_callback, /* callback function */
|
|
0, /* user data */
|
|
TIME_PERIODIC | TIME_KILL_SYNCHRONOUS
|
|
);
|
|
}
|
|
|
|
LeaveCriticalSection(&irq_lock);
|
|
}
|
|
|
|
void
|
|
mrb_task_enable_irq(void)
|
|
{
|
|
LeaveCriticalSection(&irq_lock);
|
|
}
|
|
|
|
void
|
|
mrb_task_disable_irq(void)
|
|
{
|
|
EnterCriticalSection(&irq_lock);
|
|
}
|
|
|
|
void
|
|
mrb_hal_task_idle_cpu(mrb_state *mrb)
|
|
{
|
|
(void)mrb;
|
|
/* On Windows, just sleep briefly */
|
|
Sleep(MRB_TICK_UNIT);
|
|
}
|
|
|
|
void
|
|
mrb_hal_task_sleep_us(mrb_state *mrb, mrb_int usec)
|
|
{
|
|
(void)mrb;
|
|
|
|
/* Windows Sleep() takes milliseconds, convert from microseconds */
|
|
if (usec >= 0) {
|
|
Sleep((DWORD)(usec / 1000));
|
|
}
|
|
}
|
|
|
|
void
|
|
mrb_hal_task_final(mrb_state *mrb)
|
|
{
|
|
int i, j;
|
|
|
|
EnterCriticalSection(&irq_lock);
|
|
|
|
/* 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;
|
|
InterlockedDecrement(&vm_count);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Stop timer if last VM */
|
|
if (vm_count == 0) {
|
|
if (timer_id != 0) {
|
|
timeKillEvent(timer_id);
|
|
timeEndPeriod(1);
|
|
timer_id = 0;
|
|
}
|
|
LeaveCriticalSection(&irq_lock);
|
|
DeleteCriticalSection(&irq_lock);
|
|
}
|
|
else {
|
|
LeaveCriticalSection(&irq_lock);
|
|
}
|
|
}
|