Linux 将中断处理例程分为顶半部和底半部的原因是:为了解决在中断处理例程中既要完成
一定数量耗时的任务又要避免使中断阻塞的时间过长。
- 顶半部是用request_irq注册的中断例程,是在中断上下文中运行的实际响应中断的例程。
- 底半部是被顶半部调度的并在稍后的某个时间点上运行在非中断上下文中运行的例程。
典型的情况是:
顶半部保存设备的数据到一个设备特定的缓冲区中并调度它的底半部后退出。
底半部执行其它必要的处理,比如:唤醒进程,启动另外的I/O等。
例如:当网卡中断产生时,网卡中断的顶半部仅接收和保存网络数据,并在调度它的底半部后退出。
在网卡中断的底半部中执行网络数据的协议处理工作。
在Linux中有两种机制可以用来实现底半部:tasklet 和 workqueue 。
- tasklet 机制速度快,但要求所有的代码必须是原子的。
- workqueue 机制可以允许高延迟、允许休眠。
tasklet:
- 是由系统在某个时刻调度运行在软中断上下文中的特殊函数。
- 可以多次调度,但是多次调度不会累积
- 不同的tasklet可以在SMP上同时运行
- tasklet_schedule是tasklet的调度函数
workqueue:
- 是由系统在某个时刻在工作者进程上下文中调用的一个函数。
- 由于是在进程上下文中运行,故可以休眠
- 不能向用户空间复制数据,因为工作者进程不能访问其它进程的地址空间
- schedule_work是workqueue的调度函数