中断控制---Tasklet

来源:互联网 发布:江苏网络问政 编辑:程序博客网 时间:2024/05/17 23:22

前面说说:这两天搞驱动开发涉及到中断,涉及到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/