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::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    crate::run_queue::init();
76    #[cfg(feature = "irq")]
77    crate::timers::init();
78
79    info!("  use {} scheduler.", Scheduler::scheduler_name());
80}
81
82pub fn init_scheduler_secondary() {
84    crate::run_queue::init_secondary();
85    #[cfg(feature = "irq")]
86    crate::timers::init();
87}
88
89#[cfg(feature = "irq")]
93#[doc(cfg(feature = "irq"))]
94pub fn on_timer_tick() {
95    use kernel_guard::NoOp;
96    crate::timers::check_events();
97    current_run_queue::<NoOp>().scheduler_timer_tick();
100}
101
102pub fn spawn_task(task: TaskInner) -> AxTaskRef {
104    let task_ref = task.into_arc();
105    select_run_queue::<NoPreemptIrqSave>(&task_ref).add_task(task_ref.clone());
106    task_ref
107}
108
109pub fn spawn_raw<F>(f: F, name: String, stack_size: usize) -> AxTaskRef
113where
114    F: FnOnce() + Send + 'static,
115{
116    spawn_task(TaskInner::new(f, name, stack_size))
117}
118
119pub fn spawn<F>(f: F) -> AxTaskRef
126where
127    F: FnOnce() + Send + 'static,
128{
129    spawn_raw(f, "".into(), axconfig::TASK_STACK_SIZE)
130}
131
132pub fn set_priority(prio: isize) -> bool {
142    current_run_queue::<NoPreemptIrqSave>().set_current_priority(prio)
143}
144
145pub fn set_current_affinity(cpumask: AxCpuMask) -> bool {
151    if cpumask.is_empty() {
152        false
153    } else {
154        let curr = current().clone();
155
156        curr.set_cpumask(cpumask);
157        #[cfg(feature = "smp")]
160        if !cpumask.get(axhal::percpu::this_cpu_id()) {
161            const MIGRATION_TASK_STACK_SIZE: usize = 4096;
162            let migration_task = TaskInner::new(
164                move || crate::run_queue::migrate_entry(curr),
165                "migration-task".into(),
166                MIGRATION_TASK_STACK_SIZE,
167            )
168            .into_arc();
169
170            current_run_queue::<NoPreemptIrqSave>().migrate_current(migration_task);
172
173            assert!(
174                cpumask.get(axhal::percpu::this_cpu_id()),
175                "Migration failed"
176            );
177        }
178        true
179    }
180}
181
182pub fn yield_now() {
185    current_run_queue::<NoPreemptIrqSave>().yield_current()
186}
187
188pub fn sleep(dur: core::time::Duration) {
192    sleep_until(axhal::time::wall_time() + dur);
193}
194
195pub fn sleep_until(deadline: axhal::time::TimeValue) {
199    #[cfg(feature = "irq")]
200    current_run_queue::<NoPreemptIrqSave>().sleep_until(deadline);
201    #[cfg(not(feature = "irq"))]
202    axhal::time::busy_wait_until(deadline);
203}
204
205pub fn exit(exit_code: i32) -> ! {
207    current_run_queue::<NoPreemptIrqSave>().exit_current(exit_code)
208}
209
210pub fn run_idle() -> ! {
214    loop {
215        yield_now();
216        debug!("idle task: waiting for IRQs...");
217        #[cfg(feature = "irq")]
218        axhal::asm::wait_for_irqs();
219    }
220}