分时多任务
branch ch3
一次加载多个任务
每个app加载到内存中的base address不同
user/build.py每个app定制各自的base address
使用cargo rustc单独编译
用-Clink-args=-Text=xxxx指令ld时.text section的address是0x80400000 + app_id * 0x20000
task切换
与trap相比
不涉及特权级切换,部分编译器完成
对应用透明(应用不感知)
过程
一个app Trap进S-Mode
调用__switch
A会被切换出去
运行另一个B
__switch返回后重新运行A
定义task context
ra: usize, 记录了 __switch 函数返回之后应该跳转到哪里继续执行
sp: usize, stack top of current task
s: [usize; 12], s0~s11 是被调用者保存寄存器
__switch
两个参数a0/x10, a1/x11,
当前task_cx_ptr
下一个task_cx_ptr
先保存current task的sp a0 + 8
然后保存ra a0
保存s0-12
ld读取 next_task_cx_ptr的同上
ra, s0-12, sp
sys_yield
多道程序执行
横轴时间线,纵轴是正在执行的entity
I/O task先执行
向I/O Device提交一个请求 开始阻塞 调用sys_yield让出CPU控制权
Other Task因此可以执行
一段时间cpu切换回I/O Task,device没有结束,继续yield
第二次切换,device结束,I/O Task结束
yield是协作式调度,task主动让出cpu
中间cpu会切换回蓝色应用是抢占式调度,每个task都有调度时间,防止被恶意应用饿死
sys_exit
suspend_current_and_run_next
mark_current_suspended 设置current的status为Ready
run_next_task
阻塞当前的运行接下来的
exit_current_and_run_next
退出当前的
run_next_task
退出当前的运行接下来的
run_next_task
使用find_nest_task寻找一个status为Ready的app获得ID
找不到,都执行完毕,os panic 退出
找到,调用__switch
TaskControlBlock app的管理单位 现在应该是进程process的概念
TaskManager
常量变量分离
inner里的是可变的内容
get_num_app获得app总数
对每个app初始化
t.task_cx = TaskContext::goto_restore(init_app_cx(i));
init_app_cx向os stack压入一个TrapContext
entry是 APP_BASE_ADDRESS + app_id * APP_SIZE_LIMIT
sp是 self.data.as_ptr() as usize + USER_STACK_SIZE
data代表了编译时static分配的内存
stack pointer只需要指向一块可用的足够大的内存区域即可
返回压入os stack TrapContext当前的os stack的sp
goto_restore
保存传入的sp 是os stack的那个TrapContext的sp,如上
ra设置成__restore
Status设置Ready
run_first_task 执行第一个应用
current_task_cx_ptr给了一个TaskContext::zero_init
避免其他数据被覆盖 TODO
如何覆盖?
__switch恢复sp,sp指向init_app_cx构造的TrapContext
回到之前的情况
__restore不再需要mv sp, a0
__switch后,sp正确指向需要的TrapContext
分时多任务
时钟计数器
mtime
M-Mode的SEE预留接口
riscv::register::time::read()获得
mtimecmp
使用sbi的SBI_SET_TIMER设置
use crate::config::CLOCK_FREQ; 时钟频率,单位赫兹
1s内计数器增量
const TICKS_PER_SEC: usize = 100;
set_timer(get_time() + CLOCK_FREQ / TICKS_PER_SEC);
读取当前mtime+10ms内计数器增量
mtime 超过mtimecmp
触发时钟中断
TODO
riscv
TODO
os task调度算法
riscv嵌套中断
TODO
riscv
嵌套中断是嵌套Trap的一种,Trap处理过程中发生新的Trap
同等特权级Mode的嵌套可以配置
被更高特权级Mode的Trap打断是不可避免的
默认,Trap进某个特权级,Trap处理过程中的相同特权级中断会被屏蔽
Trap发生,sstatus.sie保存在sstatus.spie
同时sstatus.sie清零,屏蔽了所有S特权级中断
Trap处理完sret,sstatus.sie从sstatus.spie恢复
如果不手动设置sstatus CSR
只考虑S特权级中断
不会嵌套中断
抢占式,每个app连续执行一段时间
内核强制切换到其他app
时间片Time Slice作为执行时长的度量单位
每个可能在毫秒量级
最简单的是RR, Round-Robin,时间片轮转算法
添加trap_handler分支
处理Trap::Interrupt(Interrupt::SupervisorTimer) S特权级时钟中断
重新设置计时器set_next_trigger()
调用suspend_current_and_run_next,暂停当前,切换下一个
为了避免S特权级时钟中断被屏蔽
执行第一个app前
sie::set_stimer(),S-Mode时钟中断不会屏蔽
再设置第一个10ms计时器,set_next_trigger()

Generated 2025-05-05 04:17:35 +0000
25bcfca-dirty 2025-05-04 14:47:56 +0000