中断的上下半部

来源:互联网 发布:淘宝历史最低价 编辑:程序博客网 时间:2024/05/07 23:13

以下内容源于朱有鹏《物联网大讲堂》课程的学习,如有侵权,请告知删除。


因为输入类设备的输入都是异步事件,因此一般使用中断来处理和响应。


1、中断处理的注意点

  • 中断处理程序处于中断上下文中,不能和用户空间数据交互(不能使用copy_to(from)_usr函数);
  • 中断处理程序不能交出CPU(不能休眠、不能schedule);
  • ISR运行时间尽可能短,越长则系统响应特性越差。

2、中断下半部2种解决方案

当中断处理程序比较长,而又希望优良的响应特性时,linux内核处理中断的方案是:人为地将处理程序分为两部分。

(1)为什么要分上半部(top half,又叫顶半部)和下半部(bottom half,又叫底半部)?

  • 上半部标记中断,调度下半部;下半部负责真正的操作(如读取按键键值、从网卡读取缓冲数据等)。


(2)下半部处理策略1:tasklet(小任务)

  • 引入tasklet,最主要的是考虑支持SMP,提高SMP多个cpu的利用率;不同的tasklet可以在不同的cpu上运行。但是tasklet属于中断上下文,因此不能被阻塞,不能睡眠,不可被打断。 

(3)下半部处理策略2:workqueue(工作队列)

  • workqueue的突出特点是下半部会交给worker thead,因此下半部处于进程上下文,可以被重新调度,可以阻塞,也可以睡眠。
  • workqueue的初始化方式有静态和动态两种。 
  • 静态初始化:调用宏DECLARE_WORK,初始化一个中断的上半部,然后在中断上半部调用schedule_work()启动我们的中断下半部 
  • 动态初始化:调用宏 INIT_WORK,初始化一个中断的上半部,然后在中断上半部调用queue_work()启动我们的中断下半部 

3、tasklet使用实战

(1)tasklet相关接口介绍

(2)实战演示tasklet实现下半部

原程序:

static irqreturn_t button_interrupt(int irq, void *dummy) { int flag;s3c_gpio_cfgpin(S5PV210_GPH0(2), S3C_GPIO_SFN(0x0));// input模式flag = gpio_get_value(S5PV210_GPH0(2));s3c_gpio_cfgpin(S5PV210_GPH0(2), S3C_GPIO_SFN(0x0f));// eint2模式input_report_key(button_dev, KEY_LEFT, !flag);input_sync(button_dev);return IRQ_HANDLED; }

使用方案的策略:




4、workqueue实战演示

(1)workqueue的突出特点

  • 下半部会交给worker thead,因此下半部处于进程上下文,可以被调度,因此可以睡眠

(2)include/linux/workqueue.h



5、中断上下半部处理原则

(1)必须立即进行紧急处理极少量任务放入在中断的顶半部中

  • 此时屏蔽了与自己同类型的中断,由于任务量少,所以可以迅速不受打扰地处理完紧急任务(除非优先级比自己高,被抢占了)。

(2)需要较少时间的中等数量的急迫任务放在tasklet中

  • 此时不会屏蔽任何中断(包括与自己的顶半部同类型的中断),所以不影响顶半部对紧急事务的处理;
  • 同时又不会进行用户进程调度,从而保证了自己急迫任务得以迅速完成。

(3)需要较多时间且并不急迫(允许被操作系统剥夺运行权)的大量任务放在workqueue中

  • 此时操作系统会尽量快速处理完这个任务,但如果任务量太大,期间操作系统也会有机会调度别的用户进程运行,从而保证不会因为这个任务需要运行时间将其它用户进程无法进行。

(4)可能引起睡眠的任务放在workqueue中

  • 因为在workqueue中睡眠是安全的。在需要获得大量的内存时、在需要获取信号量时,在需要执行阻塞式的I/O操作时,用workqueue很合适。




阅读全文
0 0