内核中断处理

本文介绍了中断处理的概念,包括异步中断与同步中断的区别。中断服务程序在中断上下文中运行,不能阻塞且需要迅速执行。在中断上下文中,不能使用mutex,通常使用自旋锁,且不能直接与用户空间交互。注册中断处理函数使用request_irq(),并讨论了不同的中断处理函数标记。文章还提到了禁止、启用中断的方法以及中断处理器的返回值含义。最后,建议在设备打开时请求中断,在关闭时释放。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

中断又叫异步中断,由硬件触发。而异常又称为同步中断,由软件触发。

中断服务程序(中断处理函数)是一种处理中断响应的函数,它是一种遵循特定原型声明的C函数,它运行在中断上下文中,也称为原子上下文,代码运行在此上下文中是不能被阻塞的。中断服务程序必须运行非常快,它最基本的工作就是告诉硬件已经收到了它发出的中断,但通常还执行大量其他的工作。为此,一般中断服务程序分为两半,一半是中数据恢复处理函数,称为上半部,它只执行那些可以很快执行的代码,如向硬件确认已经收到中断号等,其他的工作要延迟到下半部去执行。

执行在中断上下文中的代码需要注意的一些事项:

  • 中断上下文中的代码不能进入休眠。

  • 不能使用mutex,只能使用自旋锁,且仅当必须时。

  • 中断处理函数不能直接与用户空间进行数据交换。

  • 中断处理程序应该尽快结束。

  • 中断处理程序不需要是可重入的,因为相同的中断处理函数不能同时在多个处理器上运行。

  • 中断处理程序可能被一个优先级更高的中断处理程序所中断。为了避免这种情况,可以要求内核将中断处理程序标记为一个快速中断处理程序(将本地CPU上的所有中断禁用),不过在采取这个动作前要慎重考虑对系统的影响。

注册中断处理函数

Linux中,注册一个中断处理函数使用request_irq(),原型为:

/* request_irq: allocate a given interrupt line */ 
int request_irq(unsigned int irq, //中断号
irq_handler_t handler, //中断处理函数
unsigned long flags, 
const char *name, 
void *dev) 

第一个参数表示要分配的中断号,第二个参数是一个指向实际中断处理程序的指针。

第三个参数irqflags值可为0第四个参数设备名,第五个参数主要用于共享中断线

中断处理函数原型为:

typedefirqreturn_t (*irq_handler_t)(int, void *)

中断处理函数的一些标记

  • IRQF_DISABLED:禁用其他所有的中断,该标志用于性能好且执行快的中断处理函数。该标志也表明中断处理函数为一个快速中断处理函数。

  • IRQF_SAMPLE_RANDOM:设备产生的中断对内核熵池有贡献。如果设备以一个可预测的速率引发中断,不要使用该标志。

  • IRQF_TIMER:表明该中断处理函数为系统计时器中断处理函数。

  • IRQF_SHARED:表明该中断号是共享的。

  • IRQF_TRIGGER_RISING:边沿触发。

  • IRQF_TRIGGER_HIGH:水平触发。

例子:

#define ROLLER_IRQ 7
static irqreturn_t roller_interrupt(int irq, void *dev_id);

if (request_irq(ROLLER_IRQ, roller_interrupt, IRQF_DISABLED | IRQF_TRIGGER_RISING, “roll”, NULL);
{
	printk(KERN_ERR  “Roll: Can’t register IRQ %d\n”, ROLLER_IRQ);
	return –EIO;
}

释放一个中断处理函数

void free_irq(unsigned int irq, void *dev)

编写中断处理器

static irqreturn_t intr_handler(int irq, void *dev)

中断处理器的返回值的类型为irqreturn_t。中断处理器可以返回两个特殊值IRQ_HANDLEDIRQ_NONE。也可以使用IRQ_RETVAL(val)。通常中断处理器标记为static,表明它不能在其他的文件中被调用。


中断控制

禁止和使能中断

local_irq_disable();
/* interrupts are disabled .. */
local_irq_enable();

更安全的版本:

unsigned long flags;
local_irq_save(flags); /* interrupts are now disabled */
/* ... */
local_irq_restore(flags); /* interrupts are restored to their previous state */

注意: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_nosync()会立即返回。函数synchronize_irq()在返回前等待某个特定的中断处理器退出。

中断系统的状态

irqs_disabled()函数返回0,如果本地处理器上的中断系统禁用的话。

有两个宏检查当前的上下文状态

函数in_interrupt()用于决断此时代码执行的上下文是否处理中断上下文。

in_irq()仅当内核正在执行一个中断处理函数时才返回非0

设备初始化处不适合请求IRQ在打开设备时请求IRQ比较合宜。关闭设备时释放中断。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值