1、为什么要引入中断底半部?(*)
由于中断顶半部(中断处理函数)中不允许出现延时、耗时操作,可是出现特殊情况时又需要在终端中出现相对的延时操作,所以我们引入中断底半部;
2、实现机制(3个)
2.1、软中断
存在最大个数限制(32个),一般留给内核开发者使用
2.2、tasklet
tasklet是基于软中断实现的,特点与软中断差不多。
但也存在区别:
1、没有最大个数限制
2、只能使用在中断中(属于中断的一部分),不能使用在进程的上下文中
3、tasklet中可以存在相对耗时的操作,但是不能出现延时、休眠操作
2.3、工作队列
工作队列本质上就是一个events线程,在内核成功启动后它也默认启动,默认状态是休眠,在我们需要使用它时,可以将它唤醒。
注:
1、工作队列可以使用在中断中,也可以使用在进程的上下文中
2、工作队列使用时可以存在延时操作
3、相关API
3.1、tasklet
1、定义tasklet对象
1.分配tasklet对象
struct tasklet_struct
{struct tasklet_struct *next;//tasklet对象链表中下一个节点的地址unsigned long state;//是否执行底半部的状态标志位atomic_t count;//底半部被触发的此时bool use_callback;//true使用callbacck函数,false使用func函数 union {void (*func)(unsigned long data);void (*callback)(struct tasklet_struct *t);};unsigned long data;//使用func回调时向回调函数中传递的参数
};
struct tasklet_struct tasklet;
2、初始化tasklet对象
2.初始化tasklet对象
void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data)void tasklet_setup(struct tasklet_struct *t,void (*callback)(struct tasklet_struct *))
注:为什么tasklet有两个初始化函数?
由于在tasklet_struct结构体中存在一个bool类型的函数use_callback,当true时使用callbacck函数,false时使用func函数
3、开启tasklet中断底半部
3.开启底半部
void tasklet_schedule(struct tasklet_struct *t)
3.2工作队列
1、定义工作队列对象
1.分配对象
struct work_struct {atomic_long_t data;//用来进行数据传输的变量struct list_head entry;//构成链式队列work_func_t func;//底半部处理函数的函数指针//typedef void (*work_func_t)(struct work_struct *work);};
struct work_struct work;
2、初始化工作队列对象
2.对象初始化
void work_func(struct work_struct *work){}
INIT_WORK(&work, work_func);
3、开始工作队列中断底半部
3.开启底半部函数bool schedule_work(struct work_struct *work)