【中断】自己写一个中断处理程序,需要注意哪些问题?

Linux中断知识汇总:

【深入理解Linux内核】【中断】内容汇总帖


目录

什么是中断处理程序?

注册中断处理程序

编写中断处理程序

编写中断处理程序的注意事项

为什么在中断里不可以睡眠?

为什么在中断里不可以使用耗时很长的函数?


什么是中断处理程序?

中断处理程序:在响应一个特定中断的时候,内核会执行一个函数,该函数叫做中断处理程序。产生中断的每一个设备都有一个相应的中断处理程序。中断处理程序是被内核调用来响应中断的,他们运行于中断上下文中,该上下文中的代码不可阻塞。

我们一般把中断处理分为两个部分。中断处理程序是上半部——接收到一个中断就立即开始执行,通常用于做有严格时限的工作。能够被允许稍后运行的工作会被推迟到下半部去。此后在合适的时机,下半部会被运行。


注册中断处理程序

int request_irq(unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id)

具体说明:
irq是要申请的硬件中断号。
handler是向系统注册的中断处理函数,是一个回调函数,中断发生时,系统调用这个函数,dev_id参数将被传递给它。
irqflags是中断处理的属性:
    若设置了IRQF_DISABLED (老版本中的SA_INTERRUPT,本版zhon已经不支持了),则表示中断处理程序是 快速处理程序,快速处理程序被调用时屏蔽所有中断,慢速处理程序不屏蔽;
    若设置了IRQF_SHARED (老版本中的SA_SHIRQ),则表示多个设备共享中断;
    若设置了IRQF_SAMPLE_RANDOM(老版本中的SA_SAMPLE_RANDOM),表示对系统熵有贡献,对系统获取随机数有好处。(这几个flag是可以通过或的方式同时使用的)
devname设置中断名称,通常是设备驱动程序的名称  在cat /proc/interrupts中可以看到此名称。
dev_id在中断共享时会用到,一般设置为这个设备的设备结构体或者NULL。

编写中断处理程序

static inqreturn_t intr_handler(int irq, void *dev)


具体说明:
第一个参数irq就是这个处理程序要响应的中断号。如今这个参数已经没什么用了,可能只是在打印日志信息时会用到。
第二个参数dev是一个通用指针,它在与中断处理程序注册时传递给request_irq的产生dev必须一致。dev可能指向中断处理程序使用的一个数据结构。
中断处理程序可能返回两个特殊的值:IRQ_NONE和IRQ_HANDLED。当不是在注册处理函数期间产生源,返回IRQ_NONE。当中断处理程序被正确调用,且确实是它所对应的设备产生了中断时,返回IRQ_HALDLED。
linux下的中断处理函数无需考虑重入,默认中断嵌套功能是不开启的。

编写中断处理程序的注意事项

  • 不可以执行耗时的任务】代码执行效率尽量高,代码一定要简洁,尽量少调用其他函数,尽量避免增加中断的执行时长,中断处理需要快进快出。
    1. 不可以使用耗时很长的函数,因为中断会关闭调度,中断的优先级高于任何任务的优先级,长时间的中断处理会影响到系统的响应速度,使整个系统的任务无法政策运行,造成很多的任务超时,容易导致很多不可预知的后果。【可以使用中断底半部解决】
    2. 对于一些必须的操作可以放在中断中处理,其他的以异步执行的方式,放到中断底半部中解决。
  • 不可以睡眠或者放弃CPU】中断处理程序中不可以睡眠,不可以使用可能引起睡眠的函数,也不可以使用可能会引起睡眠的锁。
    1. 不可以使用metux等引起休眠的锁。可以使用自旋锁,但必须保证自旋等待时间足够短。【可以使用自旋锁解决】
    2. 不可以使用会引起休眠的函数。比如ssleep(), msleep(), kmalloc, copy_to_user(), copy_from_user() 等。
  • 中断是不可重入函数】同一时刻同一中断只能在一个CPU上被触发,中断被响应后会被关闭该中断,相同的中断处理函数不能同时在多个处理器上运行。


为什么在中断里不可以睡眠?

从系统调度的角度来说,调度的触发方式有几种(主动触发、睡眠、唤醒、中断退出时的判断),而在进入中断之前,系统调度会被关闭。在调度函数schedule()中,也会首先判断是否在中断上下文,如果是则直接退出。此时一旦睡眠或者放弃CPU,这时内核无法调度别的进程来执行,系统就会死掉。


为什么在中断里不可以使用耗时很长的函数?

因为中断会关闭调度,中断的优先级高于任何任务的优先级,长时间的中断处理会影响到系统的响应速度,使整个系统的任务无法政策运行,造成很多的任务超时,容易导致很多不可预知的后果。【可以使用中断底半部解决】

 

首先需要定义一个计时器,比如使用定时器3(TIMER3)。在中断处理程序中启动计时器,设定定时时间,比如10毫秒。当中断处理程序完成后,停止计时器并记录耗时时间。如果耗时时间超过设定时间,则认为中断处理超时。 以下是示例代码: #include <avr/io.h> #include <avr/interrupt.h> volatile uint16_t interrupt_time = 0; // 中断处理时间计时器 volatile bool interrupt_timeout = false; // 中断处理超时标志 ISR(TIMER3_COMPA_vect) { interrupt_time++; // 每1毫秒计时器加1 } void init_interrupt_timeout() { // 初始化定时器3 TCCR3A = 0; TCCR3B = (1 << WGM32) | (1 << CS31) | (1 << CS30); // CTC模式,预分频64 OCR3A = 249; // 1毫秒计数 TIMSK3 = (1 << OCIE3A); // 允许定时器3比较匹配中断 interrupt_time = 0; interrupt_timeout = false; } void start_interrupt_timeout() { interrupt_time = 0; interrupt_timeout = false; TCNT3 = 0; // 定时器3计数器清零 sei(); // 开启中断 } void stop_interrupt_timeout() { cli(); // 关闭中断 if(interrupt_time > 10) // 超过10毫秒则认为中断处理超时 { interrupt_timeout = true; } } // 示例中断处理程序 ISR(INT0_vect) { start_interrupt_timeout(); // 中断处理程序代码 stop_interrupt_timeout(); } 在中断处理程序中调用start_interrupt_timeout()函数启动计时器,中断处理程序完成后调用stop_interrupt_timeout()函数停止计时器并检测中断处理是否超时。如果interrupt_timeout为true,则中断处理超时。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Evan_ZGYF丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值