Introduce Task::Queue

- This patch implements `Task::Queue` mirroring `Thread::Queue` in CRuby.
- Producer/Consumer pattern is now possible with no polling

## No Top-level pollution
- No top-level `Queue` defined
- No `TaskError`. Instead, `Task::Error` happens when `Task::Queue#pop(true)` when empty
- No `ClosedQueueError`. `Task::Error` also happens when pushing to closed queue

## Future Work
- `Task::SizedQueue`
This commit is contained in:
HASUMI Hitoshi
2026-05-18 11:54:20 +09:00
parent 831da26b90
commit 458078f10e
7 changed files with 708 additions and 28 deletions
+38
View File
@@ -28,8 +28,11 @@ enum {
MRB_TASK_REASON_SLEEP = 0x01, /* Sleeping for time */
MRB_TASK_REASON_MUTEX = 0x02, /* Waiting for mutex (reserved) */
MRB_TASK_REASON_JOIN = 0x04, /* Waiting for another task */
MRB_TASK_REASON_QUEUE = 0x08, /* Waiting for queue item */
};
struct mrb_task_queue;
/*
* Task structure - represents a single task in the scheduler
*
@@ -53,6 +56,7 @@ typedef struct mrb_task {
uint32_t wakeup_tick; /* Tick count to wake up (REASON_SLEEP) */
const struct mrb_task *join; /* Task being waited on (REASON_JOIN) */
void *mutex; /* Mutex pointer (REASON_MUTEX, reserved) */
struct mrb_task_queue *queue; /* Queue being waited on (REASON_QUEUE) */
} wait;
mrb_value self; /* Ruby Task object reference */
@@ -140,4 +144,38 @@ MRB_API void mrb_task_init_context(mrb_state *mrb, mrb_value task, struct RProc
MRB_API void mrb_task_reset_context(mrb_state *mrb, mrb_value task);
MRB_API void mrb_task_proc_set(mrb_state *mrb, mrb_value task, struct RProc *proc);
/*
* Internal helpers - used by task.c and task_queue.c
*/
#include <stddef.h>
#include "task_hal.h"
/* Scheduler state accessors (require a local mrb variable in scope) */
#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)
/* Recover the mrb_task that owns the current mruby context */
#define MRB2TASK(mrb) ((mrb_task *)((uint8_t *)(mrb)->c - offsetof(mrb_task, c)))
/* Raise if the scheduler is locked (synchronous execution in progress) */
static inline void
task_check_scheduler_lock(mrb_state *mrb)
{
if (mrb->task.scheduler_lock > 0) {
mrb_raise(mrb, E_RUNTIME_ERROR, "Cannot use asynchronous Task API during synchronous execution");
}
}
/* Priority-queue insert/delete - defined in task.c */
void q_insert_task(mrb_state *mrb, mrb_task *t);
void q_delete_task(mrb_state *mrb, mrb_task *t);
/* Task::Queue class registration - defined in task_queue.c */
void mrb_init_task_queue(mrb_state *mrb, struct RClass *task_class);
#endif /* MRUBY_TASK_H */