为什么要在 XV6 调度程序中禁用中断?
Why disable interrupts in XV6 scheduler?
对于 XV6 中的 sched() 函数 (proc.c)
- 为什么我们在进行上下文切换时必须禁用中断?是不是因为开启了中断,sched函数可以重复调用?
- 为什么ncli(pushcli嵌套深度)必须等于1?
sched(void) {
int intena;
if(readeflags()&FL_IF)
panic("sched interruptible");
if(cp->state == RUNNING)
panic("sched running");
if(!holding(&ptable.lock))
panic("sched ptable.lock");
if(c->ncli != 1)
panic("sched locks");
intena = c->intena;
swtch(&cp->context, &c->context);
c->intena = intena;
}
- why must we disable interrupts when doing a context switch? Is it because if interrupts are enabled, the sched function can be repeatedly invoked?
每个任务都有状态,其中包括 CPU 的状态和 OS 用来跟踪事物的各种变量的状态(例如,当前哪个任务 运行 ). switch()
函数从一个任务的状态切换到另一个;但它不会自动执行此操作。如果在 switch()
正在从一个任务切换到另一个任务的过程中发生 IRQ,则 IRQ 处理程序将看到不一致的状态(例如 "which task is currently running" 变量与当前虚拟地址 space 不匹配) can/will 导致极难重现的细微错误(因为您必须准确把握问题发生的时间)并且极难找到和修复。
请注意,支持多个 CPU 的操作系统不能依赖 "IRQs disabled" 来防止重入问题(例如,禁用一个 CPU 上的 IRQ 不会阻止另一个 CPU 从调用 sched()
而它已经是 运行)。为了这; XV6(确实支持多个 CPUs)使用锁(ptable.lock
)。
- Why must ncli (the depth of pushcli nesting) be equal to 1?
从CPU的角度来看:
- 一个任务导致
ncli
设置为1
- 发生任务切换
- 另一项任务导致
ncli
减为零
从任务的角度来看:
- 任务导致
ncli
设置为 1
- 许多任务切换发生(而其他任务被给予 CPU 时间)直到任务再次被给予 CPU 时间
- 任务导致
ncli
减为零
这两种观点都需要兼容。例如,如果一个任务导致 ncli
设置为 2,则(在任务切换后)递减 ncli
两次;那么 "from that task's perspective" 会很好,但是 "from CPU's perspective" 它会中断(另一个任务只会递减 ncli
一旦导致 IRQ 在不应该被禁用时被禁用)。
换句话说,ncli
必须始终是相同的值。选择值 1 可能是因为它 "good enough" 对于大多数调用者而言,使用更高的值会增加不必要的开销。
对于 XV6 中的 sched() 函数 (proc.c)
- 为什么我们在进行上下文切换时必须禁用中断?是不是因为开启了中断,sched函数可以重复调用?
- 为什么ncli(pushcli嵌套深度)必须等于1?
sched(void) {
int intena;
if(readeflags()&FL_IF)
panic("sched interruptible");
if(cp->state == RUNNING)
panic("sched running");
if(!holding(&ptable.lock))
panic("sched ptable.lock");
if(c->ncli != 1)
panic("sched locks");
intena = c->intena;
swtch(&cp->context, &c->context);
c->intena = intena;
}
- why must we disable interrupts when doing a context switch? Is it because if interrupts are enabled, the sched function can be repeatedly invoked?
每个任务都有状态,其中包括 CPU 的状态和 OS 用来跟踪事物的各种变量的状态(例如,当前哪个任务 运行 ). switch()
函数从一个任务的状态切换到另一个;但它不会自动执行此操作。如果在 switch()
正在从一个任务切换到另一个任务的过程中发生 IRQ,则 IRQ 处理程序将看到不一致的状态(例如 "which task is currently running" 变量与当前虚拟地址 space 不匹配) can/will 导致极难重现的细微错误(因为您必须准确把握问题发生的时间)并且极难找到和修复。
请注意,支持多个 CPU 的操作系统不能依赖 "IRQs disabled" 来防止重入问题(例如,禁用一个 CPU 上的 IRQ 不会阻止另一个 CPU 从调用 sched()
而它已经是 运行)。为了这; XV6(确实支持多个 CPUs)使用锁(ptable.lock
)。
- Why must ncli (the depth of pushcli nesting) be equal to 1?
从CPU的角度来看:
- 一个任务导致
ncli
设置为1 - 发生任务切换
- 另一项任务导致
ncli
减为零
从任务的角度来看:
- 任务导致
ncli
设置为 1 - 许多任务切换发生(而其他任务被给予 CPU 时间)直到任务再次被给予 CPU 时间
- 任务导致
ncli
减为零
这两种观点都需要兼容。例如,如果一个任务导致 ncli
设置为 2,则(在任务切换后)递减 ncli
两次;那么 "from that task's perspective" 会很好,但是 "from CPU's perspective" 它会中断(另一个任务只会递减 ncli
一旦导致 IRQ 在不应该被禁用时被禁用)。
换句话说,ncli
必须始终是相同的值。选择值 1 可能是因为它 "good enough" 对于大多数调用者而言,使用更高的值会增加不必要的开销。