第七章 中断和中断处理

    xiaoxiao2021-03-26  5

    什么是中断

    中断本质上是一种特殊的电信号,由硬件设备发向处理器,处理器接收到中断后,会马上向操作系统反应此信号到来。硬件设备产生中断的时候并不考虑处理器的时钟同步,因此中断是异步的,换句话说中断随时可能产生。

    什么是异常

    异常一般由处理器本身引起(异常是同步中断),比如运算中的除0操作。

    中断处理程序——中断上下文、原子上下文

    中断处理程序与其他内核函数的真正区别在于,中断处理程序是被内核调用来相应中断的,而它们运行于我们称之为中断上下文的特殊上下文中,中断上下文偶尔也被称作原子上下文。

    上半部和下半部

    中断可能随时发生,因此中断处理程序也就随时可能执行,所以必须保证中断处理程序能够快速执行,这样才能保证尽快恢复被中断代码的执行。因此,对硬件而言,操作系统能够迅速对其中断进行服务非常重要;当然对于系统的其它部分而言,让中断处理程序在尽可能短的时间内完成也同样重要。 又想中断处理的快,同时也想在中断处理程序中完成的工作量多该如何处理?两者显然相抵触,所以我们一般把中断切为两部分。中断处理程序是上半部(top half)——接收到一个中断它就立刻执行,但只做严格时限的工作。能够被允许稍后完成的工作会推迟到下半部(bottom half)去,在合适的时机,下半部会执行。

    中断相关函数

    注册中断

    /* * irg - 表示要分配的中断号 * handler - 实际的中断处理程序 * flags - 标志位,表示此中断的具有特性 * name - 中断设备名称的ASCII 表示,这些会被/proc/irq和/proc/interrupts文件使用 * dev - 用于共享中断线,多个中断程序共享一个中断线时(共用一个中断号),依靠dev来区别各个中断程序 * 返回值: * 执行成功:0 * 执行失败:非0 */ int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char* name, void *dev)

    注意: request_irq()函数可能会睡眠(根本原因是调用了kmalloc(),kmalloc()是可以睡眠的),绝不能再中断上下文或其它不允许阻塞的代码中调用该函数。

    释放中断

    void free_irq(unsigned int irq, void *dev) 如果不是共享中断线,则直接删除irq对应的中断线。如果是共享中断线,则判断此中断处理程序是否中断线上的最后一个中断处理程序, 是最后一个中断处理程序 -> 删除中断线和中断处理程序不是最后一个中断处理程序 -> 删除中断处理程序

    重入和中断处理程序

    Linux 中的中断处理程序是无须重入的。当一个给定的中断处理程序正在执行时,相应的中断线在所有的处理器上都会被屏蔽掉,以防止在同一个中断线上接收另一个新的中断。通常情况下,所有的其他的中断都是打开的,所以这些不同中断线上的其它中断都能被处理,但是当前中断线总是被禁止的。由此可见,同一个中断处理程序绝对不会被同时调用以处理嵌套的中断,简化了中断处理程序的编写。

    禁止中断

    禁止本处理器上的全部中断

    local_irq_disable() local_irq_enable()

    以上两个函数会无条件的禁止和使能中断,如果本身中断已经禁止,可能会带来潜在的危险。下面这两个函数会更安全一些。

    unsigned long flags; local_irq_save(flags);//禁止中断,保存状态 local_irq_restore(flags);//恢复状态

    注意: flags 为 unsigned long 类型,不能传递给另一个函数, local_irq_save(flags);local_irq_restore(flags);必须成对的在同一个函数中运行,它们既可以在中断上下文使用,也可以在进程上下文使用。

    禁止指定的中断线

    void disable_irq(unsigned int irq) void disable_irq_nosync(unsigned int irq) void enable_irq(unsigned int irq) void synchronize_irq(unsigned int irq)

    disable_irq()只有在相应的中断处理程序完成后才能返回,如果在当前中断线的处理程序中使用disable_irq()来关闭当前中断线,一方面没必要,第二也会造成内核死掉。 disable_irq_nosync()不会等待对应的中断处理程序执行完毕就返回。 关闭中断和使能中断最好成对的使用,如果你连续两次调用禁止中断,那么你必须也得同样调用两次使能中断才能真正的使能。

    void disable_irq(unsigned int irq) void disable_irq_nosync(unsigned int irq) void enable_irq(unsigned int irq) 以上三个函数可以在中断上下文和进程上下文中使用

    void synchronize_irq(unsigned int irq) 会休眠等待,因此不能用在中断上下文和任何不允许阻塞的上下文中。

    中断系统状态

    in_interrupt() 是判断当前内核是否处于中断上下文,这个中断上下文包括底半部和硬件中断处理过程,函数实现:

    #define in_interrupt() ({ const int __cpu = smp_processor_id(); / (local_irq_count(__cpu) + local_bh_count(__cpu) != 0); })

    判断中断计数和底半部计数是否〉0,如果只希望判断是否在硬件中断上下文,则可以使用:in_irq()。

    转载请注明原文地址: https://ju.6miu.com/read-650159.html

    最新回复(0)