一、tasklet使用
Tasklet的使用比较简单,只需要定义tasklet及其处理函数并将两者关联
例子:
Void my_tasklet_func(unsigned long)
DECLARE_TASKLET(my_tasklet.my_tasklet_func,data)
代码DECLARE_TASKLET实现了定义名称为my_tasklet的tasklet并将其与my_tasklet_func这个函数绑定,而传入这个函数的参数为data。
需要调度tasklet的时候引用一个tasklet_schedule()函数就能使系统在适当的时候进行调度,如下所示
Tasklet_schedule(&my_tasklet)
下面给出驱动模板
void xxx_do_tasklet(unsigned long ); DECLARE_TASKLET(xxx_tasklet,xxx_do_tasklet,0 ); void xxx_do_tasklet(unsigned long ) { } irqreturn_t xxx_interrupt(int irq,void *dev_id,struct pt_regs * regs) { tasklet_schedule(&xxx_tasklet);} int _init xxx_init(void ) { result=request_irq(xxx_irq,xxx_interrupt,SA_INTERRUPT,”xxx”,NULL)} void _exit xxx_exit(void ) { free_irq(xxx_irq,xxx_irq_interrupt); }
二、tasklet函数详解
它对于中断处理特别有用:硬件中断必须尽快处理, 但大部分的数据管理可以延后到以后安全的时间执行。
tasklet 以一个数据结构形式存在,使用前必须被初始化。初始化能够通过调用一个特定函数或者通过使用某些宏定义声明结构:
一、 工作队列的使用
定义一个工作队列
Struct work_struct my_wq;
Void my_wq_func(unsigned long);
通过INIT_WORK可以初始化这个工作队列并将工作队列与处理函数绑定
INIT_WORK(&my_wq,(void(*)(void*))my_wq_func,NULL)
调度工作队列
Schedule_work(&my_wq)
使用模板
struct work_struct xxx_wq;
void xxx_do_work(unsigned long);
void xxx_do_work(unsigned long)
{
}
irqreturn_t xxx_interrupt(int irq,void *dev_id,struct pt_regs *regs)
{
schedule_work(&xxx_wq);
}
int init(void)
{
result=request_irq(xxx_irq,xxx_interrupt,SA_INTERRUPT,“xxx”,NULL)
INIT_WORK(&xxx_wq,(void(*)(void*))xxx_do_work,NULL);
}
void xxx_exit(void)
{
free_irq(xxx_irq,xxx_interrupt);
}
二、 工作队列函数详解
工作队列有 struct workqueue_struct 类型,在 <linux/workqueue.h> 中定义。一个工作队列必须明确的在使用前创建,宏为:
struct workqueue_struct *create_workqueue(const char *name); |
每个工作队列有一个或多个专用的进程("内核线程"), 这些进程运行提交给这个队列的函数。 若使用 create_workqueue, 就得到一个工作队列它在系统的每个处理器上有一个专用的线程。在很多情况下,过多线程对系统性能有影响,如果单个线程就足够则使用 create_singlethread_workqueue 来创建工作队列。
提交一个任务给一个工作队列,在这里《LDD3》介绍的内核2.6.10和我用的新内核2.6.22.2已经有不同了,老接口已经不能用了,编译会出错。这里我只讲2.6.22.2的新接口,至于老的接口我想今后内核不会再有了。从这一点我们可以看出内核发展。
/*需要填充work_struct或delayed_work结构,可以在编译时完成, 宏如下: */ struct work_struct { atomic_long_t data; #define WORK_STRUCT_PENDING 0 /* T if work item pending execution */ #define WORK_STRUCT_FLAG_MASK (3UL) #define WORK_STRUCT_WQ_DATA_MASK (~WORK_STRUCT_FLAG_MASK) struct list_head entry; work_func_t func; }; struct delayed_work { struct work_struct work; struct timer_list timer; }; 三、与tasklet的联系 工作队列类似 tasklets,允许内核代码请求在将来某个时间调用一个函数,不同在于: (1)tasklet 在软件中断上下文中运行,所以 tasklet 代码必须是原子的。而工作队列函数在一个特殊内核进程上下文运行,有更多的灵活性,且能够休眠。 (2)tasklet 只能在最初被提交的处理器上运行,这只是工作队列默认工作方式。 (3)内核代码可以请求工作队列函数被延后一个给定的时间间隔。 (4)tasklet 执行的很快, 短时期, 并且在原子态, 而工作队列函数可能是长周期且不需要是原子的,两个机制有它适合的情形。