1use alloc::{string::String, sync::Arc};
4
5use kernel_guard::NoPreemptIrqSave;
6
7pub(crate) use crate::run_queue::{current_run_queue, select_run_queue};
8
9#[doc(cfg(feature = "multitask"))]
10pub use crate::task::{CurrentTask, TaskId, TaskInner};
11#[doc(cfg(feature = "multitask"))]
12pub use crate::task_ext::{TaskExtMut, TaskExtRef};
13#[doc(cfg(feature = "multitask"))]
14pub use crate::wait_queue::WaitQueue;
15
16pub type AxTaskRef = Arc<AxTask>;
18
19pub type AxCpuMask = cpumask::CpuMask<{ axconfig::plat::MAX_CPU_NUM }>;
21
22cfg_if::cfg_if! {
23 if #[cfg(feature = "sched-rr")] {
24 const MAX_TIME_SLICE: usize = 5;
25 pub(crate) type AxTask = axsched::RRTask<TaskInner, MAX_TIME_SLICE>;
26 pub(crate) type Scheduler = axsched::RRScheduler<TaskInner, MAX_TIME_SLICE>;
27 } else if #[cfg(feature = "sched-cfs")] {
28 pub(crate) type AxTask = axsched::CFSTask<TaskInner>;
29 pub(crate) type Scheduler = axsched::CFScheduler<TaskInner>;
30 } else {
31 pub(crate) type AxTask = axsched::FifoTask<TaskInner>;
33 pub(crate) type Scheduler = axsched::FifoScheduler<TaskInner>;
34 }
35}
36
37#[cfg(feature = "preempt")]
38struct KernelGuardIfImpl;
39
40#[cfg(feature = "preempt")]
41#[crate_interface::impl_interface]
42impl kernel_guard::KernelGuardIf for KernelGuardIfImpl {
43 fn disable_preempt() {
44 if let Some(curr) = current_may_uninit() {
45 curr.disable_preempt();
46 }
47 }
48
49 fn enable_preempt() {
50 if let Some(curr) = current_may_uninit() {
51 curr.enable_preempt(true);
52 }
53 }
54}
55
56pub fn current_may_uninit() -> Option<CurrentTask> {
59 CurrentTask::try_get()
60}
61
62pub fn current() -> CurrentTask {
68 CurrentTask::get()
69}
70
71pub fn init_scheduler() {
73 info!("Initialize scheduling...");
74
75 init_cpu_mask_full();
77
78 crate::run_queue::init();
80 #[cfg(feature = "irq")]
81 crate::timers::init();
82
83 info!(" use {} scheduler.", Scheduler::scheduler_name());
84}
85
86static CPU_MASK_FULL: lazyinit::LazyInit<AxCpuMask> = lazyinit::LazyInit::new();
88
89fn init_cpu_mask_full() {
91 let cpu_num = axhal::cpu_num();
92 let mut cpumask = AxCpuMask::new();
93 for cpu_id in 0..cpu_num {
94 cpumask.set(cpu_id, true);
95 }
96
97 CPU_MASK_FULL.call_once(|| cpumask);
98}
99
100pub(crate) fn cpu_mask_full() -> AxCpuMask {
101 CPU_MASK_FULL
102 .get()
103 .expect("CPU mask not initialized")
104 .clone()
105}
106
107pub fn init_scheduler_secondary() {
109 crate::run_queue::init_secondary();
110 #[cfg(feature = "irq")]
111 crate::timers::init();
112}
113
114#[cfg(feature = "irq")]
118#[doc(cfg(feature = "irq"))]
119pub fn on_timer_tick() {
120 use kernel_guard::NoOp;
121 crate::timers::check_events();
122 current_run_queue::<NoOp>().scheduler_timer_tick();
125}
126
127pub fn spawn_task(task: TaskInner) -> AxTaskRef {
129 let task_ref = task.into_arc();
130 select_run_queue::<NoPreemptIrqSave>(&task_ref).add_task(task_ref.clone());
131 task_ref
132}
133
134pub fn spawn_raw<F>(f: F, name: String, stack_size: usize) -> AxTaskRef
138where
139 F: FnOnce() + Send + 'static,
140{
141 spawn_task(TaskInner::new(f, name, stack_size))
142}
143
144pub fn spawn<F>(f: F) -> AxTaskRef
151where
152 F: FnOnce() + Send + 'static,
153{
154 spawn_raw(f, "".into(), axconfig::TASK_STACK_SIZE)
155}
156
157pub fn set_priority(prio: isize) -> bool {
167 current_run_queue::<NoPreemptIrqSave>().set_current_priority(prio)
168}
169
170pub fn set_current_affinity(cpumask: AxCpuMask) -> bool {
176 if cpumask.is_empty() {
177 false
178 } else {
179 let curr = current().clone();
180
181 curr.set_cpumask(cpumask);
182 #[cfg(feature = "smp")]
185 if !cpumask.get(axhal::percpu::this_cpu_id()) {
186 const MIGRATION_TASK_STACK_SIZE: usize = 4096;
187 let migration_task = TaskInner::new(
189 move || crate::run_queue::migrate_entry(curr),
190 "migration-task".into(),
191 MIGRATION_TASK_STACK_SIZE,
192 )
193 .into_arc();
194
195 current_run_queue::<NoPreemptIrqSave>().migrate_current(migration_task);
197
198 assert!(
199 cpumask.get(axhal::percpu::this_cpu_id()),
200 "Migration failed"
201 );
202 }
203 true
204 }
205}
206
207pub fn yield_now() {
210 current_run_queue::<NoPreemptIrqSave>().yield_current()
211}
212
213pub fn sleep(dur: core::time::Duration) {
217 sleep_until(axhal::time::wall_time() + dur);
218}
219
220pub fn sleep_until(deadline: axhal::time::TimeValue) {
224 #[cfg(feature = "irq")]
225 current_run_queue::<NoPreemptIrqSave>().sleep_until(deadline);
226 #[cfg(not(feature = "irq"))]
227 axhal::time::busy_wait_until(deadline);
228}
229
230pub fn exit(exit_code: i32) -> ! {
232 current_run_queue::<NoPreemptIrqSave>().exit_current(exit_code)
233}
234
235pub fn run_idle() -> ! {
239 loop {
240 yield_now();
241 debug!("idle task: waiting for IRQs...");
242 #[cfg(feature = "irq")]
243 axhal::asm::wait_for_irqs();
244 }
245}