linux中断处理上下部分

Linux中断处理为什么需要分为上下部分?

linux中断处理不参与调度,所以中断处理事件过长会影响实时性;

中断处理函数(ISR)运行事件应尽可能短,但有些处理不可能再很短时间内处理完成,于是linux内核提供中断处理上下部。

 

Linux 中断处理上下部含义

中断处理的上半部(top half ,又叫顶半部);中断处理的下半部(bottom half , 又叫底半部);上半部指的是中断处理程序,下半部则是指一些虽然与中断有相关性但是可以延后执行的任务。例如:在网络传输中,网卡接收到数据包这个事件不一定需要马上被处理,这就适合放在下半部分去实现;而用户敲击键盘这样的事件就必须马上被响应,这个中断处理就必须放在中断的上半部去实现。具体的区分规则如下:

1、如果一个任务对时间非常敏感,将其放在中断处理程序中执行

2、如果一个任务和硬件相关,将其放在中断处理程序中执行

3、如果一个任务保证不被其他中断(特别是相同的中断)打断,将其放在中断处理程序中执行

4、其他所有任务,考虑放在下半部分执行

 

中断处理上下部的三种实现机制

软中断

tasklet 机制

workqueue 机制

 

软中断

软中断是下半部机制的代表,是随着SMP的出现应运而生的,它也是tasklet实现的基础 。它的出现就是因为要满足上面所提出的上半部和下半部的区别,使得对时间不敏感的任务延后执行,而且可以在多个cpu上并行执行,使得总的系统效率更高,它的特征包括:

1、产生后并不是马上可以执行,必须要等待内核的调度才能执行。软中断不能被自己打断(即单个cpu上软中断不能嵌套执行),只能被硬件中断打断(上半部)。

2、可以并发运行在多个cpu上(即使同一类型的也可以),所以软中断必须设计为可重入的函数(允许多个cpu同时操作),因此也需要使用自旋锁来保证其数据结构。

 

tasklet机制

tasklet机制是一种比较特殊的软中断,tasklet一词的原意为“小片任务”的意思,这里是指一小段可以执行的代码,且通常是以函数的形式出现,这个tasklet绑定的函数在一个时刻只能在一个cpu上运行,在smp系统上不会出现问题。

tasklet机制编程步骤:

1、编写tasklet结构中的绑定函数

void tasklet_func(unsigned long data){

...

}

2、定义tasklet结构

第一种使用静态定义:(定义出的tasklet能被调度)

DECLARE_TASKLET(mytasklet,tasklet_func,123);

第二种使用静态定义:(定义出的tasklet不能被调度)

DECLARE_TASKLET_DISABLE(mytasklet,tasklet_func,123);

第三种动态定义:一般在模块初始化时候

1)先定义一个变量

struct tasklet_struct mytasklet;

2) 对这个变量进行初始化,如果是静态定义结构体,略过这一步

tasklet_init(&mytasklet,tasklet_func,123);

3、初始化tasklet结构

根据想要实现的功能,需要在什么情况下调用到绑定的函数,就在哪里调用tasklet_schedule函数进行调度

tasklet_schedule(&mytasklet);

4、在适当的地方进行调度

如果中途不想使用tasklet,则可以删除它。

tasklet_kill(&mytasklet)一般情况在模块卸载函数中编写。

注意:tasklet 和 软中断都是运行在中断上下文中,因此tasklet 和 软中断实现得中断下部不能阻塞和睡眠。

工作队列

工作队列(work queue)是一种将工作推后执行的机制,它和之前的tasklet不同的是,工作队列可以把工作推后 ,交由一个内核线程去执行,也就是说这个中断下半部分可以在进程上下文中执行,这样,通过工作队列执行的代码就能占尽进程上下文的所有优点,最重要的就是工作队列允许被重新调度甚至睡眠。

工作队列使用步骤:

1、声明编写一个工作处理函数和一个工作队列

void my_func();

struct workqueue_struct *p_queue = create_singlethread_workqueue("p_queue");

2、创建一个工作结构体变量并初始化

struct work_struct my_work;

INIT_WORK(&my_work,my_func);

3、将工作添加到自己创建的工作队列等待执行

queue_work(p_queue,&my_work); //将my_work 添加到p_queue中等待执行

4、删除自己的工作队列

destroy_workqueue(p_queue);

 

工作队列和tasklet的选择

如果推后执行的任务需要睡眠,那么就选择工作队列,如果推后执行的任务不需要睡眠,那么就选择tasklet。

如果需要用一个可以重新调度的实体来执行你的下半部处理,也应该使用工作队列。它是唯一能在进程上下文运行的下半部实现的机制,也只有它才可以睡眠。

当需要获得大量的内存,需要获取信号量、需要执行阻塞式的I/O操作时。都需要选择使用工作队列。

 

总结:尽量少用tasklet,多用workqueue。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值