veridian_kernel/sched/runtime.rs
1//! Scheduler runtime loop and idle task management
2//!
3//! Contains the main scheduler execution loop (`run`), the idle task entry
4//! point, timer tick handling, and scheduler start/query functions.
5
6use super::scheduler;
7
8/// Start the scheduler
9///
10/// This transfers control to the scheduler, which will run the current task
11/// (bootstrap or idle) and never return.
12pub fn start() -> ! {
13 kprintln!("[SCHED] Starting scheduler execution");
14
15 #[cfg(target_arch = "aarch64")]
16 {
17 // Enter idle loop
18 loop {
19 // SAFETY: WFI (Wait For Interrupt) is a hint instruction that
20 // puts the CPU into a low-power state until an interrupt arrives.
21 // It does not modify any memory or registers beyond the PC. The
22 // nomem/nostack/preserves_flags options correctly reflect this.
23 unsafe {
24 core::arch::asm!("wfi", options(nomem, nostack, preserves_flags));
25 }
26 }
27 }
28
29 #[cfg(target_arch = "riscv64")]
30 {
31 // Enter idle loop
32 loop {
33 // SAFETY: WFI (Wait For Interrupt) is a hint instruction on RISC-V
34 // that suspends execution until an interrupt occurs. It does not
35 // modify memory or registers. The options correctly reflect this.
36 unsafe {
37 core::arch::asm!("wfi", options(nomem, nostack, preserves_flags));
38 }
39 }
40 }
41
42 // x86_64: Enter HLT idle loop (matches AArch64 WFI and RISC-V WFI)
43 #[cfg(target_arch = "x86_64")]
44 {
45 println!("[SCHED] Entering idle loop");
46 loop {
47 crate::arch::idle();
48 }
49 }
50}
51
52/// Check if there are ready tasks
53pub fn has_ready_tasks() -> bool {
54 #[cfg(not(target_arch = "riscv64"))]
55 {
56 super::READY_QUEUE.lock().has_ready_tasks()
57 }
58 #[cfg(target_arch = "riscv64")]
59 {
60 super::queue::get_ready_queue().has_ready_tasks()
61 }
62}
63
64/// Run scheduler main loop (called by idle task)
65pub fn run() -> ! {
66 kprintln!("[SCHED] Entering scheduler main loop");
67
68 let mut balance_counter = 0u64;
69
70 loop {
71 // Check for ready tasks
72 #[cfg(not(target_arch = "riscv64"))]
73 {
74 if super::READY_QUEUE.lock().has_ready_tasks() {
75 super::SCHEDULER.lock().schedule();
76 }
77 }
78 #[cfg(target_arch = "riscv64")]
79 {
80 if super::queue::get_ready_queue().has_ready_tasks() {
81 super::SCHEDULER.lock().schedule();
82 }
83 }
84
85 // Periodically perform load balancing and cleanup
86 balance_counter = balance_counter.wrapping_add(1);
87 if balance_counter.is_multiple_of(1000) {
88 #[cfg(feature = "alloc")]
89 {
90 super::load_balance::balance_load();
91
92 // Also clean up dead tasks
93 if balance_counter.is_multiple_of(10000) {
94 super::load_balance::cleanup_dead_tasks();
95 }
96 }
97 }
98
99 // Enter low power state
100 crate::arch::idle();
101 }
102}
103
104/// Idle task entry point
105pub extern "C" fn idle_task_entry() -> ! {
106 run()
107}
108
109/// Handle timer tick
110pub fn timer_tick() {
111 scheduler::current_scheduler().lock().tick();
112}
113
114/// Set scheduling algorithm
115pub fn set_algorithm(algorithm: super::SchedAlgorithm) {
116 super::SCHEDULER.lock().algorithm = algorithm;
117}