中断下半部分机制--tasklet和工作队列
1.tasklet
tasklet机制是内核定义的几种softirq之一(常用)
根据优先级不同内核将tasklet分成两种:TASKLET_SOFTIRQ 和 HI_SOFTIRQ (后者优先级高)
执行时机通常是上半部分返回的时候。
1.1 tasklet机制初始化
在linux系统内核初始化的时候,通过调用softirq_init( )为TASKLET_SOFTIRQ 和 HI_SOFTIRQ
安装了执行函数。
1.2 相关的操作
struct tasklet_struct
{
struct tasklet_struct *next; //用来将系统中tasklet链接成链表
unsigned long state; //记录在系统中tasklet的状态
atomic_t count; //如果为0,则不可被调度执行
void (*func)(unsigned long); //在tasklet上执行函数或者延迟函数
unsigned long data; //将data传递给fun指向的函数
};
1.2.1 初始化tasklet
声明并初始化一个静态的tasklet对象;
//struct tasklet_struct name;
//void func(unsigned long);
//unsingned long data;
DECLARE_TASKLET(name, func, data);
动态初始化tasklet对象
void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data)
-->tasklet_init(&name, fun, data);
1.2.2 提交一个tasklet
在声明和初始化一个tasklet对象之后,
驱动程序需要调用tasklet_schedule来向系统提交tasklet(一般在中断处理程序中提交)
void tasklet_schedule(struct tasklet_struct *t)
tasklet_schedule(name);
驱动模型:
2. 工作队列
2.1 使用内核自己带的工作队列
工作队列和tasklet相似,工作队列执行的上下文是内核线程,因此可以调度和睡眠
在Workqueue机制中,Linux系统在初始化的时候通过init_workqueues(void)函数创建了一个workqueue队列——events,
用户可以直接初始化一个work_struct对象,然后在该队列中进行调度,使用更加方便。
struct work_sturct my_wrok;//定义一个工作节点
void my_wq_func(struct work_struct *work);//定一个处理函数
INIT_WORK(&my_work, my_wq_func) /*初始化工作节点,并和处理函数绑定*/
schedule_work(&my_wq) /*使用内核自己创建的工作队列-events和处理线程, 提交工作节点(一般在中断处理函数中)*/
---> queue_work(system_wq, work);
2.2 使用自己创建工作队列
首先创建工作队列:
#define create_workqueue(name)
alloc_workqueue((name), WQ_MEM_RECLAIM, 1)
--->struct workqueue_struct* myworkqueue = create_workqueue("mywq"); /*创建工作队列和处理线程*/
提交工作:
int queue_work(struct workqueue_struct *wq, struct work_struct *work)
-->queue_work(myworkqueue, &my_work);