os/kernel/scheduler/
rr_scheduler.rs

1//! 轮转调度器模块
2//!
3//! 实现了一个简单的轮转调度器(Round-Robin Scheduler)
4use 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; // 默认时间片长度
15
16/// 简单的轮转调度器实现
17/// 每个任务按顺序轮流获得 CPU 时间片
18/// 约束:
19/// 1. 要求开始调度后任何时刻,至少有一个任务处于运行状态
20// XXX: 现在的实现是单核的。且没有支持内核抢占。
21pub struct RRScheduler {
22    // 运行队列
23    run_queue: TaskQueue,
24    // 时间片长度(以时钟中断滴答数为单位)
25    time_slice: usize,
26    // 当前时间片剩余时间
27    current_slice: usize,
28}
29
30impl RRScheduler {
31    /// 更新当前时间片计数器
32    /// # 返回值
33    /// 如果时间片用尽,返回 true;否则返回 false
34    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        // 取出当前任务,避免在下面赋值时被 Drop 掉
57        let prev_task_opt = current_cpu().lock().current_task.take();
58
59        // 选择下一个可运行任务(或返回/转 idle)
60        let next_task = match self.run_queue.pop_task() {
61            Some(t) => t,
62            None => {
63                // 没有可运行任务:恢复 current 并返回
64                current_cpu().lock().current_task = prev_task_opt;
65                return None;
66            }
67        };
68
69        // 准备 new 上下文指针(短作用域锁)
70        let new_ctx_ptr: *const Context = {
71            let g = next_task.lock();
72            &g.context as *const _
73        };
74
75        // 准备 old 上下文指针
76        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        // 轮转策略:旧任务若仍可运行,放回运行队列尾
84        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        // 在切换前,更新当前任务与时间片
92        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    // // 基础轮转:current=T0,队列[T1,T2],三次切换应依次运行 T1 -> T2 -> T0
173    // test_case!(test_rr_prepare_switch_round_robin_order, {
174    //     // 设置当前任务
175    //     let t0 = mk_task(10);
176    //     current_cpu().lock().current_task = Some(t0.clone());
177
178    //     // 构造调度器并加入待运行任务
179    //     let mut rr = RRScheduler::new();
180    //     let t1 = mk_task(11);
181    //     let t2 = mk_task(12);
182    //     rr.add_task(t1.clone());
183    //     rr.add_task(t2.clone());
184
185    //     // 第一次切换:next 应为 t1,prev=t0 被放回队列
186    //     let plan1 = rr.prepare_switch().expect("no switch plan 1");
187    //     kassert!(plan1.old as usize != 0 && plan1.new as usize != 0);
188    //     let cur1 = {
189    //         let g = current_cpu().lock();
190    //         g.current_task.as_ref().unwrap().lock().tid
191    //     };
192    //     kassert!(cur1 == 11);
193
194    //     // 第二次切换:current=t1,next=t2,prev=t1 放回队列
195    //     let plan2 = rr.prepare_switch().expect("no switch plan 2");
196    //     kassert!(plan2.old as usize != 0 && plan2.new as usize != 0);
197    //     let cur2 = {
198    //         let g = current_cpu().lock();
199    //         g.current_task.as_ref().unwrap().lock().tid
200    //     };
201    //     kassert!(cur2 == 12);
202
203    //     // 第三次切换:current=t2,next 应为 t0(被回收至队列尾)
204    //     let plan3 = rr.prepare_switch().expect("no switch plan 3");
205    //     kassert!(plan3.old as usize != 0 && plan3.new as usize != 0);
206    //     let cur3 = {
207    //         let g = current_cpu().lock();
208    //         g.current_task.as_ref().unwrap().lock().tid
209    //     };
210    //     kassert!(cur3 == 10);
211    // });
212
213    // // 添加任务:仅允许 Running 状态
214    // test_case!(test_rr_add_task_only_running, {
215    //     let mut rr = RRScheduler::new();
216    //     let stopped = mk_task(21);
217    //     {
218    //         let mut g = stopped.lock();
219    //         g.state = TaskState::Stopped;
220    //     }
221    //     let result = catch_unwind(AssertUnwindSafe(|| {
222    //         rr.add_task(stopped);
223    //     }));
224    //     kassert!(result.is_err());
225    // });
226
227    // sleep / wake:sleep 后应不在队列且状态更新;wake 后回到队列且为 Running
228    test_case!(test_rr_sleep_and_wakeup, {
229        // 需要一个当前任务以便 prepare_switch 不报错;本测试不调用 prepare_switch,但保持一致设定
230        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        // 休眠
237        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        // 唤醒
245        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    // 任务退出:应设置状态为 Zombie,并从队列移除
254    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    // 时间片更新:手动将 current_slice 置 1,update 后应返回 true 并重置为 time_slice
270    test_case!(test_rr_update_time_slice, {
271        let mut rr = RRScheduler::new();
272        rr.current_slice = 1; // 直接操纵以触发用尽路径
273        let expired = rr.update_time_slice();
274        kassert!(expired);
275        kassert!(rr.current_slice == rr.time_slice);
276    });
277}