use alloc::sync::Arc;
use super::{context_switch, Task, TaskContext};
use crate::cpu_local_cell;
cpu_local_cell! {
static CURRENT_TASK_PTR: *const Task = core::ptr::null();
static PREVIOUS_TASK_PTR: *const Task = core::ptr::null();
static BOOTSTRAP_CONTEXT: TaskContext = TaskContext::new();
}
pub(super) fn current_task() -> Option<Arc<Task>> {
let ptr = CURRENT_TASK_PTR.load();
if ptr.is_null() {
return None;
}
let restored = unsafe { Arc::from_raw(ptr) };
let _ = core::mem::ManuallyDrop::new(restored.clone());
Some(restored)
}
pub(super) fn switch_to_task(next_task: Arc<Task>) {
super::atomic_mode::might_sleep();
let irq_guard = crate::trap::disable_local();
let current_task_ptr = CURRENT_TASK_PTR.load();
let current_task_ctx_ptr = if current_task_ptr.is_null() {
unsafe { BOOTSTRAP_CONTEXT.as_ptr_mut() }
} else {
let cur_task_arc = unsafe {
let restored = Arc::from_raw(current_task_ptr);
let _ = core::mem::ManuallyDrop::new(restored.clone());
restored
};
let ctx_ptr = cur_task_arc.ctx().get();
ctx_ptr
};
let next_task_ctx_ptr = next_task.ctx().get().cast_const();
if let Some(next_user_space) = next_task.user_space() {
next_user_space.vm_space().activate();
}
let old_prev = PREVIOUS_TASK_PTR.load();
PREVIOUS_TASK_PTR.store(current_task_ptr);
CURRENT_TASK_PTR.store(Arc::into_raw(next_task));
if !old_prev.is_null() {
drop(unsafe { Arc::from_raw(old_prev) });
}
drop(irq_guard);
unsafe {
context_switch(current_task_ctx_ptr, next_task_ctx_ptr);
}
}