前面说说:这两天搞驱动开发涉及到中断,涉及到tasklet机制,度娘半天发现只有此篇比较快速入手呵呵,特转一下。
/**************************************************************************************************************************************************/
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);
/********************************************************************************************/
http://bdxnote.blog.163.com/blog/static/84442352012429102943929/