mruby-task: add initial gem structure with api skeleton

create mruby-task gem directory structure with:
- mrbgem.rake: gem specification with task scheduler define
- include/task.h: tcb structure and core scheduler declarations
- src/task.c: implementation skeleton with empty method stubs
- mrblib/task.rb: ruby api documentation and task::stat class

all methods have empty bodies ready for implementation.

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Yukihiro "Matz" Matsumoto
2025-10-04 12:27:40 +09:00
parent 00667c5e09
commit ae0d7a0c16
4 changed files with 556 additions and 0 deletions
+111
View File
@@ -0,0 +1,111 @@
/*
** task.h - Task scheduler
**
** See Copyright Notice in mruby.h
*/
#ifndef MRUBY_TASK_H
#define MRUBY_TASK_H
#include <mruby.h>
#ifdef MRB_USE_TASK_SCHEDULER
/*
* Task status values (bit-mapped)
*/
enum {
MRB_TASKSTATUS_DORMANT = 0x00, /* Not started or finished */
MRB_TASKSTATUS_READY = 0x02, /* Ready to run */
MRB_TASKSTATUS_RUNNING = 0x03, /* Currently executing */
MRB_TASKSTATUS_WAITING = 0x04, /* Waiting for condition */
MRB_TASKSTATUS_SUSPENDED = 0x08, /* Manually suspended */
};
/*
* Task wait reason
*/
enum {
MRB_TASKREASON_NONE = 0x00, /* No specific reason */
MRB_TASKREASON_SLEEP = 0x01, /* Sleeping for time */
MRB_TASKREASON_MUTEX = 0x02, /* Waiting for mutex (reserved) */
MRB_TASKREASON_JOIN = 0x04, /* Waiting for another task */
};
/*
* Task Control Block (TCB)
*/
typedef struct mrb_tcb {
struct mrb_tcb *next; /* Linked list pointer */
uint8_t priority; /* Initial priority (0-255, 0=highest) */
uint8_t priority_preemption; /* Effective priority for preemption */
volatile uint8_t timeslice; /* Remaining time slice ticks */
uint8_t status; /* Current status (TASKSTATUS enum) */
uint8_t reason; /* Wait reason (TASKREASON enum) */
mrb_value name; /* Optional task name */
union {
uint32_t wakeup_tick; /* Tick count to wake up (for sleep) */
void *mutex; /* Mutex pointer (reserved) */
};
const struct mrb_tcb *tcb_join; /* Task being waited on (for join) */
mrb_value task; /* Ruby Task object reference */
mrb_value value; /* Task return value */
struct mrb_context c; /* Execution context (stack, callinfo, etc) */
} mrb_tcb;
/*
* Task scheduler state (part of mrb_state)
*/
#define MRB_NUM_TASK_QUEUE 4
typedef struct mrb_task_state {
mrb_tcb *queues[MRB_NUM_TASK_QUEUE]; /* Task queues */
volatile uint32_t tick; /* Current tick count */
volatile uint32_t wakeup_tick; /* Next wakeup tick */
volatile mrb_bool switching; /* Context switch pending flag */
} mrb_task_state;
/* Queue indices */
#define MRB_TASK_QUEUE_DORMANT 0
#define MRB_TASK_QUEUE_READY 1
#define MRB_TASK_QUEUE_WAITING 2
#define MRB_TASK_QUEUE_SUSPENDED 3
/* Configuration */
#ifndef MRB_TICK_UNIT
#define MRB_TICK_UNIT 4 /* Tick period in milliseconds */
#endif
#ifndef MRB_TIMESLICE_TICK_COUNT
#define MRB_TIMESLICE_TICK_COUNT 3 /* Number of ticks per timeslice */
#endif
#define TASK_STACK_INIT_SIZE 64 /* Initial task stack size */
#define TASK_CI_INIT_SIZE 8 /* Initial task callinfo size */
/*
* HAL (Hardware Abstraction Layer) functions
* Platform-specific implementations must provide these
*/
void mrb_task_hal_init(mrb_state *mrb);
void mrb_task_enable_irq(void);
void mrb_task_disable_irq(void);
void mrb_task_hal_idle_cpu(mrb_state *mrb);
/*
* Core task scheduler API
*/
void mrb_tick(mrb_state *mrb);
mrb_value mrb_tasks_run(mrb_state *mrb);
/*
* Task context status values (extends mrb_fiber_state)
*/
#define MRB_TASK_CREATED (MRB_FIBER_TRANSFERRED + 1)
#define MRB_TASK_STOPPED (MRB_FIBER_TRANSFERRED + 2)
#endif /* MRB_USE_TASK_SCHEDULER */
#endif /* MRUBY_TASK_H */
+8
View File
@@ -0,0 +1,8 @@
MRuby::Gem::Specification.new('mruby-task') do |spec|
spec.license = 'MIT'
spec.authors = 'mruby developers'
spec.summary = 'Cooperative multitasking with preemptive scheduling'
spec.cc.defines << 'MRB_USE_TASK_SCHEDULER'
spec.add_dependency 'mruby-fiber' # Uses same context infrastructure
end
+115
View File
@@ -0,0 +1,115 @@
class Task
# Class methods
# Create a new task with optional name and priority
# @param name [String, Symbol, nil] optional task name
# @param priority [Integer, nil] task priority (0-255, 0 is highest)
# @yield block to execute in the task
# @return [Task] the created task
def self.new(name: nil, priority: nil, &block)
end
# Get the currently running task
# @return [Task] the current task
def self.current
end
# Get all tasks in the system
# @return [Array<Task>] array of all tasks
def self.list
end
# Yield execution to other tasks (cooperative yielding)
# @return [nil]
def self.pass
end
# Get task scheduler statistics
# @return [Task::Stat] scheduler statistics object
def self.stat
end
# Find a task by name
# @param name [String, Symbol] task name to find
# @return [Task, nil] the task if found, nil otherwise
def self.get(name)
end
# Instance methods
# Get the task status
# @return [Symbol] one of :DORMANT, :READY, :RUNNING, :WAITING, :SUSPENDED
def status
end
# Get the task name
# @return [String, Symbol, nil] the task name
def name
end
# Set the task name
# @param val [String, Symbol] new task name
def name=(val)
end
# Get the task priority
# @return [Integer] priority value (0-255, 0 is highest)
def priority
end
# Set the task priority
# @param val [Integer] new priority (0-255, 0 is highest)
def priority=(val)
end
# Suspend the task
# @return [self]
def suspend
end
# Resume a suspended task
# @return [self]
def resume
end
# Terminate the task
# @return [self]
def terminate
end
# Wait for the task to complete
# @return [self]
def join
end
# Task scheduler statistics class
class Stat
attr_reader :tick, :wakeup_tick, :tasks
def initialize(tick, wakeup_tick, tasks)
@tick = tick
@wakeup_tick = wakeup_tick
@tasks = tasks
end
def to_s
"tick: #{@tick}, wakeup_tick: #{@wakeup_tick}, tasks: #{@tasks.size}"
end
end
end
# Kernel methods for sleeping
module Kernel
# Sleep for specified duration
# @param sec [Integer, Float, nil] seconds to sleep (nil = suspend indefinitely)
# @return [Integer, nil] actual sleep time
def sleep(sec = nil)
end
# Sleep for specified milliseconds
# @param ms [Integer] milliseconds to sleep
# @return [nil]
def sleep_ms(ms)
end
end
+322
View File
@@ -0,0 +1,322 @@
/*
** task.c - Task scheduler
**
** See Copyright Notice in mruby.h
*/
#include <mruby.h>
#ifdef MRB_USE_TASK_SCHEDULER
#include <mruby/array.h>
#include <mruby/class.h>
#include <mruby/data.h>
#include <mruby/error.h>
#include <mruby/proc.h>
#include <mruby/string.h>
#include <mruby/variable.h>
#include "../include/task.h"
/*
* Queue helper macros
*/
#define q_dormant_ (mrb->task.queues[MRB_TASK_QUEUE_DORMANT])
#define q_ready_ (mrb->task.queues[MRB_TASK_QUEUE_READY])
#define q_waiting_ (mrb->task.queues[MRB_TASK_QUEUE_WAITING])
#define q_suspended_ (mrb->task.queues[MRB_TASK_QUEUE_SUSPENDED])
#define tick_ (mrb->task.tick)
#define wakeup_tick_ (mrb->task.wakeup_tick)
#define switching_ (mrb->task.switching)
/*
* Task data type for GC
*/
static void
mrb_task_free(mrb_state *mrb, void *ptr)
{
/* TODO: Free TCB and associated resources */
}
static const struct mrb_data_type mrb_task_type = {
"Task", mrb_task_free,
};
/*
* Queue operations
*/
/* Insert task into appropriate queue based on priority */
static void
q_insert_task(mrb_state *mrb, mrb_tcb *tcb)
{
/* TODO: Implement priority-based insertion */
}
/* Delete task from its current queue */
static void
q_delete_task(mrb_state *mrb, mrb_tcb *tcb)
{
/* TODO: Implement queue deletion */
}
/* Find task in queues */
static mrb_tcb*
q_find_task(mrb_state *mrb, mrb_tcb *tcb)
{
/* TODO: Implement task search */
return NULL;
}
/*
* TCB lifecycle
*/
/* Allocate new TCB */
static mrb_tcb*
mrb_tcb_new(mrb_state *mrb)
{
/* TODO: Allocate and initialize TCB */
return NULL;
}
/* Free TCB and context */
static void
mrb_tcb_free(mrb_state *mrb, mrb_tcb *tcb)
{
/* TODO: Free TCB and associated context */
}
/* Initialize task context (stack and callinfo) */
static void
mrb_task_init_context(mrb_state *mrb, mrb_value task, struct RProc *proc)
{
/* TODO: Allocate and initialize context similar to Fiber */
}
/*
* Scheduler core
*/
/* Tick handler - called by timer interrupt */
void
mrb_tick(mrb_state *mrb)
{
/* TODO: Implement tick handler
* - Increment tick counter
* - Decrease current task timeslice
* - Wake up sleeping tasks
* - Set switching flag if needed
*/
}
/* Main scheduler loop */
mrb_value
mrb_tasks_run(mrb_state *mrb)
{
/* TODO: Implement main scheduler loop
* - Get next ready task
* - Switch context
* - Execute via mrb_vm_exec()
* - Handle completion/switching
* - Run incremental GC
*/
return mrb_nil_value();
}
/*
* Sleep operations
*/
static void
sleep_ms_impl(mrb_state *mrb, mrb_int ms)
{
/* TODO: Implement sleep
* - Move current task to waiting queue
* - Set wakeup tick
* - Trigger context switch
*/
}
static mrb_value
mrb_f_sleep(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Kernel#sleep */
return mrb_nil_value();
}
static mrb_value
mrb_f_sleep_ms(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Kernel#sleep_ms */
return mrb_nil_value();
}
/*
* Task class methods
*/
static mrb_value
mrb_task_s_new(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Task.new */
return mrb_nil_value();
}
static mrb_value
mrb_task_s_current(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Task.current */
return mrb_nil_value();
}
static mrb_value
mrb_task_s_list(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Task.list */
return mrb_ary_new(mrb);
}
static mrb_value
mrb_task_s_pass(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Task.pass */
return mrb_nil_value();
}
static mrb_value
mrb_task_s_stat(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Task.stat */
return mrb_nil_value();
}
static mrb_value
mrb_task_s_get(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Task.get */
return mrb_nil_value();
}
/*
* Task instance methods
*/
static mrb_value
mrb_task_status(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Task#status */
return mrb_nil_value();
}
static mrb_value
mrb_task_name(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Task#name */
return mrb_nil_value();
}
static mrb_value
mrb_task_set_name(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Task#name= */
return mrb_nil_value();
}
static mrb_value
mrb_task_priority(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Task#priority */
return mrb_nil_value();
}
static mrb_value
mrb_task_set_priority(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Task#priority= */
return mrb_nil_value();
}
static mrb_value
mrb_task_suspend(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Task#suspend */
return self;
}
static mrb_value
mrb_task_resume(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Task#resume */
return self;
}
static mrb_value
mrb_task_terminate(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Task#terminate */
return self;
}
static mrb_value
mrb_task_join(mrb_state *mrb, mrb_value self)
{
/* TODO: Implement Task#join */
return self;
}
/*
* Initialization
*/
void
mrb_mruby_task_gem_init(mrb_state *mrb)
{
struct RClass *task_class;
task_class = mrb_define_class(mrb, "Task", mrb->object_class);
MRB_SET_INSTANCE_TT(task_class, MRB_TT_DATA);
/* Class methods */
mrb_define_class_method(mrb, task_class, "new", mrb_task_s_new, MRB_ARGS_BLOCK());
mrb_define_class_method(mrb, task_class, "current", mrb_task_s_current, MRB_ARGS_NONE());
mrb_define_class_method(mrb, task_class, "list", mrb_task_s_list, MRB_ARGS_NONE());
mrb_define_class_method(mrb, task_class, "pass", mrb_task_s_pass, MRB_ARGS_NONE());
mrb_define_class_method(mrb, task_class, "stat", mrb_task_s_stat, MRB_ARGS_NONE());
mrb_define_class_method(mrb, task_class, "get", mrb_task_s_get, MRB_ARGS_REQ(1));
/* Instance methods */
mrb_define_method(mrb, task_class, "status", mrb_task_status, MRB_ARGS_NONE());
mrb_define_method(mrb, task_class, "name", mrb_task_name, MRB_ARGS_NONE());
mrb_define_method(mrb, task_class, "name=", mrb_task_set_name, MRB_ARGS_REQ(1));
mrb_define_method(mrb, task_class, "priority", mrb_task_priority, MRB_ARGS_NONE());
mrb_define_method(mrb, task_class, "priority=", mrb_task_set_priority, MRB_ARGS_REQ(1));
mrb_define_method(mrb, task_class, "suspend", mrb_task_suspend, MRB_ARGS_NONE());
mrb_define_method(mrb, task_class, "resume", mrb_task_resume, MRB_ARGS_NONE());
mrb_define_method(mrb, task_class, "terminate", mrb_task_terminate, MRB_ARGS_NONE());
mrb_define_method(mrb, task_class, "join", mrb_task_join, MRB_ARGS_NONE());
/* Kernel methods */
mrb_define_method(mrb, mrb->kernel_module, "sleep", mrb_f_sleep, MRB_ARGS_OPT(1));
mrb_define_method(mrb, mrb->kernel_module, "sleep_ms", mrb_f_sleep_ms, MRB_ARGS_REQ(1));
}
void
mrb_mruby_task_gem_final(mrb_state *mrb)
{
/* Cleanup if needed */
}
#else
/* Task scheduler not enabled - provide stub */
void
mrb_mruby_task_gem_init(mrb_state *mrb)
{
}
void
mrb_mruby_task_gem_final(mrb_state *mrb)
{
}
#endif /* MRB_USE_TASK_SCHEDULER */