当用户进程需要访问设备或者使用操作系统内核时,必须通过系统调用来完成。系统调用将CPU切换到保护模式,随后访问内核的地址空间,在保护模式下,所有设备和内存资源通过内核实现API访问。
中断优先级:
硬件中断可以打断其他所有的中断(软件中断,tasklet,bottom half)。系统调用和进程可以被上述所有打断。
硬件中断
硬件中断是一种系统资源,当我们为设备编写中断处理程序来处理外部事件时,要向系统申请中断资源(即硬件中断信号线,通常称为中断号),并将中断处理程序与中断源关联。内核提供接口:
int request_irq( unsigned int irq, irq_handler_t handler, unsigned long flags, const char* devname, void* dev_id )
函数request_irq申请中断号为irq的资源,将申请到的中断号irq与设备名为devname,设备索引为dev_id的设备中断处理程序handler关联,设备的中断类型为flags。
int free_irq( unsigned int irq, void *dev_id )
free_irq释放中断资源
flags的类型
1. 快速中断
中断运行时间非常短,不会被其他中断打断,flags设为SA_INTERRUPT。
2. 慢速中断
执行时间较长,可以被其他中断打断。
3. top half和bottom half
top half只完成硬件中断触发后的最重要的任务处理,top half 即对应中断处理程序。
bottom half完成所有非紧急的中断处理,如网络数据包复制到内核由top half完成,而之后的分析处理由bottom half完成。
top half和bottom half最大的区别就是,在bottom half执行期间,打开所有的硬件中断。由top half将设备缓冲区的数据复制到内核地址空间缓冲区,调用bottom half后退出,这个过程非常快。bottom half 会执行剩下的操作,此时CPU可以响应外部中断请求。linux通过tasklet和workqueue来实现bottom half。
tasklet
tasklet是可以被调度执行的特殊函数,在系统某个特定的安全时间运行在软件中断现场。
由函数tasklet_schedule( struct tasklet_struct *t )调度执行,一个tasklet只执行一次。
static inline void tasklet_schedule( struct tasklet_struct *t )
一个CPU上只能执行一个
不同tasklet可以在不同CPU上执行
tasklet的实现:
编写tasklet处理函数->用宏DECLARE_TASKLET声明一个新的tasklet->用task_schedule调度tasklet执行。
void my_func( unsigned long );
char tasklet_data[] = "This is a new tasklet.";
DECLARE_TASKLET( my_tasklet, my_func, ( unsigned long )&tasklet_data );
void my_func( unsigned long data )
{
return;
}
tasklet_schedule( &my_tasklet );
workqueue
- tasklet在软件中断现场执行,是原子操作。workqueue函数在内核进程现场执行,可以休眠。
- tasklet总是在最初调度它的处理器上执行。默认情况下workqueue与tasklet一样。
- 内核可以将workqueue推迟一段时间执行。
软件中断
硬件中断可以立即打断CPU现场活动,而软件中断需要CPU调度。软件中断的调度由内核函数do_softirq完成。
asmlinkage void do_softirq(void)
软件中断的处理在do_softirq中执行,软件中断的执行时间:
- 系统调度结束后被调度执行
- 硬件调度结束后被调度执行
网络子系统使用的中断:
- NET_RX_SOFTIRQ
- NET_TX_SOFTIRQ
软件中断最重要的特性:
- 可以在多个处理器上运行,所以编写软件中断时,必须考虑重入问题。如果需要访问共享全局变量,必须采用锁机制执行并发访问。
- 软件中断不能被同类的软件中断打断。
- 只能被硬件中断打断。
网友评论