use alloc::{string::String, sync::Arc};
#[cfg(feature = "monolithic")]
use axhal::KERNEL_PROCESS_ID;
use taskctx::TaskState;
pub(crate) use crate::run_queue::{AxRunQueue, RUN_QUEUE};
use crate::schedule::get_wait_for_exit_queue;
#[doc(cfg(feature = "multitask"))]
pub use crate::task::{new_task, CurrentTask, TaskId, TaskInner};
#[doc(cfg(feature = "multitask"))]
pub use crate::wait_queue::WaitQueue;
pub type AxTaskRef = Arc<AxTask>;
cfg_if::cfg_if! {
if #[cfg(feature = "sched_rr")] {
const MAX_TIME_SLICE: usize = 5;
pub(crate) type AxTask = scheduler::RRTask<TaskInner, MAX_TIME_SLICE>;
pub(crate) type Scheduler = scheduler::RRScheduler<TaskInner, MAX_TIME_SLICE>;
} else if #[cfg(feature = "sched_cfs")] {
pub(crate) type AxTask = scheduler::CFSTask<TaskInner>;
pub(crate) type Scheduler = scheduler::CFScheduler<TaskInner>;
} else {
pub(crate) type AxTask = scheduler::FifoTask<TaskInner>;
pub(crate) type Scheduler = scheduler::FifoScheduler<TaskInner>;
}
}
pub fn current_may_uninit() -> Option<CurrentTask> {
CurrentTask::try_get()
}
pub fn current() -> CurrentTask {
CurrentTask::get()
}
pub fn init_scheduler() {
info!("Initialize scheduling...");
crate::run_queue::init();
#[cfg(feature = "irq")]
crate::timers::init();
info!(" use {} scheduler.", Scheduler::scheduler_name());
}
pub fn init_scheduler_secondary() {
crate::run_queue::init_secondary();
}
#[cfg(feature = "irq")]
#[doc(cfg(feature = "irq"))]
pub fn on_timer_tick() {
crate::timers::check_events();
RUN_QUEUE.lock().scheduler_timer_tick();
}
#[cfg(feature = "preempt")]
pub fn current_check_preempt_pending() {
let curr = crate::current();
if curr.get_preempt_pending() && curr.can_preempt(0) {
let mut rq = crate::RUN_QUEUE.lock();
if curr.get_preempt_pending() {
rq.preempt_resched();
}
}
}
pub fn spawn_raw<F>(f: F, name: String, stack_size: usize) -> AxTaskRef
where
F: FnOnce() + Send + 'static,
{
let task = new_task(
f,
name,
stack_size,
#[cfg(feature = "monolithic")]
KERNEL_PROCESS_ID,
#[cfg(feature = "monolithic")]
0,
#[cfg(feature = "monolithic")]
false,
);
RUN_QUEUE.lock().add_task(task.clone());
task
}
pub fn spawn<F>(f: F) -> AxTaskRef
where
F: FnOnce() + Send + 'static,
{
spawn_raw(f, "".into(), axconfig::TASK_STACK_SIZE)
}
pub fn set_priority(prio: isize) -> bool {
RUN_QUEUE.lock().set_current_priority(prio)
}
pub fn yield_now() {
RUN_QUEUE.lock().yield_current();
}
pub fn sleep(dur: core::time::Duration) {
sleep_until(axhal::time::current_time() + dur);
}
pub fn sleep_until(deadline: axhal::time::TimeValue) {
#[cfg(feature = "irq")]
RUN_QUEUE.lock().sleep_until(deadline);
#[cfg(not(feature = "irq"))]
axhal::time::busy_wait_until(deadline);
}
pub fn join(task: &AxTaskRef) -> Option<i32> {
get_wait_for_exit_queue(task)
.map(|wait_queue| wait_queue.wait_until(|| task.state() == TaskState::Exited));
Some(task.get_exit_code())
}
#[cfg(feature = "monolithic")]
pub fn vfork_suspend(task: &AxTaskRef) {
get_wait_for_exit_queue(task).map(|wait_queue| {
wait_queue.wait_until(|| {
task.is_leader() || task.state() == TaskState::Exited
});
});
}
#[cfg(feature = "monolithic")]
pub fn wake_vfork_process(task: &AxTaskRef) {
get_wait_for_exit_queue(task).map(|wait_queue| wait_queue.notify_all(true));
}
pub fn exit(exit_code: i32) -> ! {
RUN_QUEUE.lock().exit_current(exit_code)
}
pub fn run_idle() -> ! {
loop {
yield_now();
debug!("idle task: waiting for IRQs...");
#[cfg(feature = "irq")]
axhal::arch::wait_for_irqs();
}
}