Operating system 为什么xv6调度程序在每个循环的开头调用sti()?

Operating system 为什么xv6调度程序在每个循环的开头调用sti()?,operating-system,kernel,xv6,Operating System,Kernel,Xv6,配套书上说 在空闲CPU上定期启用中断的原因是 可能没有可运行的进程,因为进程(例如shell) 正在等待I/O;如果计划程序左中断禁用所有 随着时间的推移,I/O永远不会到达 但是我认为我们只需要在outter for循环之前调用一次sti(),因为每次我们释放ptable.lock时,中断都会再次启用。有可能在禁用中断的情况下调用schedule(),在这种情况下,释放ptable spinlock将无法重新启用它们。如果查看,您将看到它没有显式地启用中断。相反,它使用函数popcli vo

配套书上说

在空闲CPU上定期启用中断的原因是 可能没有可运行的进程,因为进程(例如shell) 正在等待I/O;如果计划程序左中断禁用所有 随着时间的推移,I/O永远不会到达


但是我认为我们只需要在outter for循环之前调用一次sti(),因为每次我们释放ptable.lock时,中断都会再次启用。

有可能在禁用中断的情况下调用
schedule()
,在这种情况下,释放ptable spinlock将无法重新启用它们。

如果查看,您将看到它没有显式地启用中断。相反,它使用函数
popcli

void释放(结构自旋锁*lk)
{
...
popcli();//启用中断
}
功能
popcli
并不总是启用中断。它与
pushcli
一起用于跟踪嵌套级别。“Pushcli/popcli与cli/sti类似,只是它们是匹配的:撤销两个Pushcli需要两个popcli”

void-popcli(void)
{
//如果中断被启用,死机。。。
if(readeflags()&FL\u if)
{
恐慌(“popcli:interruptable”);
}
//cli嵌套的跟踪深度
mycpu()->ncli-=1;
//弹出的比推的多。。。
如果(mycpu()->ncli<0)
{
恐慌(“popcli”);
}
//已到达最外层,因此恢复中断状态
如果(mycpu()->ncli==0&&mycpu()->intena)
{
sti();//启用中断
}
}
popcli
有时会启用中断,
pushcli
总是禁用中断

void pushcli(void)
{
内部eflags;
eflags=readeflags();
//禁用中断
cli();
//在最外层开始时保存中断状态
如果(mycpu()->ncli==0)
{
mycpu()->intena=eflags&FL_IF;
}
//cli嵌套的跟踪深度
mycpu()->ncli+=1;
}
通过显式调用
sti
,计划程序将覆盖当前的push/popcli状态。我认为这提供了允许IO中断发生所需的简短窗口。即,调用
sti
和调用
cli
(通过
acquire
->
pushcli
->
cli
)之间的时间段

void调度程序(void)
{
...
对于(;;)
{
//在此处理器上启用中断。
sti();
//获取进程表锁
获取(&ptable.lock);
//在进程表上循环查找要运行的进程。
对于(p=ptable.proc;p<&ptable.proc[NPROC];p+=1)
{
...
}
//释放进程表锁
释放(&ptable.lock);
}
}

是的,没错。但是我认为我们只需要在scheduler()的开始启用中断。为什么我们需要重复这样做?你能在需要的时候给我一个场景吗?非常感谢。也许您应该尝试删除重复的
sti
,看看调度程序是否挂起或正常继续。