【问题标题】:Context switching in function vs interrupt call? [closed]函数中的上下文切换与中断调用? [关闭]
【发布时间】:2014-09-25 03:41:07
【问题描述】:

我从下面的 SE 问题了解函数调用和中断 (ISR) 跳转之间的基本区别。

difference between function call & ISR

但是我仍然不清楚,在这两种情况下,哪些寄存器将被推入/弹出堆栈?在这两种情况下,上下文切换将如何发生?由于我们不知道什么时候会发生中断,所以在进入 ISR 之前我们需要保存什么(变量、PC、标志 (PSW)、寄存器、上下文)?

如何在多线程环境下恢复原始上下文而不会丢失任何数据。

【问题讨论】:

  • 这是高度依赖于平台的。对于 x86,指令指针和标志寄存器将被自动保存,但 ISR 必须保存/恢复其他寄存器。 ARM 使用专门用于中断的寄存器组。
  • 你的意思是每个中断都有单独的寄存器组吗?如果嵌套中断会发生什么?每次切换到新银行都会发生保存当前上下文?如果正常调用函数会发生什么?只保存指令指针和标志?
  • 很多时候,当一个CPU被中断时,它会自动禁用中断以防止嵌套中断。 ARM 的寄存器组尤其如此。至于函数调用,通常只保存指令指针(可能还有一些其他寄存器;同样,这取决于 CPU),而不是标志。
  • 在进入ISR时,我们需要禁用中断&返回时它会调用reti,所以它会再次启用中断。它是否正确?如果在服务低优先级中断时,如果高优先级中断来了,那么上下文切换或库切换会再次发生吗?我只是想确认一下我的理解。

标签: c linux multithreading interrupt-handling isr


【解决方案1】:

我试图用谷歌搜索它并从中找到了所需的信息:

  1. Interrupts
  2. Context Switch

感谢@Drew McGowen

所以总结一下,中断的一般顺序如下:

Foreground code is running, interrupts are enabled
Interrupt event sends an interrupt request to the CPU
After completing the current instruction(s), the CPU begins the interrupt response
automatically saves current program counter
automatically saves some status (depending on CPU)
jump to correct interrupt service routine for this request
ISR code saves any registers and flags it will modify
ISR services the interrupt and re-arms it if necessary
ISR code restores any saved registers and flags
ISR executes a return-from-interrupt instruction or sequence
return-from-interrupt instruction restores automatically-saved status
return-from-interrupt instruction recovers saved program counter
Foreground code continues to run from the point it responded to the interrupt

像往常一样,这个过程的细节将取决于 CPU 设计。许多设备使用硬件堆栈来保存所有保存的数据,但 RISC 设计通常将 PC 保存在寄存器(链接寄存器)中。许多设计还具有可用于中断处理的独立重复寄存器,从而减少了必须保存和恢复的状态数据量。

请注意,出于效率原因,保存和恢复前台代码状态通常是一个两步过程。硬件对中断的响应会自动保存最基本的状态,但 ISR 代码的第一行通常专门用于保存额外的状态(如果硬件不保存,通常以保存条件标志的形式,以及保存额外的寄存器)。使用这两个步骤的过程是因为每个 ISR 对其所需的寄存器数量有不同的要求,因此每个 ISR 可能需要保存不同的寄存器和不同数量的寄存器,以确保保存所有适当的状态数据而不会浪费时间不必要地保存寄存器(即保存未在 ISR 中修改的寄存器,因此不需要保存)。一个非常简单的 ISR 可能不需要使用任何寄存器,另一个 ISR 可能只需要使用一个或两个寄存器,而更复杂的 ISR 可能需要使用大量的寄存器。在任何情况下,ISR 都应该只保存和恢复它实际使用的那些寄存器。

【讨论】:

    【解决方案2】:

    我确信根据您使用的 CPU 会有不同的实现。在一般级别上,函数调用将输入参数存储在 SPARC 上的给定寄存器 (%o0-%o9) 中,并且在被调用函数的 (%i0-%i9) 寄存器中可用。被调用函数然后将返回值放在 %i0 寄存器中,以便在调用函数的 %o0 寄存器中可用。根据Sparc Manual,每个中断是:

    Accompanied by data, referred to as an “interrupt packet”. 
    An interrupt packet is 64 bytes long, consisting of eight 64-bit doublewords.
    

    根据this来源,你当前执行线程中的数据是:

       Saved either on a stack (PDP-11, VAX, MIPS, x86_64) 
       or in a single set of dedicated registers (ARM, PowerPC)
    

    上述来源还提到了在几种不同的架构上如何处理中断。

    如果您有任何问题,请告诉我!

    【讨论】:

    • 你的意思是在函数调用中,指令指针和参数将被推送到堆栈和其他一些寄存器?这些 (%o0-%o9) 寄存器是什么?在这两种情况下,银行切换是否有助于保存当前上下文?
    • 所以有一个栈和一个栈帧。一个堆栈帧。堆栈帧允许访问函数参数和自动函数变量。它会根据您当前所在的函数来滑动。整个基础是 %o 寄存器在调用函数时变为 %i 寄存器,然后在函数调用结束时滑回。这允许诸如按值传递、按引用传递、按引用返回等的事情;你可以在这里阅读更多内容:en.wikibooks.org/wiki/X86_Disassembly/….
    猜你喜欢
    • 1970-01-01
    • 2017-11-19
    • 2017-06-01
    • 2016-02-18
    • 1970-01-01
    • 1970-01-01
    • 2020-09-21
    • 2020-11-01
    • 2014-11-10
    相关资源
    最近更新 更多