Tasklet机制是一种较为特殊的软中断;Tasklet的原意是"小片任务",这里是指一小段可执行代码,而且通常以函数的形式出现;软中断向量HI_SOFTIRQ和TASKLET_SOFTIRQ均是使用Tasklet机制来实现的; 从某种程度上讲,Tasklet机制是中断底半部机制的一种扩展;在Linux内核中引入软中断机制后,原有的底半部机制正是通过Tasklet机制这个桥梁来纳入软中断机制的整体框架中的;正是这种历史关系的延伸,使得Tasklet机制与一般意义上的软中断机制有所不同,而且呈现出以下两个显著的特点: (1):与一般的软中断不同,某一段Tasklet代码在某个时刻只能在一个CPU上运行,而不像一般的软中断服务函数那样,在同一时刻可以被多个CPU并发地执行; (2):与底半部机制不同,不同的Tasklet代码在同一时刻可以在多个CPU上并发地执行,而不像底半部机制那样必须严格地串行化执行(即:在同一时刻系统中只能有一个CPU执行底半部函数); Tasklet机制是通过一个struct tasklet_struct结构来描述tasklet的,它的使用比较简单,只需要定义Tasklet实例及其处理函数,并把Tasklet实例与其处理函数绑定起来;例如: void my_tasklet_func(unsigned long); //tasklet处理函数 DECLARE_TASKLET(my_tasklet, my_tasklet_func, data); 该操作定义一个tasklet实例my_tasklet,并与处理函数my_tasklet_func(data)绑定起来,data作为参数传递给函数my_tasklet_func(); 在需要调度tasklet的时候,引用一个tasklet_schedule()函数,就能使系统在适当的时候进行调度运行;如下: tasklet_schedule(&my_tasklet); 使用tasklet处理中断底半部的设备驱动程序模板如下: //定义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_interrupt); ...... } 例子: #include <linux/module.h> #include <linux/version.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/jiffies.h> #include <linux/delay.h> #include <linux/sched.h> #include <linux/kthread.h> #include <linux/err.h> //tasklet相关 #include <linux/interrupt.h> MODULE_LICENSE("GPL"); MODULE_AUTHOR("*************"); MODULE_VERSION("2.6.35.000"); static int flag = 0; //STEP1:实现tasklet处理函数; void my_do_tasklet(unsigned long param) { flag = 1; printk("%s:hello, my tasklet function,param=%lu\n", __FUNCTION__, param); }; //STEP2:定义tasklet DECLARE_TASKLET(my_tasklet, my_do_tasklet, 789); static int thread_process(void* param) { while(1) { set_current_state(TASK_UNINTERRUPTIBLE); if(kthread_should_stop()) { printk("kernel thread should stop;file:%s;line:%d\n", __FILE__, __LINE__); break; } mdelay(10*HZ); //STEP3:调度tasklet运行; if(0 == flag) { tasklet_schedule(&my_tasklet); } else { flag = 0; } } return 123; }; static struct task_struct* my_thread = NULL; static int __init study_init(void) { int err = 0; printk("%s\n", __PRETTY_FUNCTION__); my_thread = kthread_create(thread_process, NULL, "my_thread"); if(IS_ERR(my_thread)) { err = PTR_ERR(my_thread); my_thread = NULL; printk(KERN_ERR "unable to start kernel thread:%d\n", err); return err; } wake_up_process(my_thread); printk("kernel thread start;file:%s;line:%d\n", __FILE__, __LINE__); return 0; } static void __exit study_exit(void) { int ret = -1; printk("%s\n",__PRETTY_FUNCTION__); if(my_thread) { ret = kthread_stop(my_thread); my_thread = NULL; } printk("kernel thread stop,exit code is %d;file:%s;line:%d\n",ret, __FILE__, __LINE__); } module_init(study_init); module_exit(study_exit);
|