使用无限循环时,x86中断处理程序被阻止
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用无限循环时,x86中断处理程序被阻止相关的知识,希望对你有一定的参考价值。
我正在尝试学习x86汇编和c语言。现在我已经完成了一个简单的计时器和键盘中断。第一个可以每隔几个刻度打印一行,第二个可以打印你在键盘上按下的内容。代码就像:
timer.c中:
print();
return;
keyboard.c中:
print();
return;
main.c中:
while(1);
这两个处理程序都在IDT中。因此,当发生中断时,IF标志被清除。 CPU将忽略其他中断。初始化了main函数中的所有配置后,我用无限循环完成了它,就像:while(1)
。好的,这很好,我可以在屏幕上看到这两个处理程序的工作原理。
但是,当我想使它成为嵌套中断时,我做了以下事情:
timer.c中:
sti(); //set IF to 1 to enable interrupt
print();
while(1); // wait here to test if the keyboard interrupt can occur
return;
keyboard.c中:
print();
return;
main.c中:
while(1);
接下来发生的事情真的让我感兴趣:使用Bochs,我可以看到我的程序只是在timer.c中执行while循环。此时,我检查了标志,它显示IF标志已经设置,但是当我尝试输入某个东西来测试另一个interrut时,它失败了。似乎所有的中断都被阻止或忽略了。
问题是,这两个循环之间的区别是什么,一个只是在中断处理程序中,我也不知道如何解决这个问题。我在我的vmware和virtualbox中仔细检查了我的代码,但结果是一样的。
我知道这个问题肯定发生在我遇到它之前,但是,我找不到任何与此问题有关的内容。
通过在中断处理程序中启用中断,您不会仅启用“其他”中断,而是启用所有中断。包括定时器中断。 (这太笼统了,payne在评论中指出,在x86上可能有不同的IRQ信号源,特别是PIC / APIC芯片可以配置为优先于其他...不会改变任何关于re的原理-inrant IRQ处理,但您可以微调哪些IRQ具有优先级,这可能意味着如果您的配置阻止它,最终根本不需要重新进入锁定)
你的代码看起来不像是可重入的处理程序,所以如果这就是你的处理程序代码的完成方式,那么你的计时器会按照配置继续启动新的计时器中断,并且因为你在那里有sti
,它们会不断重新进入处理程序代码,填充缓慢的堆栈空间,直到它会溢出(或环绕,我不确定你是否处于实际或保护模式,以及如何设置堆栈)。只有最后一个当然是在运行,休息是休眠的(永远,如果最后一个没有返回)。
长时间的中断处理程序通常是错误的代码体系结构的标志(针对最短的+最快的中断处理程序,通常只是用数据填充一些队列,在中断处理程序之外以异步方式处理)。但是如果你确实需要一个,并且你不能禁用其他中断,你必须将处理程序编写为可重入的中断。
Re-entrant timer interrupt handler
{
if (locked) return; // already handling previous IRQ
// which means the new IRQ is **IGNORED**! (price for slow handler)
locked = true; // lock to prevent further re-entry
sti(); //set IF to 1 to enable interrupts
// do the slow stuff here (but not infinite loop of course!)
// "print();" is not an excellent idea either, for interrupt handler
// while(1); // this would never ever end at all, so NO.
// slow stuff finished, ready for next request
locked = false; // allow next timer IRQ to process the slow stuff again
return;
}
附录:还有一句话,可能是“显而易见的”,但只是为了确保清楚。单CPU内核只能在同一时刻运行指令的单个“线程”,即它在main
中执行无限循环,或者它正在执行其中一个中断处理程序。当新的IRQ信号进入CPU并启用中断时,当前CPU状态存储在堆栈中(无论是在主,或定时器或键盘,无关紧要),CPU将切换到所需的中断处理程序。因此,如果你发出的IRQ比你的处理程序完成并返回到前面的代码更快,你将慢慢地用存储的CPU状态阻塞堆栈内存,它将永远不会返回到底部的原始线程(main
内的无限循环)。
定时器中断(IRQ0)优先于键盘中断(IRQ1)。
因此,即使您在定时器中断处理程序中一般启用中断(使用sti指令),主中断控制器(PIC)也只会启用更高优先级的中断,直到您的定时器/ IRQ0服务程序完成。
有关其他解释,请参阅:https://groups.google.com/forum/#!topic/comp.lang.asm.x86/7coo0px-BU4
对,就是这样。中断控制器(在这种情况下是主要的中断控制器)向CPU发出定时器中断信号将不会允许任何相等或更低优先级的中断,直到CPU通过EOI指令告知定时器中断已完成(
outportb(0x20, 0x20)
for主中断控制器)。
您可以从技术上向PIC发出EOI指令,告诉它已完成IRQ0的处理,但您可能会为一些非常混乱的场景和竞争条件设置自己。
让中断处理程序只处理它们的特定中断并保存相关状态会更加清晰。然后,让您的主程序监视您需要的序列(例如计时器,然后是键盘)
以上是关于使用无限循环时,x86中断处理程序被阻止的主要内容,如果未能解决你的问题,请参考以下文章
因发布 JavaScript 无限循环代码,13岁女学生被捕!