C 使用无限循环时,x86中断处理程序被阻止
我正在努力学习x86汇编语言和c语言。现在我已经完成了一个简单的计时器和键盘中断。第一个可以每隔几格打印一行,第二个可以打印您在键盘上按下的内容。代码如下: Timer.c:C 使用无限循环时,x86中断处理程序被阻止,c,assembly,x86,C,Assembly,X86,我正在努力学习x86汇编语言和c语言。现在我已经完成了一个简单的计时器和键盘中断。第一个可以每隔几格打印一行,第二个可以打印您在键盘上按下的内容。代码如下: Timer.c: print(); return; print(); return; while(1); sti(); //set IF to 1 to enable interrupt print(); while(1); // wait here to test if the keyboard interrupt ca
print();
return;
print();
return;
while(1);
sti(); //set IF to 1 to enable interrupt
print();
while(1); // wait here to test if the keyboard interrupt can occur
return;
print();
return;
while(1);
键盘。c:
print();
return;
print();
return;
while(1);
sti(); //set IF to 1 to enable interrupt
print();
while(1); // wait here to test if the keyboard interrupt can occur
return;
print();
return;
while(1);
main.c:
print();
return;
print();
return;
while(1);
sti(); //set IF to 1 to enable interrupt
print();
while(1); // wait here to test if the keyboard interrupt can occur
return;
print();
return;
while(1);
这两个处理程序位于IDT中。因此,当中断发生时,IF标志被清除。CPU将忽略其他中断。
在初始化了主函数中的所有配置之后,我用一个无限循环完成了它,就像:while(1)
。
好的,这很好,我可以在屏幕上看到这两个处理程序工作。但是,当我想使其成为嵌套中断时,我做了以下事情: Timer.c:
print();
return;
print();
return;
while(1);
sti(); //set IF to 1 to enable interrupt
print();
while(1); // wait here to test if the keyboard interrupt can occur
return;
print();
return;
while(1);
键盘。c:
print();
return;
print();
return;
while(1);
sti(); //set IF to 1 to enable interrupt
print();
while(1); // wait here to test if the keyboard interrupt can occur
return;
print();
return;
while(1);
main.c:
print();
return;
print();
return;
while(1);
sti(); //set IF to 1 to enable interrupt
print();
while(1); // wait here to test if the keyboard interrupt can occur
return;
print();
return;
while(1);
接下来发生的事情让我非常困惑:使用Bochs,我可以看到我的程序只是在timer.c中执行while循环。在这一刻,我检查了标志,它显示,如果标志已经设置,但当我试图键入一些东西来测试另一个中断时,它失败了。似乎所有的中断都被屏蔽或忽略了
问题是,这两个循环之间有什么区别,一个只是在一个中断处理程序中,而且,我不知道如何解决这个问题。我在vmware和virtualbox中仔细检查了我的代码,但结果是一样的
我知道这个问题一定是在我遇到它之前发生的,但是,我找不到任何与这个问题相关的东西。通过在中断处理程序中启用中断,您不仅启用了“其他”中断,而且启用了所有中断。包括定时器中断。 (payne在评论中指出,这太笼统了,在x86上可能有不同的IRQ信号源,特定的PIC/APIC芯片可以配置为优先于其他芯片……这不会改变重入式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状态存储在堆栈中(无论是在main中,还是在计时器或键盘中,都无关紧要),CPU将切换到所需的中断处理程序。因此,如果您发出IRQ的速度快于处理程序完成并返回到以前的代码,那么您将使用存储的CPU状态缓慢阻塞堆栈内存,并且它将永远不会返回到底部的原始线程(main中的无限循环).通过在中断处理程序中启用中断,不仅可以启用“其他”中断,还可以启用所有中断。包括计时器中断。
(payne在评论中指出,这太笼统了,在x86上可能有不同的IRQ信号源,特定的PIC/APIC芯片可以配置为优先于其他芯片……这不会改变重入式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状态存储在堆栈中(无论是在main中,还是在计时器或键盘中,都无关紧要),CPU将切换到所需的中断处理程序。因此,如果您发出IRQ的速度快于处理程序完成并返回到以前的代码,那么您将使用存储的CPU状态缓慢阻塞堆栈内存,并且它将永远不会返回到底部的原始线程(无限线程)