Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 使用无限循环时,x86中断处理程序被阻止_C_Assembly_X86 - Fatal编程技术网

C 使用无限循环时,x86中断处理程序被阻止

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

我正在努力学习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 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状态缓慢阻塞堆栈内存,并且它将永远不会返回到底部的原始线程(无限线程)