本文转载自:http://edsionte.com/techblog/archives/1547

tasklet的实现

tasklet(小任务)机制是中断处理下半部分最常用的一种方法,其使用也是非常简单的。正如在前文中你所知道的那样,一个使用tasklet的中断程序首先会通过执行中断处理程序来快速完成上半部分的工作,接着通过调用tasklet使得下半部分的工作得以完成。可以看到,下半部分被上半部分所调用,至于下半部分何时执行则属于内核的工作。对应到我们此刻所说的tasklet就是,在中断处理程序中,除了完成对中断的响应等工作,还要调用tasklet,如下图示。

tasklet由tasklet_struct结构体来表示,每一个这样的结构体就表示一个tasklet。在<linux/interrupt.h>中可以看到如下的定义:

1 tasklet_struct
2 {
3     struct tasklet_struct *next;
4     unsigned long state;
5     atomic_t count;
6     void (*func)(unsigned long);
7     unsigned long data;
8 };

在这个结构体中,第一个成员代表链表中的下一个tasklet。第二个变量代表此刻tasklet的状态,一般为TASKLET_STATE_SCHED,表示此tasklet已被调度且正准备运行;此变量还可取TASKLET_STATE_RUN,表示正在运行,但只用在多处理器的情况下。count成员是一个引用计数器,只有当其值为0时候,tasklet才会被激活;否则被禁止,不能被执行。而接下来的func变量很明显是一个函数指针,它指向tasklet处理函数,这个处理函数的唯一参数为data。

使用tasklet

在使用tasklet前,必须首先创建一个tasklet_struct类型的变量。通常有两种方法:静态创建和动态创建。这样官方的说法仍然使我们不能理解这两种创建到底是怎么一回事。不够透过源码来分析倒是可以搞明白。

在<linux/interrupt.h>中的两个宏:

1 464#define DECLARE_TASKLET(name, func, data) \
2 465struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(0), func, data }
3 466
4 467#define DECLARE_TASKLET_DISABLED(name, func, data) \
5 468struct tasklet_struct name = { NULL, 0, ATOMIC_INIT(1), func, data }

就是我们进行静态创建tasklet的两种方法。通过第一个宏创建的tasklet处于激活状态,再通过调度函数被挂起尽而被内核执行;而通过第二个宏创建的tasklet处于禁止状态。从两个宏的定义可以看到,所谓的静态创建就是直接定义个一个名为name的tasklet_struct类型的变量,并将宏中各个参数相应的赋值给这个name变量的各个成员。注意,两个宏在功能上差异就在于对name变量count成员的赋值上,具体原因在第一部分已经说明。也许你对ATOMIC_INIT这样的初始化方式感到疑惑,那么看完定义后,你就会一目了然:

1 //在arch/x86/include/asm/atomic.h中
2 15#define ATOMIC_INIT(i)  { (i) }
3 //在linux/types.h中
4 190typedef struct {
5 191        int counter;
6 192} atomic_t;

与静态创建相对的是动态创建,通过给tasklet_init函数传递一个事先定义的指针,来动态创建一个tasklet。这个函数源码如下。

1 470void tasklet_init(struct tasklet_struct *t,
2 471                  void (*func)(unsigned long), unsigned long data)
3 472{
4 473        t->next = NULL;
5 474        t->state = 0;
6 475        atomic_set(&t->count, 0);
7 476        t->func = func;
8 477        t->data = data;
9 478}

相信你在阅读上面的代码是基本上没有什么难以理解的地方,不过这里还是要特别说明一下atomic_set函数:

1 //在arch/x86/include/asm/atomic.h中
2 35static inline void atomic_set(atomic_t *v, int i)
3 36{
4 37        v->counter = i;
5 38}

首先tasklet_init当中,将&t->count传递给了此函数。也就是说将atomic_t类型的成员count的地址传递给了atomic_set函数。而我们在此函数中却要为count变量中的成员counter赋值。如果说我们当前要使用i,那么应该是如下的引用方法:t-》count.i。明白了吗?

ok,通过上述两种方法就可以创建一个tasklet了。同时,你应该注意到不管是上述那种创建方式都有func参数。透过上述分析的源码,我们可以看到func参数是一个函数指针,它指向的是这样的一个函数:

1 void tasklet_handler(unsigned long data);

如同上半部分的中断处理程序一样,这个函数需要我们自己来实现。

创建好之后,我们还要通过如下的方法对tasklet进行调度:

1 tasklet_schedule(&my_tasklet)

通过此函数的调用,我们的tasklet就会被挂起,等待机会被执行

一个举例

在此只分析上下两部分的调用关系,完整代码在这里查看。

01 //define a argument of tasklet struct
02 static struct tasklet_struct mytasklet;
03  
04 static void mytasklet_handler(unsigned long data)
05 {
06     printk("This is tasklet handler..\n");
07 }
08  
09 static irqreturn_t myirq_handler(int irq,void* dev)
10 {
11     static int count=0;
12     if(count<10)
13     {
14         printk("-----------%d start--------------------------\n",count+1);
15                 printk("The interrupt handeler is working..\n");
16                 printk("The most of interrupt work will be done by following tasklet..\n");
17                 tasklet_init(&mytasklet,mytasklet_handler,0);
18             tasklet_schedule(&mytasklet);
19                 printk("The top half has been done and bottom half will be processed..\n");
20     }
21     count++;
22         return IRQ_HANDLED;
23 }

从代码中可以看到,在上半部中通过调用tasklet,使得对时间要求宽松的那部分中断程序推后执行。

中断下半部tasklet【转】的更多相关文章

  1. 中断下半部-tasklet

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

  2. linux设备驱动归纳总结(六):3.中断的上半部和下半部——tasklet【转】

    本文转载自:http://blog.chinaunix.net/uid-25014876-id-100005.html linux设备驱动归纳总结(六):3.中断的上半部和下半部——tasklet x ...

  3. Linux 中断下半部

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

  4. 《Linux内核设计与实现》读书笔记(八)- 中断下半部的处理

    在前一章也提到过,之所以中断会分成上下两部分,是由于中断对时限的要求非常高,需要尽快的响应硬件. 主要内容: 中断下半部处理 实现中断下半部的机制 总结中断下半部的实现 中断实现示例 1. 中断下半部 ...

  5. linux驱动学习笔记---实现中断下半部以及驱动编写规范(七)【转】

    转自:https://blog.csdn.net/weixin_42471952/article/details/81609141 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协 ...

  6. linux 中断softirq tasklet

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

  7. 中断下半部处理之tasklet

    1.tasklet概述 下半部和退后执行的工作,软中断的使用只在那些执行频率很高和连续性要求很高的情况下才需要.在大多数情况下,为了控制一个寻常的硬件设备,tasklet机制都是实现自己下半部的最佳选 ...

  8. 【linux kernel】 中断处理-中断下半部

    欢迎转载,转载时需保留作者信息,谢谢. 邮箱:tangzhongp@163.com 博客园地址:http://www.cnblogs.com/embedded-tzp Csdn博客地址:http:// ...

  9. 【linux kernel】 中断处理-中断下半部【转】

    转自:http://www.cnblogs.com/embedded-tzp/p/4453987.html 欢迎转载,转载时需保留作者信息,谢谢. 邮箱:tangzhongp@163.com 博客园地 ...

随机推荐

  1. linux oracle error解决记录

    1.sqlplus / as sysdba后使用select instance_name,status from v$instance后出错: ERROR:ORA-01034: ORACLE not ...

  2. Android实现短信监听并且转发到指定的手机号,转发后不留痕

    转载:http://blog.csdn.net/swqqcs/article/details/7252419 通过这些代码也可以对远程手机实现短信控制.有兴趣的可以自己改一下,说一下简单的原理,要实现 ...

  3. 怎么在Word中找MathType菜单

    一些用户朋友在使用word的过程中,发现自己突然找不到MathType公式编辑器菜单项了,而这个时候又急着编写公式,所以会特别的着急.下面我们就来针对这个问题好好的给大家分析一下,并提供解决方案.请关 ...

  4. http 状态吗

    100:继续  客户端应当继续发送请求.客户端应当继续发送请求的剩余部分,或者如果请求已经完成,忽略这个响应. 101: 转换协议  在发送完这个响应最后的空行后,服务器将会切换到在Upgrade 消 ...

  5. Android开发:《Gradle Recipes for Android》阅读笔记1.4

    在android studio下可以使用gradle视图运行gradle. gradle任务被分别组织在不同目录下,如android,build,install. 需要执行特定的任务只要双击任务名称. ...

  6. bin/mysqld: error while loading shared libraries: libnuma.so.1: 安装mysql

    如果安装mysql出现了以上的报错信息.这是却少numactl这个时候如果是Centos就yum -y install numactl就可以解决这个问题了. ubuntu的就sudo apt-get ...

  7. 【BZOJ4917】Hash Killer IV 乱搞

    [BZOJ4917]Hash Killer IV Description 有一天,tangjz造了一个Hash函数: unsigned int Hash(unsigned int v){     un ...

  8. mac安装以及删除mysql5.7

    关于msyql5.7,安装时最大的改变就是有了一个默认密码 我安装的是mysql-5.7.17-macos10.12-x86_64.dmg 和mysql-workbench-community-6.3 ...

  9. 将方法定义在prototype上的好处

    通常js类定义和使用的是这样的: var Class=function(){}; Class.prototype.sharedFn=function(){}; var instanceA=new Cl ...

  10. css,查询相应标签,div等

    1.类名 .类别 例子: 查询类名为“useradd” .useradd{ margin-top:50px; margin-left:200px;} 2.属性找 例子:查询类为useradd下的inp ...