一个使用tasklet的中断程序首先会通过执行中断处理程序来快速完成上半部分的工作,接着通过调度tasklet使得下半部分的工作得以完成,但是下半部分何时执行属于内核的工作。

由于tasklet依靠软中断实现,所以tasklet不能休眠。这就意味着不能在tasklet中使用信号量或其他任何可能引起阻塞的函数。两个相同的tasklet绝不会同时执行。这点是和软中断的一个重要的区别。尽管两个不同的tasklet可以在两个处理器上同时执行,但只要不同的tasklet不共享数据,就不会有任何问题。当然,如果要共享数据,仍然需要使用本地锁保护临界区数据。

本文档描述基于3.14.77内核。

1. 定义

tasklet定义在linux/interrupt.h中,实现在kernel/softirq.c中。

struct tasklet_struct {
struct tasklet_struct *next;
unsigned long state;
atomic_t count;
void (*func)(unsigned long);
unsigned long data; // 给tasklet处理函数传递的参数
};

tasklet_struct.state可以设置成0,也可以设置成两个枚举值(TASKLET_STATE_SCHED和TASKLET_STATE_RUN),除此之外,tasklet_struct.state不能设置成其他的值。

enum
{
TASKLET_STATE_SCHED, /* Tasklet is scheduled for execution */
TASKLET_STATE_RUN /* Tasklet is running (SMP only) */
};

tasklet_struct.count是tasklet的引用计数器,如果count不为0,表示tasklet被禁用,不允许执行。只有当count为0时,tasklet才会被激活,并且只有tasklet被设置为挂起时,该tasklet才能被执行(下一次调用do_softirq函数时会执行所有挂起的tasklet)。

初始化

#define DECLARE_TASKLET(name, func, data) \
struct tasklet_struct name = { NULL, , ATOMIC_INIT(), func, data } #define DECLARE_TASKLET_DISABLED(name, func, data) \
struct tasklet_struct name = { NULL, , ATOMIC_INIT(), func, data } void tasklet_init(struct tasklet_struct *t, void (*func)(unsigned long), unsigned long data);

由于tasklet_init函数本身不会创建tasklet_struct结构体,因此,在调用tasklet_init函数之前,需要使用kmalloc或其他类似的内核空间分配函数为tasklet_struct结构体分配内存空间(动态创建tasklet_struct结构体)。

调度

tasklet_schedule(&mytasklet);  //调用底半部,注意,这不是立即调用,是调度,意味着tasklet底半部会在顶半部执行完成后才会执行。

在_tasklet_schedule函数中调用raise_softirq_irqoff函数挂起了TASKLET_SOFTIRQ中断。这就意味着一旦do_softirq函数在某个时刻被调用,系统就会扫描软中断向量表(softirq_vec),这时发现TASKLET_SOFTIRQ软中断被挂起,就会立刻执行与TASKLET_SOFTIRQ软中断对应的处理程序。在TASKLET_SOFTIRQ软中断处理程序中会扫描tasklet向量表(tasklet_vec)。

销毁

一般会在Linux驱动的exit函数中使用tasklet_kill函数(kernel/softirq.c)销毁当前的tasklet,实际上就是将tasklet_struct.state设为0。

extern void tasklet_kill(struct tasklet_struct *t);
extern void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu);

2. 应用

static struct tasklet_struct my_tasklet;   

static void tasklet_handler (unsigned long data)
{
printk(KERN_ALERT "tasklet_handler is running.\n");
} tasklet_init(&my_tasklet, tasklet_handler, ); // 初始化tasklet
tasklet_schedule(&my_tasklet); // 调度tasklet处理程序 tasklet_kill(&my_tasklet);

3. 小结

由于软中断是Linux系统全局的,整个Linux系统最多也只能有10个不同类型的软中断。而且如果不修改Linux内核源代码,这个最大中断数是不会变的,就算修改了内核源代码,最大也只能有32个软中断。为了可以处理更多的底半部,系统定义了两个特殊的软中断(HI_SOFTIRQ和TASKLET_SOFTIRQ),通过这两个软中断的处理函数可以执行两个tasklet向量(tasklet_vec和tasklet_hi_vec)中的tasklet处理程序。因此tasklet处理程序的执行效率要比软中断处理程序的执行效率低一些(也低不了太多)。这是因为tasklet处理程序需要先执行软中断处理程序,然后才能扫描tasklet向量,比软中断处理程序多了一步。

参考:

1. tasklet_workqueue

2. linux内核对中断的处理方式

3. tasklet

小任务tasklet应用的更多相关文章

  1. Linux软中断、tasklet和工作队列

    Linux内核中的软中断.tasklet和工作队列详解 引言 软中断.tasklet和工作队列并不是Linux内核中一直存在的机制,而是由更早版本的内核中的“下半部”(bottom half)演变而来 ...

  2. linux中的tasklet机制【转】

    转自:http://blog.csdn.net/yasin_lee/article/details/12999099 转自: http://www.kerneltravel.net/?p=143 中断 ...

  3. Linux tasklet 和workqueue学习

    中断服务程序一般都是在中断请求关闭的条件下执行的,以避免嵌套而使中断控制复杂化.但是,中断是一个随机事件,它随时会到来,如果关中断的时间太长,CPU就不能及时响应其他的中断请求,从而造成中断的丢失.因 ...

  4. linux 中断softirq tasklet

    硬中断为什么不能休眠--- 中断线程以及软中断解决了什么问题---- 软中断cb函数是否允许相应本地中断,什么时候开启中断关闭中断---- 什么是软中断上下文------- 什么是tasklet 和软 ...

  5. linux中断编程

    本文档只介绍中断编程所需的函数及应用,中断完整处理流程应参考文档<linux中断处理流程>,可参考文档<linux内核对中断的处理方式>对中断初步了解. 本文档基于3.14内核 ...

  6. Linux 中断下半部

    为什么使用中断下半部? 中断执行的原则是要以最快的速度执行完,而且期间不能延时和休眠! 可是现实中,中断中可能没办法很快的处理完需要做的事,或者必须用到延时和休眠,因此引入了中断下半部. 中断中处理紧 ...

  7. 内核源码分析之tasklet(基于3.16-rc4)

    tasklet是在HI_SOFTIRQ和TASKLET_SOFTIRQ两个软中断的基础上实现的(它们是在同一个源文件中实现,由此可见它们的关系密切程度),它的数据结构和软中断比较相似,这篇博文将分析t ...

  8. 中断下半部-tasklet

    http://edsionte.com/techblog/ tasklet的实现 tasklet(小任务)机制是中断处理下半部分最常用的一种方法,其使用也是非常简单的.正如在前文中你所知道的那样,一个 ...

  9. tasklet和workqueue的选择

    linux内核设计与实现page127中有个比較,内容比較多.概括一下就是1. tasklet不能休眠, 2. 不须要休眠tasklet效率更高 3.有休眠仅仅能workqueue (1)假设不须要休 ...

随机推荐

  1. HDUOJ1086You can Solve a Geometry Problem too

    You can Solve a Geometry Problem too Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/3 ...

  2. HDUOJ-----1098 Ignatius's puzzle

    Ignatius's puzzle Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others ...

  3. 动态计算UITableViewCell高度详解

    本文将介绍四种情况下UITableViewCell的计算方式,分别是: Auto Layout with UILabel in UITableViewCell Auto Layout with UIT ...

  4. Google C++单元测试框架之宏

    一.概述 gtest中,断言的宏可以理解分为两类,一类是ASSERT系列,一类是EXPECT系列: 1.ASSERT_*系列的断言,当检查点失败时,退出当前函数(注意:并非退出当前案例) 2.EXCE ...

  5. Android JUnit 入门指南

    自动化单元测试可以做许多的事,并帮你节省时间.它也可以被用作快速检验新建工程或进行冒烟测试.始终,单元测试是作为一种有效的.系统的检验应用程序各功能执行的方式.Android SDK支持JUnit的自 ...

  6. 如何在Access2007中使用日期类型查询数据

    select * from 表 where datediff("d",日期型的字段,#2008-09-01#)=0或select * from 表 where 日期型的字段 > ...

  7. AspxPivotGrid和WebChartControl数据联动处理日志

    AspxPivotGrid具有很好的表格样式体验,WebChartControl也是个很内容丰富的做图控件,我希望实现的功能是这样的, 处理题库统计分析图表,用户点AspxPivotGrid绑定知识点 ...

  8. Android 自定义属性动画&Camera动画

      摘要: Android 自定义属性动画&Camera动画 1.相关知识点 对于Androi的帧动画,可以制作gif图片,有时为了能够动态的生成帧动画,就得需要使用代码构建了 Animati ...

  9. 普里姆Prim算法介绍

    普里姆(Prim)算法,和克鲁斯卡尔算法一样,是用来求加权连通图的最小生成树的算法. 基本思想 对于图G而言,V是所有顶点的集合:现在,设置两个新的集合U和T,其中U用于存放G的最小生成树中的顶点,T ...

  10. 关闭VS的实时调试器

    今天要安装一个水晶报表.安装过程有几个文件有错误.结果这个vs的实时调试器老是调出来.而且还是5次跳出来等你取消5次之后,才到默认的忽略的界面.你知道有多烦的,还得看这他,点完一次还要等几秒钟.差点崩 ...