嵌入式Linux内核tasklet机制(附实测代码)

Linux 中断编程分为中断顶半部,中断底半部

中断顶半部: 做紧急,耗时短的事情,同时还启动中断底半部。
中断底半部: 做耗时的事件,这个事件在执行过程可以被中断。
中断底半部实现方法: tasklet,工作队列,软中断等机制实现。实际上是把耗时事件推后执行,不在中断程序执行。

成都创新互联长期为成百上千客户提供的网站建设服务,团队从业经验10年,关注不同地域、不同群体,并针对不同对象提供差异化的产品和服务;打造开放共赢平台,与合作伙伴共同营造健康的互联网生态环境。为洛川企业提供专业的网站建设、网站设计,洛川网站改版等技术服务。拥有十余年丰富建站经验和众多成功案例,为您定制开发。

什么是tasklet?

Tasklet 一词的原意是“小片任务”的意思,这里是指一小段可执行的代码,且通常以函数的形式出现。这个 tasklet 绑定的函数在一个时刻只能在一个 CPU 上运行 ,tasklet(小任务)机制是中断处理下半部分最常用的一种方法,其使用也是非常简单的。一个使用 tasklet 的中断程序首先会通过执行中断处理程序来快速完成上半部分的工作,接着通过调用 tasklet 使得下半部分的工作得以完成。可以看到,下半部分被上半部分所调用,至于下半部分何时执行则属于内核的工作。

tasklet 机制核心数据结构

Interrupt.h linux-3.5\include\Linux
struct tasklet_struct
{
      struct tasklet_struct *next; // tasklet_struct 结构链表
      unsigned long state; //当前这个 tasklet 是否已经被调度
      atomic_t count; 
      void (*func)(unsigned long); //指向 tasklet 绑定的函数的指针
      unsigned long data; //传递给tasklet 绑定的函数的参数
};

tasklet 相关 API

  • 初始化相关

    • 1) 静态初始化 DECLARE_TASKLET(name, func, data)
      作用:定义一个名字为 name 的 tasklet_struct 结构变量,并且初始化这个结构。 所定义的这个 tasklet 是可以被调度,默认是处于被使能状态。

    • 2 ) 静态初始化 DECLARE_TASKLET_DISABLED(name, func, data)
      作用:定义一个名字为 name 的 tasklet_struct 结构变量,并且初始化这个结构。所定义的这个 tasklet 是不能被调度,默认是处于被禁能状态。 要调度这个 tasklet 需要先使能。

    • 3 )动态初始化
      void tasklet_init(struct tasklet_struct *t,void (*func)(unsigned long), unsigned long data)
      作用:初始化一个 tasklet_struct 结构变量,初始化的结构默认是处于激活状态,可以被调度。

tasklet_disable使能函数

1. void tasklet_disable(struct tasklet_struct *t)
作用:函数激活给定的 tasklet被 tasklet_schedule 调度
2. void tasklet_enable (struct tasklet_struct *t)
作用:函数禁止给定的 tasklet被 tasklet_schedule 调度

tasklet 调度函数

void tasklet_schedule (struct tasklet_struct *t)
作用:调用 tasklet_schedule 函数去通知内核帮我们调度所绑定的函数
void tasklet_kill(struct tasklet_struct *t);
作用:取消调度函数

编程步骤

Step1 定义并静态初始化tasklet_struct 结构变量

Step2 编写tasklet服务函数

Step3 在适当的地地方进行调度

Step4 在适当的地地方取消调度

开发平台

芯灵思SinlinxA33开发板

淘宝店铺: [https://sinlinx.taobao.com/]()

嵌入式Linux内核tasklet机制(附实测代码)

嵌入式linux 开发板交流 QQ:641395230

驱动代码:

#include 
#include 
#include 

void tasklet_fun(unsigned long data);
//Step1 定义并静态初始化tasklet_struct 结构变量
DECLARE_TASKLET(mytasklet, tasklet_fun, 651);
//Step2 tasklet服务函数
void tasklet_fun(unsigned long data)
{
    static unsigned long count = 0;
    printk("count:%lu,%s is call! data:%lu\r\n",count++,__FUNCTION__,data);
    tasklet_schedule(&mytasklet); //在工作函数中重新调度自己,这样会循环调用tasklet_fun
}
static int __init mytasklet_init(void)
{
    //Step3 开始调度 mytasklet
    tasklet_schedule(&mytasklet);
    printk("%s is call!\r\n",__FUNCTION__);
    return 0;
}
static void __exit mytasklet_exit(void) //Module exit function specified by module_exit()
{
    //Step4 删除 tasklet
    tasklet_kill(&mytasklet);
}
module_init(mytasklet_init);
module_exit(mytasklet_exit);
MODULE_LICENSE("GPL");

Makefile 代码

KERN_DIR = /work/lichee/linux-3.4
all:
    make -C $(KERN_DIR) M=`pwd` modules 
    arm-none-linux-gnueabi-gcc  btntest.c -o btntest
clean:
    make -C $(KERN_DIR) M=`pwd` modules clean
    rm -rf modules.order
obj-m        += tasklet_drv.o

实验现象

循环调用tasklet_fun函数

嵌入式Linux内核tasklet机制(附实测代码)


当前文章:嵌入式Linux内核tasklet机制(附实测代码)
本文链接:http://csdahua.cn/article/jsoccd.html
扫二维码与项目经理沟通

我们在微信上24小时期待你的声音

解答本文疑问/技术咨询/运营咨询/技术建议/互联网交流