1mod context;
13mod switch;
14#[allow(clippy::module_inception)]
15mod task;
16
17use crate::loader::{get_app_data, get_num_app};
18use crate::sbi::shutdown;
19use crate::sync::UPSafeCell;
20use crate::trap::TrapContext;
21use alloc::vec::Vec;
22use lazy_static::*;
23use switch::__switch;
24use task::{TaskControlBlock, TaskStatus};
25
26pub use context::TaskContext;
27
28pub struct TaskManager {
38 num_app: usize,
40 inner: UPSafeCell<TaskManagerInner>,
42}
43
44struct TaskManagerInner {
46 tasks: Vec<TaskControlBlock>,
48 current_task: usize,
50}
51
52lazy_static! {
53 pub static ref TASK_MANAGER: TaskManager = {
55 println!("init TASK_MANAGER");
56 let num_app = get_num_app();
57 println!("num_app = {}", num_app);
58 let mut tasks: Vec<TaskControlBlock> = Vec::new();
59 for i in 0..num_app {
60 tasks.push(TaskControlBlock::new(get_app_data(i), i));
61 }
62 TaskManager {
63 num_app,
64 inner: unsafe {
65 UPSafeCell::new(TaskManagerInner {
66 tasks,
67 current_task: 0,
68 })
69 },
70 }
71 };
72}
73
74impl TaskManager {
75 fn run_first_task(&self) -> ! {
80 let mut inner = self.inner.exclusive_access();
81 let next_task = &mut inner.tasks[0];
82 next_task.task_status = TaskStatus::Running;
83 let next_task_cx_ptr = &next_task.task_cx as *const TaskContext;
84 drop(inner);
85 let mut _unused = TaskContext::zero_init();
86 unsafe {
88 __switch(&mut _unused as *mut _, next_task_cx_ptr);
89 }
90 panic!("unreachable in run_first_task!");
91 }
92
93 fn mark_current_suspended(&self) {
95 let mut inner = self.inner.exclusive_access();
96 let cur = inner.current_task;
97 inner.tasks[cur].task_status = TaskStatus::Ready;
98 }
99
100 fn mark_current_exited(&self) {
102 let mut inner = self.inner.exclusive_access();
103 let cur = inner.current_task;
104 inner.tasks[cur].task_status = TaskStatus::Exited;
105 }
106
107 fn find_next_task(&self) -> Option<usize> {
111 let inner = self.inner.exclusive_access();
112 let current = inner.current_task;
113 (current + 1..current + self.num_app + 1)
114 .map(|id| id % self.num_app)
115 .find(|id| inner.tasks[*id].task_status == TaskStatus::Ready)
116 }
117
118 fn get_current_token(&self) -> usize {
120 let inner = self.inner.exclusive_access();
121 inner.tasks[inner.current_task].get_user_token()
122 }
123
124 fn get_current_trap_cx(&self) -> &'static mut TrapContext {
126 let inner = self.inner.exclusive_access();
127 inner.tasks[inner.current_task].get_trap_cx()
128 }
129
130 pub fn change_current_program_brk(&self, size: i32) -> Option<usize> {
132 let mut inner = self.inner.exclusive_access();
133 let cur = inner.current_task;
134 inner.tasks[cur].change_program_brk(size)
135 }
136
137 fn run_next_task(&self) {
140 if let Some(next) = self.find_next_task() {
141 let mut inner = self.inner.exclusive_access();
142 let current = inner.current_task;
143 inner.tasks[next].task_status = TaskStatus::Running;
144 inner.current_task = next;
145 let current_task_cx_ptr = &mut inner.tasks[current].task_cx as *mut TaskContext;
146 let next_task_cx_ptr = &inner.tasks[next].task_cx as *const TaskContext;
147 drop(inner);
148 unsafe {
150 __switch(current_task_cx_ptr, next_task_cx_ptr);
151 }
152 } else {
154 println!("All applications completed!");
155 shutdown(false);
156 }
157 }
158}
159
160pub fn run_first_task() {
162 TASK_MANAGER.run_first_task();
163}
164
165fn run_next_task() {
168 TASK_MANAGER.run_next_task();
169}
170
171fn mark_current_suspended() {
173 TASK_MANAGER.mark_current_suspended();
174}
175
176fn mark_current_exited() {
178 TASK_MANAGER.mark_current_exited();
179}
180
181pub fn suspend_current_and_run_next() {
183 mark_current_suspended();
184 run_next_task();
185}
186
187pub fn exit_current_and_run_next() {
189 mark_current_exited();
190 run_next_task();
191}
192
193pub fn current_user_token() -> usize {
195 TASK_MANAGER.get_current_token()
196}
197
198pub fn current_trap_cx() -> &'static mut TrapContext {
200 TASK_MANAGER.get_current_trap_cx()
201}
202
203pub fn change_program_brk(size: i32) -> Option<usize> {
205 TASK_MANAGER.change_current_program_brk(size)
206}