Linux 中断之中断控制

版权声明:原创文章 && 转载请著名出处 https://blog.csdn.net/zhoutaopower/article/details/86524397

中断使能/禁止


IRQ 的控制在内核代码很多地方都有使用,主要是中断的禁止和使能的几组函数:

  • local_irq_enable()
  • local_irq_disable()

这两个通常以单个汇编指令实现,用于禁止/使能当前处理器的本地中断。

针对 ARM 处理器:

include/linux/irqflags.h

arch/arm/include/asm/irqflags.h

#define raw_local_irq_disable()		arch_local_irq_disable()
#define raw_local_irq_enable()		arch_local_irq_enable()

#define local_irq_enable()	do { raw_local_irq_enable(); } while (0)
#define local_irq_disable()	do { raw_local_irq_disable(); } while (0)

#define arch_local_irq_enable arch_local_irq_enable
static inline void arch_local_irq_enable(void)
{
	asm volatile(
		"	cpsie i			@ arch_local_irq_enable"
		:
		:
		: "memory", "cc");
}

#define arch_local_irq_disable arch_local_irq_disable
static inline void arch_local_irq_disable(void)
{
	asm volatile(
		"	cpsid i			@ arch_local_irq_disable"
		:
		:
		: "memory", "cc");
}

还有两个常用到的:

  • local_irq_save(flags)
  • local_irq_restore(flags)

这两个宏相对于local_irq_disable和local_irq_enable最大的区别在于,local_irq_save会在关闭中断前,将处理器当前的标志位保持在一个unsigned long flags中,在调用local_irq_restore时,在将保存的flags恢复到处理器的 flags 寄存器中。这样做是为了防止在一个关闭中断的环境中因为调用local_irq_disable和local_irq_enable破坏之前的中断响应状态。

注意:前面的调用,既可以在中断上下文中调用,也可以在进程上下文调用。

local_irq_enable() / local_irq_disable() / local_irq_save(flags) / local_irq_restore(flags)

扫描二维码关注公众号,回复: 5041250 查看本文章

禁止的是处理器的全局的中断,即全部禁止,如果希望禁止一条特定的中断(也就是 Mask 一个),则使用:

  • void disable_irq(unsigned int irq)
  • void enable_irq(unsigned int irq)

或者

  • void disable_irq_nosync(unsigned int irq)
  • void synchronize_irq(unsigned int irq)

他们可以禁止给定的中断向所有的处理器的传递。

disable_irq 的官方解释是:

This function waits for any pending IRQ handlers for this interrupt to complete before returning. If you use this function while holding a resource the IRQ handler may need you will deadlock. This function may be called - with care - from IRQ context

它需要等待被 pending 上的 IRQ 被处理完,才会返回!所以,官方给的说法是:“小心使用,否则死锁!”

如果在 IRQ Context 中使用这个,会导致死锁,死机,最后CPU 重启。

disable_irq_nosync 的官方解释是:

Unlike disable_irq(), this function does not ensure existing instances of the IRQ handler have completed before returning. This function may be called from IRQ context.

和 disable_irq 不一样,这个直接返回,所以能够在中断上下文调用。

enable_irq 是开启一条中断的 API,的官方解释是:

Undoes the effect of one call to disable_irq().  If this matches the last disable, processing of interrupts on this IRQ line is re-enabled. This function may be called from IRQ context only when desc->irq_data.chip->bus_lock and desc->chip->bus_sync_unlock are NULL !

有条件的在中断上下文使用,这里强调了一下,和 disable_irq 配对使用,什么意思呢?

比如你调用了 2 次 disable_irq() 或者 disable_irq_nosync() ,则下一次调用 enable_irq() 的时候,对应的中断并不会打开,需要在调用一次才行,也就是需要的嵌套配对。

synchronize_irq 也是开启一条中断的 API,的官方解释是:

This function waits for any pending IRQ handlers for this interrupt to complete before returning. If you use this function while holding a resource the IRQ handler may need you will deadlock. This function may be called - with care - from IRQ context.

所以,也是有等待的过程,所以中断上下文慎用!!

中断状态


irqs_disabled() 用于检测当前本地中断是否被禁止,若被禁止,返回非0,否则返回0

in_interrupt() 用来检测当前是否在中断上下文(很常用),若在中断上下文(或者在执行下半部),返回非0,否则返回0

如果代码希望做一些像睡眠这样的事情,可以调用这个函数,返回0,则说明是进程上下文。

猜你喜欢

转载自blog.csdn.net/zhoutaopower/article/details/86524397