os/kernel/scheduler/
rr_scheduler.rs1use crate::{
5 arch::kernel::context::Context,
6 kernel::{
7 TaskState,
8 cpu::current_cpu,
9 scheduler::{Scheduler, SwitchPlan, TaskQueue},
10 task::SharedTask,
11 },
12};
13
14const DEFAULT_TIME_SLICE: usize = 1; pub struct RRScheduler {
22 run_queue: TaskQueue,
24 time_slice: usize,
26 current_slice: usize,
28}
29
30impl RRScheduler {
31 pub fn update_time_slice(&mut self) -> bool {
35 if self.current_slice > 0 {
36 self.current_slice -= 1;
37 }
38 if self.current_slice == 0 {
39 self.current_slice = self.time_slice;
40 return true;
41 }
42 false
43 }
44}
45
46impl Scheduler for RRScheduler {
47 fn new() -> Self {
48 RRScheduler {
49 run_queue: TaskQueue::new(),
50 time_slice: DEFAULT_TIME_SLICE,
51 current_slice: DEFAULT_TIME_SLICE,
52 }
53 }
54
55 fn next_task(&mut self) -> Option<SwitchPlan> {
56 let prev_task_opt = current_cpu().lock().current_task.take();
58
59 let next_task = match self.run_queue.pop_task() {
61 Some(t) => t,
62 None => {
63 current_cpu().lock().current_task = prev_task_opt;
65 return None;
66 }
67 };
68
69 let new_ctx_ptr: *const Context = {
71 let g = next_task.lock();
72 &g.context as *const _
73 };
74
75 let old_ctx_ptr: *mut Context = if let Some(ref prev) = prev_task_opt {
77 let mut g = prev.lock();
78 &mut g.context as *mut _
79 } else {
80 panic!("RRScheduler: no current task to schedule from");
81 };
82
83 if let Some(prev) = &prev_task_opt {
85 let still_running = { prev.lock().state == TaskState::Running };
86 if still_running {
87 self.run_queue.add_task(prev.clone());
88 }
89 }
90
91 current_cpu().lock().switch_task(next_task);
93 self.current_slice = self.time_slice;
94
95 Some(SwitchPlan {
96 old: old_ctx_ptr,
97 new: new_ctx_ptr,
98 })
99 }
100
101 fn add_task(&mut self, task: SharedTask) {
102 let state = { task.lock().state };
103 match state {
104 TaskState::Running => {
105 self.run_queue.add_task(task);
106 }
107 _ => {
108 panic!("RRScheduler: can only add running tasks to scheduler");
109 }
110 }
111 }
112
113 fn sleep_task(&mut self, task: SharedTask, receive_signal: bool) {
114 {
115 task.lock().state = if receive_signal {
116 TaskState::Interruptible
117 } else {
118 TaskState::Uninterruptible
119 };
120 }
121
122 self.run_queue.remove_task(&task);
123 }
124
125 fn wake_up(&mut self, task: SharedTask) {
126 {
127 task.lock().state = TaskState::Running;
128 }
129
130 if !self.run_queue.contains(&task) {
131 self.run_queue.add_task(task);
132 }
133 }
134
135 fn exit_task(&mut self, task: SharedTask) {
136 {
137 task.lock().state = TaskState::Zombie;
138 }
139
140 self.run_queue.remove_task(&task);
141 }
142
143 fn sleep_task_with_guard(
144 &mut self,
145 task: &mut crate::sync::SpinLockGuard<'_, crate::kernel::TaskStruct>,
146 stask: SharedTask,
147 receive_signal: bool,
148 ) {
149 task.state = if receive_signal {
150 TaskState::Interruptible
151 } else {
152 TaskState::Uninterruptible
153 };
154
155 self.run_queue.remove_task(&stask);
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162 use crate::{
163 kassert,
164 kernel::{cpu::current_cpu, task::TaskStruct},
165 test_case,
166 };
167
168 fn mk_task(tid: u32) -> SharedTask {
169 TaskStruct::new_dummy_task(tid).into_shared()
170 }
171
172 test_case!(test_rr_sleep_and_wakeup, {
229 current_cpu().lock().current_task = Some(mk_task(30));
231
232 let mut rr = RRScheduler::new();
233 let t = mk_task(31);
234 rr.add_task(t.clone());
235
236 rr.sleep_task(t.clone(), false);
238 {
239 let g = t.lock();
240 kassert!(matches!(g.state, TaskState::Uninterruptible));
241 }
242 kassert!(!rr.run_queue.contains(&t));
243
244 rr.wake_up(t.clone());
246 {
247 let g = t.lock();
248 kassert!(matches!(g.state, TaskState::Running));
249 }
250 kassert!(rr.run_queue.contains(&t));
251 });
252
253 test_case!(test_rr_exit_task, {
255 current_cpu().lock().current_task = Some(mk_task(40));
256
257 let mut rr = RRScheduler::new();
258 let t = mk_task(41);
259 rr.add_task(t.clone());
260
261 rr.exit_task(t.clone());
262 {
263 let g = t.lock();
264 kassert!(matches!(g.state, TaskState::Zombie));
265 }
266 kassert!(!rr.run_queue.contains(&t));
267 });
268
269 test_case!(test_rr_update_time_slice, {
271 let mut rr = RRScheduler::new();
272 rr.current_slice = 1; let expired = rr.update_time_slice();
274 kassert!(expired);
275 kassert!(rr.current_slice == rr.time_slice);
276 });
277}