Skip to main content

os/task/
mod.rs

1//! Task management implementation
2//!
3//! Everything about task management, like starting and switching tasks is
4//! implemented here.
5//!
6//! A single global instance of [`TaskManager`] called `TASK_MANAGER` controls
7//! all the tasks in the whole operating system.
8//!
9//! A single global instance of [`Processor`] called `PROCESSOR` monitors running
10//! task(s) for each core.
11//!
12//! A single global instance of [`PidAllocator`] called `PID_ALLOCATOR` allocates
13//! pid for user apps.
14//!
15//! Be careful when you see `__switch` ASM function in `switch.S`. Control flow around this function
16//! might not be what you expect.
17mod context;
18mod manager;
19mod pid;
20mod processor;
21mod switch;
22#[allow(clippy::module_inception)]
23#[allow(rustdoc::private_intra_doc_links)]
24mod task;
25
26use crate::fs::{OpenFlags, open_file};
27use crate::sbi::shutdown;
28use alloc::sync::Arc;
29pub use context::TaskContext;
30use lazy_static::*;
31pub use manager::{TaskManager, fetch_task};
32use switch::__switch;
33use task::{TaskControlBlock, TaskStatus};
34
35pub use manager::add_task;
36pub use pid::{KernelStack, PidAllocator, PidHandle, pid_alloc};
37pub use processor::{
38    Processor, current_task, current_trap_cx, current_user_token, run_tasks, schedule,
39    take_current_task,
40};
41/// Suspend the current 'Running' task and run the next task in task list.
42pub fn suspend_current_and_run_next() {
43    // There must be an application running.
44    let task = take_current_task().unwrap();
45
46    // ---- access current TCB exclusively
47    let mut task_inner = task.inner_exclusive_access();
48    let task_cx_ptr = &mut task_inner.task_cx as *mut TaskContext;
49    // Change status to Ready
50    task_inner.task_status = TaskStatus::Ready;
51    drop(task_inner);
52    // ---- release current PCB
53
54    // push back to ready queue.
55    add_task(task);
56    // jump to scheduling cycle
57    schedule(task_cx_ptr);
58}
59
60/// pid of usertests app in make run TEST=1
61pub const IDLE_PID: usize = 1;
62
63/// Exit the current 'Running' task and run the next task in task list.
64pub fn exit_current_and_run_next(exit_code: i32) {
65    // take from Processor
66    let task = take_current_task().unwrap();
67
68    let pid = task.getpid();
69    if pid == IDLE_PID {
70        println!(
71            "[kernel] Idle process exit with exit_code {} ...",
72            exit_code
73        );
74        if exit_code != 0 {
75            //crate::sbi::shutdown(255); //255 == -1 for err hint
76            shutdown(true)
77        } else {
78            //crate::sbi::shutdown(0); //0 for success hint
79            shutdown(false)
80        }
81    }
82
83    // **** access current TCB exclusively
84    let mut inner = task.inner_exclusive_access();
85    // Change status to Zombie
86    inner.task_status = TaskStatus::Zombie;
87    // Record exit code
88    inner.exit_code = exit_code;
89    // do not move to its parent but under initproc
90
91    // ++++++ access initproc TCB exclusively
92    {
93        let mut initproc_inner = INITPROC.inner_exclusive_access();
94        for child in inner.children.iter() {
95            child.inner_exclusive_access().parent = Some(Arc::downgrade(&INITPROC));
96            initproc_inner.children.push(child.clone());
97        }
98    }
99    // ++++++ release parent PCB
100
101    inner.children.clear();
102    // deallocate user space
103    inner.memory_set.recycle_data_pages();
104    drop(inner);
105    // **** release current PCB
106    // drop task manually to maintain rc correctly
107    drop(task);
108    // we do not have to save task context
109    let mut _unused = TaskContext::zero_init();
110    schedule(&mut _unused as *mut _);
111}
112
113lazy_static! {
114    ///Globle process that init user shell
115    pub static ref INITPROC: Arc<TaskControlBlock> = Arc::new({
116        let inode = open_file("initproc", OpenFlags::RDONLY).unwrap();
117        let v = inode.read_all();
118        TaskControlBlock::new(v.as_slice())
119    });
120}
121///Add init process to the manager
122pub fn add_initproc() {
123    add_task(INITPROC.clone());
124}