///|
/// Scheduler - Task scheduling and dependency management
/// ブラウザの Event Loop / Task Scheduler に相当
// =============================================================================
// Blocked Sources Tracking
// =============================================================================
///|
/// ブロック中のソースを追跡
struct BlockedSources {
sources : @hashset.HashSet[TaskSource]
}
///|
fn BlockedSources::new() -> BlockedSources {
{ sources: @hashset.HashSet([]) }
}
///|
fn BlockedSources::block(self : BlockedSources, source : TaskSource) -> Unit {
self.sources.add(source)
}
///|
fn BlockedSources::unblock(self : BlockedSources, source : TaskSource) -> Unit {
self.sources.remove(source)
}
///|
fn BlockedSources::is_blocked(
self : BlockedSources,
source : TaskSource,
) -> Bool {
self.sources.contains(source)
}
// =============================================================================
// Scheduler
// =============================================================================
///|
/// スケジューラ本体
pub struct Scheduler {
/// 全タスクのマップ(高速検索用)
tasks : Map[Int, Task]
/// 実行可能なタスクキュー
ready_queue : TaskQueue
/// ソース別キュー管理
source_queues : SourceQueueManager
/// ブロック中のソース
blocked : BlockedSources
/// 完了したタスクのID(依存解決用)
completed_ids : @hashset.HashSet[Int]
}
///|
pub fn Scheduler::new() -> Scheduler {
{
tasks: {},
ready_queue: TaskQueue::new(),
source_queues: SourceQueueManager::new(),
blocked: BlockedSources::new(),
completed_ids: @hashset.HashSet([]),
}
}
// =============================================================================
// Task Enqueueing
// =============================================================================
///|
/// タスクを追加
pub fn Scheduler::enqueue(
self : Scheduler,
action : TaskAction,
constraint : TaskConstraint,
) -> TaskId {
let task = Task::new(action, constraint)
self.add_task(task)
}
///|
/// 依存関係付きでタスクを追加
pub fn Scheduler::enqueue_after(
self : Scheduler,
action : TaskAction,
constraint : TaskConstraint,
dependencies : Array[TaskId],
) -> TaskId {
let task = Task::new(action, constraint, dependencies~)
self.add_task(task)
}
///|
/// 優先度付きでタスクを追加
pub fn Scheduler::enqueue_with_priority(
self : Scheduler,
action : TaskAction,
constraint : TaskConstraint,
priority : Int,
) -> TaskId {
let task = Task::new(action, constraint, priority~)
self.add_task(task)
}
///|
/// 内部: タスクを追加して管理構造に登録
fn Scheduler::add_task(self : Scheduler, task : Task) -> TaskId {
let TaskId(id) = task.id
// タスクマップに追加
self.tasks[id] = task
// ソース別キューに追加
self.source_queues.push(task)
// 依存関係をチェックして Ready なら ready_queue にも追加
if task.is_ready() {
self.ready_queue.push(task)
}
task.id
}
// =============================================================================
// Dependency Resolution
// =============================================================================
///|
/// 依存関係を解決して Ready 状態に昇格
pub fn Scheduler::resolve_dependencies(self : Scheduler) -> Int {
let mut promoted = 0
// 全タスクをチェック
self.tasks.each(fn(_id, task) {
// Pending 状態のタスクのみ処理
match task.state {
Pending => {
// 全ての依存タスクが完了しているかチェック
let mut all_deps_completed = true
for dep_id in task.dependencies {
let TaskId(dep_int) = dep_id
if !self.completed_ids.contains(dep_int) {
all_deps_completed = false
break
}
}
if all_deps_completed {
// Ready に昇格
task.state = Ready
self.ready_queue.push(task)
promoted += 1
}
}
_ => ()
}
})
promoted
}
// =============================================================================
// Task Polling (外部ランタイムが呼ぶ)
// =============================================================================
///|
/// 実行可能なタスクをすべて取得(状態を Running に変更)
pub fn Scheduler::poll_ready(self : Scheduler) -> Array[Task] {
let ready = self.ready_queue.get_ready()
// ブロックされているソースのタスクを除外
let unblocked : Array[Task] = ready.filter(fn(task) {
!self.blocked.is_blocked(task.source)
})
// 優先度でソート(高い順)
unblocked.sort_by(fn(a, b) { b.priority - a.priority })
// 状態を Running に変更
for task in unblocked {
task.mark_running()
}
unblocked
}
///|
/// 並列実行可能なタスクのみ取得
pub fn Scheduler::poll_parallel(self : Scheduler) -> Array[Task] {
let parallel = self.ready_queue.get_parallel_ready()
// ブロックされているソースのタスクを除外
let unblocked : Array[Task] = parallel.filter(fn(task) {
!self.blocked.is_blocked(task.source)
})
// 優先度でソート(高い順)
unblocked.sort_by(fn(a, b) { b.priority - a.priority })
// 状態を Running に変更
for task in unblocked {
task.mark_running()
}
unblocked
}
///|
/// メインスレッド専用タスクのみ取得(1つずつ)
pub fn Scheduler::poll_main_thread(self : Scheduler) -> Task? {
let main_tasks = self.ready_queue.get_main_thread_ready()
// ブロックされているソースのタスクを除外して、最初の1つを返す
for task in main_tasks {
if !self.blocked.is_blocked(task.source) {
task.mark_running()
return Some(task)
}
}
None
}
// =============================================================================
// Task Completion
// =============================================================================
///|
/// タスク完了を通知(成功)
pub fn Scheduler::complete(
self : Scheduler,
task_id : TaskId,
result : TaskResult,
) -> Array[TaskId] {
let TaskId(id) = task_id
match self.tasks.get(id) {
Some(task) =>
match result {
Success(new_tasks~) => {
task.mark_completed()
self.completed_ids.add(id)
// Blocking 制約を解除
self.release_blocks(task)
// 新しいタスクを追加
let new_ids : Array[TaskId] = []
for action in new_tasks {
let new_id = self.enqueue(action, MainThreadOnly)
new_ids.push(new_id)
}
// 依存関係を解決
let _ = self.resolve_dependencies()
new_ids
}
Failure(error~) => {
task.mark_failed(error)
self.release_blocks(task)
[]
}
Cancelled => {
task.mark_cancelled()
self.release_blocks(task)
[]
}
}
None => []
}
}
///|
/// タスク失敗を通知(ショートカット)
pub fn Scheduler::fail(
self : Scheduler,
task_id : TaskId,
error : String,
) -> Unit {
let _ = self.complete(task_id, Failure(error~))
}
///|
/// タスクキャンセルを通知(ショートカット)
pub fn Scheduler::cancel(self : Scheduler, task_id : TaskId) -> Unit {
let _ = self.complete(task_id, Cancelled)
}
///|
/// Blocking 制約を解除
fn Scheduler::release_blocks(self : Scheduler, task : Task) -> Unit {
match task.constraint {
Blocking(sources) =>
for source in sources {
self.blocked.unblock(source)
}
_ => ()
}
}
// =============================================================================
// Blocking Management
// =============================================================================
///|
/// タスクの Blocking 制約を適用
pub fn Scheduler::apply_blocks(self : Scheduler, task : Task) -> Unit {
match task.constraint {
Blocking(sources) =>
for source in sources {
self.blocked.block(source)
}
_ => ()
}
}
///|
/// 特定のソースがブロックされているか確認
pub fn Scheduler::is_source_blocked(
self : Scheduler,
source : TaskSource,
) -> Bool {
self.blocked.is_blocked(source)
}
// =============================================================================
// Status and Queries
// =============================================================================
///|
/// 全タスク数を取得
pub fn Scheduler::task_count(self : Scheduler) -> Int {
self.tasks.length()
}
///|
/// Ready 状態のタスク数を取得
pub fn Scheduler::ready_count(self : Scheduler) -> Int {
self.ready_queue.get_ready().length()
}
///|
/// Pending 状態のタスク数を取得
pub fn Scheduler::pending_count(self : Scheduler) -> Int {
let mut count = 0
self.tasks.each(fn(_id, task) {
match task.state {
Pending => count += 1
_ => ()
}
})
count
}
///|
/// Running 状態のタスク数を取得
pub fn Scheduler::running_count(self : Scheduler) -> Int {
let mut count = 0
self.tasks.each(fn(_id, task) {
match task.state {
Running => count += 1
_ => ()
}
})
count
}
///|
/// タスクを検索
pub fn Scheduler::find_task(self : Scheduler, task_id : TaskId) -> Task? {
let TaskId(id) = task_id
self.tasks.get(id)
}
///|
/// すべての処理が完了したか確認
pub fn Scheduler::is_idle(self : Scheduler) -> Bool {
self.pending_count() == 0 &&
self.running_count() == 0 &&
self.ready_count() == 0
}
///|
/// 完了したタスクをクリーンアップ
pub fn Scheduler::cleanup(self : Scheduler) -> Int {
let mut removed = 0
// 終了状態のタスクを削除
let to_remove : Array[Int] = []
self.tasks.each(fn(id, task) { if task.is_terminal() { to_remove.push(id) } })
for id in to_remove {
self.tasks.remove(id)
removed += 1
}
// キューもクリーンアップ
let _ = self.ready_queue.cleanup()
let _ = self.source_queues.cleanup()
removed
}