1mod context;
13mod switch;
14
15#[allow(clippy::module_inception)]
16mod task;
17
18use crate::config::MAX_APP_NUM;
19use crate::loader::{get_num_app, init_app_cx};
20use crate::sbi::shutdown;
21use crate::sync::UPSafeCell;
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
44pub struct TaskManagerInner {
46 tasks: [TaskControlBlock; MAX_APP_NUM],
48 current_task: usize,
50}
51
52lazy_static! {
53 pub static ref TASK_MANAGER: TaskManager = {
55 let num_app = get_num_app();
56 let mut tasks = [TaskControlBlock {
57 task_cx: TaskContext::zero_init(),
58 task_status: TaskStatus::UnInit,
59 }; MAX_APP_NUM];
60 for (i, task) in tasks.iter_mut().enumerate() {
61 task.task_cx = TaskContext::goto_restore(init_app_cx(i));
62 task.task_status = TaskStatus::Ready;
63 }
64 TaskManager {
65 num_app,
66 inner: unsafe {
67 UPSafeCell::new(TaskManagerInner {
68 tasks,
69 current_task: 0,
70 })
71 },
72 }
73 };
74}
75
76impl TaskManager {
77 fn run_first_task(&self) -> ! {
82 let mut inner = self.inner.exclusive_access();
83 let task0 = &mut inner.tasks[0];
84 task0.task_status = TaskStatus::Running;
85 let next_task_cx_ptr = &task0.task_cx as *const TaskContext;
86 drop(inner);
87 let mut _unused = TaskContext::zero_init();
88 unsafe {
90 __switch(&mut _unused as *mut TaskContext, next_task_cx_ptr);
91 }
92 panic!("unreachable in run_first_task!");
93 }
94
95 fn mark_current_suspended(&self) {
97 let mut inner = self.inner.exclusive_access();
98 let current = inner.current_task;
99 inner.tasks[current].task_status = TaskStatus::Ready;
100 }
101
102 fn mark_current_exited(&self) {
104 let mut inner = self.inner.exclusive_access();
105 let current = inner.current_task;
106 inner.tasks[current].task_status = TaskStatus::Exited;
107 }
108
109 fn find_next_task(&self) -> Option<usize> {
113 let inner = self.inner.exclusive_access();
114 let current = inner.current_task;
115 (current + 1..current + self.num_app + 1)
116 .map(|id| id % self.num_app)
117 .find(|id| inner.tasks[*id].task_status == TaskStatus::Ready)
118 }
119
120 fn run_next_task(&self) {
123 if let Some(next) = self.find_next_task() {
124 let mut inner = self.inner.exclusive_access();
125 let current = inner.current_task;
126 inner.tasks[next].task_status = TaskStatus::Running;
127 inner.current_task = next;
128 let current_task_cx_ptr = &mut inner.tasks[current].task_cx as *mut TaskContext;
129 let next_task_cx_ptr = &inner.tasks[next].task_cx as *const TaskContext;
130 drop(inner);
131 unsafe {
133 __switch(current_task_cx_ptr, next_task_cx_ptr);
134 }
135 } else {
137 println!("All applications completed!");
138 shutdown(false);
139 }
140 }
141}
142
143pub fn run_first_task() {
145 TASK_MANAGER.run_first_task();
146}
147
148fn run_next_task() {
150 TASK_MANAGER.run_next_task();
151}
152
153fn mark_current_suspended() {
155 TASK_MANAGER.mark_current_suspended();
156}
157
158fn mark_current_exited() {
160 TASK_MANAGER.mark_current_exited();
161}
162
163pub fn suspend_current_and_run_next() {
165 mark_current_suspended();
166 run_next_task();
167}
168
169pub fn exit_current_and_run_next() {
171 mark_current_exited();
172 run_next_task();
173}