From c4edfb87cb9f2b20c6dfbe7cdb6322468af2cde9 Mon Sep 17 00:00:00 2001 From: acevest Date: Fri, 26 May 2023 22:28:35 +0800 Subject: [PATCH] =?utf8?q?=E5=BC=80=E5=8F=91=E6=97=A5=E5=BF=97:=E5=88=86?= =?utf8?q?=E6=9E=90=E5=BD=93=E5=89=8D=E4=B8=AD=E6=96=AD=E5=B5=8C=E5=A5=97?= =?utf8?q?=E9=97=AE=E9=A2=98,=E5=B9=B6=E6=8F=90=E5=87=BA=E4=BA=86=E4=B8=80?= =?utf8?q?=E4=B8=AA=E4=BC=98=E5=8C=96=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- doc/dev.md | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 doc/dev.md diff --git a/doc/dev.md b/doc/dev.md new file mode 100644 index 0000000..5e4c67d --- /dev/null +++ b/doc/dev.md @@ -0,0 +1,103 @@ +# 开发日志 + +这个文件主要用来记录特定版本的代码存在的主要问题,及修改方向。 + + +## 001073af2176de114d8588124d665aad2b4f2995 版本问题 + +### 问题表现 + +虽然在`kernel/sched.c:schedule`里如果`0 == current->ticks`则会将其重置的逻辑,但在`clock_handler`里的`current->ticks-`代码任有可能将其值减到0后继续再减进而溢出。就算是`schedule`代码里的处理逻辑已经是在关中断的情况下进行的也无济于事。 + +将`qemu`的速度调至10%比较容易复现这个问题。 + +### 问题原因 + +在这个版本中,由于在`clock_handler`里塞了过多的调试代码,导致其耗时很长。这就可能会出现如下处理序列: + +1. 处理器进入硬盘`14`号中断的处理逻辑 +2. 如果硬盘中断逻辑已经到达开中断的部分 +3. 这时时钟中断到达,则会中断当前硬盘中断转而执行时钟中断。 +4. 时钟中断执行`current->ticks--`,其值有可能从`1`变为`0` +5. 时钟中断占用相当长时间,甚至超过两次时钟中断间隔 +6. 时钟中断返回前判断到当前中断处于嵌套状态,不执行重新调度,此时`current->ticks == 0`。 +7. 时钟中断返回 +8. 由于上一个时钟中断耗时过长,因此当其刚返回后,14号中断还没来得及继续执行,或者刚执行了有限的几条指令,又被下一个时钟中断打断。 +9. 重复以上逻辑,这个时钟中断逻辑就继续对`current->ticks`减`1`,使其值为`0xFFFFFFFF`。 + +### 问题修复计划 + +### 优化中断处理服务程序 + +只写少量必要代码,尽快返回,不再加入大量调试程序。 + +#### 不再支持中断嵌套 + +不支持中断嵌套仅指不嵌套执行中断服务器程序,而其它需要在中断环境执行的逻辑是可以开中断执行的,也就是有再次被新中断打断的可能。 + +不再支持中断嵌套后,每次中断处理过程大致如下 + +1. 硬件触发中断,自动关中断 +2. 保存上下文 +3. 执行中断服务例程 +3. 开中断 +4. 执行其它逻辑 +5. 关中断 +6. 恢复上下文返回 + +可以到第4步是在开中断的状态下执行的。而执行它的时候是可能被新到的中断程序再次打断的,也就是第4步是可能嵌套执行的。 + +为了避免这种情况,将上述程序引入一个`int`型的全局变更`reenter`,并将其初始化为`-1`后再做修改 + +1. 硬件触发中断,自动关中断 +2. 保存上下文 +3. `reenter++` +4. 执行中断服务例程 +5. 判断`reenter != 0`则跳转到第`9`步 +6. 开中断 +7. 执行其它逻辑 +8. 关中断 +9. `reenter--` +10. 恢复上下文返回 + +如果在执行第`7`步后被新到中断打断,那新逻辑就会执行如下序列 + + +1. 硬件触发中断,自动关中断 +2. 保存上下文 +3. `reenter++` +4. 执行中断服务例程 +5. 判断`reenter != 0`则跳转到第`9`步 +6. ~~开中断~~ +7. ~~执行其它逻辑~~ +8. ~~关中断~~ +9. `reenter--` +10. 恢复上下文返回 + +这样就算第`7`步很耗时,在中断打断这个步骤的情况下,它也只会被执行一次,而不会嵌套执行。这是优点,也是缺点,目前逻辑简单还能应付。后续也还是要继续优化。 + + +但这也改变不了时钟中断可能将`current->ticks`改成负数的情况(因为可能在`current->ticks == 0`的情况下,第`7`步是有可能再撑到下一个时钟中断将之再减1的)。因此需要在`task_union`中引入一个`need_resched`字段,当`current->ticks == 0`时不再减,而是直接将`need_resched`设置为`1`。 + + +1. 硬件触发中断,自动关中断 +2. 保存上下文 +3. `reenter++` +4. 执行中断服务例程 +5. 判断`reenter != 0`则跳转到第`11`步 +6. 开中断 +7. 执行其它逻辑 +8. 关中断 +9. assert(reenter == 0); +10. 如果`current->need_resched == 0`则继续,否则跳`20` +11. `reenter--` +12. 恢复上下文返回 + + +以下为需要进程抢占步骤,目前不分内核还是用户进程。 + +20. `reenter--`、`current->need_resched = 0`、`current->ticks = current->priority` +21. schedule +22. 跳`12` + +相似的逻辑也可以加到系统调用返回处。这样就可以在中断返回和系统调用返回处抢占任务。 \ No newline at end of file -- 2.44.0