2022-04-30 16:04:58 +08:00
|
|
|
//! Task management implementation
|
|
|
|
//!
|
|
|
|
//! Everything about task management, like starting and switching tasks is
|
|
|
|
//! implemented here.
|
|
|
|
//!
|
|
|
|
//! A single global instance of [`TaskManager`] called `TASK_MANAGER` controls
|
|
|
|
//! all the tasks in the whole operating system.
|
2022-05-20 08:50:52 +08:00
|
|
|
//!
|
|
|
|
//! A single global instance of [`Processor`] called `PROCESSOR` monitors running
|
|
|
|
//! task(s) for each core.
|
|
|
|
//!
|
|
|
|
//! A single global instance of [`PidAllocator`] called `PID_ALLOCATOR` allocates
|
2022-04-30 16:04:58 +08:00
|
|
|
//! pid for user apps.
|
2022-05-20 08:50:52 +08:00
|
|
|
//!
|
2022-04-30 16:04:58 +08:00
|
|
|
//! Be careful when you see `__switch` ASM function in `switch.S`. Control flow around this function
|
|
|
|
//! might not be what you expect.
|
2020-11-29 01:31:36 +08:00
|
|
|
mod context;
|
2020-12-08 15:37:10 +08:00
|
|
|
mod manager;
|
2020-12-08 17:17:28 +08:00
|
|
|
mod pid;
|
2022-01-21 14:56:19 -08:00
|
|
|
mod processor;
|
|
|
|
mod switch;
|
2022-01-24 17:50:49 -08:00
|
|
|
#[allow(clippy::module_inception)]
|
2022-04-30 16:04:58 +08:00
|
|
|
#[allow(rustdoc::private_intra_doc_links)]
|
2022-01-21 14:56:19 -08:00
|
|
|
mod task;
|
2020-11-29 01:31:36 +08:00
|
|
|
|
2025-02-19 21:27:17 +08:00
|
|
|
use crate::fs::{OpenFlags, open_file};
|
2023-03-29 21:04:20 +08:00
|
|
|
use crate::sbi::shutdown;
|
2020-12-08 15:37:10 +08:00
|
|
|
use alloc::sync::Arc;
|
2020-11-29 01:31:36 +08:00
|
|
|
pub use context::TaskContext;
|
2022-01-21 14:56:19 -08:00
|
|
|
use lazy_static::*;
|
2025-02-19 21:27:17 +08:00
|
|
|
pub use manager::{TaskManager, fetch_task};
|
2022-01-21 14:56:19 -08:00
|
|
|
use switch::__switch;
|
|
|
|
use task::{TaskControlBlock, TaskStatus};
|
2022-01-18 02:48:50 -08:00
|
|
|
|
2022-01-21 14:56:19 -08:00
|
|
|
pub use manager::add_task;
|
2025-02-19 21:27:17 +08:00
|
|
|
pub use pid::{KernelStack, PidAllocator, PidHandle, pid_alloc};
|
2020-12-08 15:37:10 +08:00
|
|
|
pub use processor::{
|
2025-02-19 21:27:17 +08:00
|
|
|
Processor, current_task, current_trap_cx, current_user_token, run_tasks, schedule,
|
|
|
|
take_current_task,
|
2020-12-08 15:37:10 +08:00
|
|
|
};
|
2022-04-30 16:04:58 +08:00
|
|
|
/// Suspend the current 'Running' task and run the next task in task list.
|
2020-11-29 10:31:15 +08:00
|
|
|
pub fn suspend_current_and_run_next() {
|
2020-12-08 15:37:10 +08:00
|
|
|
// There must be an application running.
|
2020-12-10 11:57:26 +08:00
|
|
|
let task = take_current_task().unwrap();
|
|
|
|
|
2021-07-20 22:10:22 +08:00
|
|
|
// ---- access current TCB exclusively
|
|
|
|
let mut task_inner = task.inner_exclusive_access();
|
|
|
|
let task_cx_ptr = &mut task_inner.task_cx as *mut TaskContext;
|
2020-12-10 11:57:26 +08:00
|
|
|
// Change status to Ready
|
2021-02-16 20:50:03 +08:00
|
|
|
task_inner.task_status = TaskStatus::Ready;
|
|
|
|
drop(task_inner);
|
2021-07-20 22:10:22 +08:00
|
|
|
// ---- release current PCB
|
2020-12-10 11:57:26 +08:00
|
|
|
|
2020-12-08 15:37:10 +08:00
|
|
|
// push back to ready queue.
|
|
|
|
add_task(task);
|
|
|
|
// jump to scheduling cycle
|
2021-07-20 22:10:22 +08:00
|
|
|
schedule(task_cx_ptr);
|
2020-11-29 10:31:15 +08:00
|
|
|
}
|
2022-06-24 01:26:26 +08:00
|
|
|
|
|
|
|
/// pid of usertests app in make run TEST=1
|
|
|
|
pub const IDLE_PID: usize = 0;
|
|
|
|
|
2022-04-30 16:04:58 +08:00
|
|
|
/// Exit the current 'Running' task and run the next task in task list.
|
2020-12-11 01:44:07 +08:00
|
|
|
pub fn exit_current_and_run_next(exit_code: i32) {
|
2020-12-10 11:57:26 +08:00
|
|
|
// take from Processor
|
|
|
|
let task = take_current_task().unwrap();
|
2022-06-24 01:26:26 +08:00
|
|
|
|
|
|
|
let pid = task.getpid();
|
|
|
|
if pid == IDLE_PID {
|
|
|
|
println!(
|
|
|
|
"[kernel] Idle process exit with exit_code {} ...",
|
|
|
|
exit_code
|
|
|
|
);
|
|
|
|
if exit_code != 0 {
|
|
|
|
//crate::sbi::shutdown(255); //255 == -1 for err hint
|
2023-03-29 20:51:50 +08:00
|
|
|
shutdown(true)
|
2022-06-24 01:26:26 +08:00
|
|
|
} else {
|
|
|
|
//crate::sbi::shutdown(0); //0 for success hint
|
2023-03-29 20:51:50 +08:00
|
|
|
shutdown(false)
|
2022-06-24 01:26:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-20 22:10:22 +08:00
|
|
|
// **** access current TCB exclusively
|
|
|
|
let mut inner = task.inner_exclusive_access();
|
2020-12-10 11:57:26 +08:00
|
|
|
// Change status to Zombie
|
|
|
|
inner.task_status = TaskStatus::Zombie;
|
2020-12-11 01:44:07 +08:00
|
|
|
// Record exit code
|
|
|
|
inner.exit_code = exit_code;
|
2020-12-11 16:14:14 +08:00
|
|
|
// do not move to its parent but under initproc
|
2020-12-10 11:57:26 +08:00
|
|
|
|
2021-07-20 22:10:22 +08:00
|
|
|
// ++++++ access initproc TCB exclusively
|
2020-12-10 11:57:26 +08:00
|
|
|
{
|
2021-07-20 22:10:22 +08:00
|
|
|
let mut initproc_inner = INITPROC.inner_exclusive_access();
|
2020-12-10 11:57:26 +08:00
|
|
|
for child in inner.children.iter() {
|
2021-07-20 22:10:22 +08:00
|
|
|
child.inner_exclusive_access().parent = Some(Arc::downgrade(&INITPROC));
|
2020-12-11 16:14:14 +08:00
|
|
|
initproc_inner.children.push(child.clone());
|
2020-12-10 11:57:26 +08:00
|
|
|
}
|
|
|
|
}
|
2021-07-20 22:10:22 +08:00
|
|
|
// ++++++ release parent PCB
|
2020-12-10 11:57:26 +08:00
|
|
|
|
|
|
|
inner.children.clear();
|
|
|
|
// deallocate user space
|
2020-12-11 16:14:14 +08:00
|
|
|
inner.memory_set.recycle_data_pages();
|
2020-12-10 11:57:26 +08:00
|
|
|
drop(inner);
|
2021-07-20 22:10:22 +08:00
|
|
|
// **** release current PCB
|
2020-12-10 11:57:26 +08:00
|
|
|
// drop task manually to maintain rc correctly
|
|
|
|
drop(task);
|
|
|
|
// we do not have to save task context
|
2021-07-20 22:10:22 +08:00
|
|
|
let mut _unused = TaskContext::zero_init();
|
|
|
|
schedule(&mut _unused as *mut _);
|
2020-12-06 13:56:13 +08:00
|
|
|
}
|
|
|
|
|
2020-12-11 16:14:14 +08:00
|
|
|
lazy_static! {
|
2022-05-20 08:50:52 +08:00
|
|
|
///Globle process that init user shell
|
2022-01-18 02:48:50 -08:00
|
|
|
pub static ref INITPROC: Arc<TaskControlBlock> = Arc::new({
|
|
|
|
let inode = open_file("initproc", OpenFlags::RDONLY).unwrap();
|
|
|
|
let v = inode.read_all();
|
|
|
|
TaskControlBlock::new(v.as_slice())
|
|
|
|
});
|
2020-12-11 16:14:14 +08:00
|
|
|
}
|
2022-04-30 16:04:58 +08:00
|
|
|
///Add init process to the manager
|
2020-12-10 11:57:26 +08:00
|
|
|
pub fn add_initproc() {
|
2020-12-11 16:14:14 +08:00
|
|
|
add_task(INITPROC.clone());
|
2020-12-06 13:56:13 +08:00
|
|
|
}
|