中断
中断的顶半部(中断的上文)
中断的上文就是普通的中断服务函数
中断的底半部(中断的下文)
如果中断服务函数里面需要写很多东西,甚至还需要有延迟。但是肯定不能直接写在中断服务函数中,否则就违背了中断快进快出的原则。中断的下半部就相当于另开一个线程。在另一个线程中操作,延时、阻塞…都不影响中断的快进快出原则。
中断底半部的实现方法
中断底半部的实现方法有两种:
1、小任务
2、工作队列
小任务
小任务API
核心结构体:
struct tasklet_struct
{
struct tasklet_struct *next;//下一个小任务
unsigned long state;//当前这个tasklet是否已经被调度(状态描述)
atomic_t count;//值为1表示用户不可调度,值为0表示用户可调度
void (*func)(unsigned long);//小任务入口函数
unsigned long data;//传递给小任务入口函数的参数
}
静态创建:
//静态创建且使能
DECLARE_TASKLET(name, func, data)
name :变量的名字
func : 函数指针
data : 传给函数指针的参数
//静态创建且失能
DECLARE_TASKLET_DISABLED(name, func, data)
动态创建:
函数功能:动态创建一个队列核心结构体
函数头文件:<linux/interrupt.h>
函数原型:
void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data);
函数参数:
t :结构体变量
*func :函数指针
data :传给函数的参数
使能tasklet小任务:
使能该小任务的结构体,可以直接把结构体内部count = 0
也可以使用如下函数:
函数功能:使能核心结构体
函数头文件:<linux/interrupt.h>
函数原型:
void tasklet_enable(struct tasklet_struct *t)
函数参数:
传入工作队列的核心结构体
函数返回值:
无
调用该小任务:
找个合适的地方和时间调度该工作队列,比如说中断服务函数,这个时候我们调度该工作队列
函数功能:调度工作队列
函数头文件:<linux/interrupt.h>
函数原型:
void tasklet_schedule(struct tasklet_struct *t)
函数参数:
传入工作队列的核心结构体
函数返回值:
无
禁止调度(失能):
功能:禁止某个指定的tasklet小任务,禁止后这个小任务不能被调用,这个实际上是把count值加1
函数头文件:<linux/interrupt.h>
void tasklet_disable(struct tasklet_struct *t)
参数:t:tasklet结构指针
返回值:无
取消tasklet任务:
功能:将一个已经被调度了的tasklet杀死,即将其恢复到未调度的状态
函数头文件:<linux/interrupt.h>
void tasklet_kill(struct tasklet_struct *t);
参数:t:tasklet结构指针
返回值:无
使用流程:
工作队列
核心结构体:
struct work_struct {
atomic_long_t data;
struct list_head entry;
work_func_t func;//工作队列入口函数
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
typedef void (*work_func_t)(struct work_struct *work);//工作队列入口函数
工作队列创建:
静态:
DECLARE_WORK(n,f);
n:name 名字
f:函数指针
动态:
INIT_WORK(* n,f);
n:取地址放入结构体变量
f:函数指针
工作队列调度:
schedule_work(* work)
work:工作队列的核心结构体
延时
创建: INIT_DELAYED_WORK(n,f)
n:name 名字
f:函数指针
调用:
schedule_delayed_work(*work, delay)
延迟delay 个时钟周期后被调度。