中断实例-tasklet
来源:互联网 发布:巴西经济数据 编辑:程序博客网 时间:2024/05/22 06:25
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
//define a devid
static int mydev=1119;
static int irq;
static char* devname=NULL;
//define arguments for this module
module_param(irq,int,0644);
module_param(devname,charp,0644);
//define a argument of tasklet struct
static struct tasklet_struct mytasklet;
static void mytasklet_handler(unsigned long data)
{
printk("This is tasklet handler../n");
}
static irqreturn_t myirq_handler(int irq,void* dev)
{
static int count=0;
if(count<10)
{
printk("-----------%d start--------------------------/n",count+1);
printk("The interrupt handeler is working../n");
printk("The most of interrupt work will be done by following tasklet../n");
tasklet_init(&mytasklet,mytasklet_handler,0);
tasklet_schedule(&mytasklet);
printk("The top half has been done and bottom half will be processed../n");
}
count++;
return IRQ_HANDLED;
}
static int __init mytasklet_init()
{
//request a irq
printk("My module is working../n");
if(request_irq(irq,myirq_handler,IRQF_SHARED,devname,&irq)!=0)
{
printk("tasklet_init:can not request irq %d for %s..",irq,devname);
return -1;
}
printk("%s request irq:%d success../n",devname,irq);
return 0;
}
static void __exit mytasklet_exit()
{
printk("My module is leaving../n");
free_irq(irq,&irq);
printk("Free the irq %d../n",irq);
}
module_init(mytasklet_init);
module_exit(mytasklet_exit);
MODULE_LICENSE("GPL");
本文包含那些内容? tasklet由tasklet_struct结构体来表示,每一个这样的结构体就表示一个tasklet。在<linux/interrupt.h>中可以看到如下的定义: 在这个结构体中,第一个成员代表链表中的下一个tasklet。第二个变量代表此刻tasklet的状态,一般为TASKLET_STATE_SCHED,表示此tasklet已被调度且正准备运行;此变量还可取TASKLET_STATE_RUN,表示正在运行,但只用在多处理器的情况下。count成员是一个引用计数器,只有当其值为0时候,tasklet才会被激活;否则被禁止,不能被执行。而接下来的func变量很明显是一个函数指针,它指向tasklet处理函数,这个处理函数的唯一参数为data。 在<linux/interrupt.h>中的两个宏: 就是我们进行静态创建tasklet的两种方法。通过第一个宏创建的tasklet处于激活状态,再通过调度函数被挂起尽而被内核执行;而通过第二个宏创建的tasklet处于禁止状态。从两个宏的定义可以看到,所谓的静态创建就是直接定义个一个名为name的tasklet_struct类型的变量,并将宏中各个参数相应的赋值给这个name变量的各个成员。注意,两个宏在功能上差异就在于对name变量count成员的赋值上,具体原因在第一部分已经说明。也许你对ATOMIC_INIT这样的初始化方式感到疑惑,那么看完定义后,你就会一目了然: 与静态创建相对的是动态创建,通过给tasklet_init函数传递一个事先定义的指针,来动态创建一个tasklet。这个函数源码如下。 相信你在阅读上面的代码是基本上没有什么难以理解的地方,不过这里还是要特别说明一下atomic_set函数: 首先tasklet_init当中,将&t->count传递给了此函数。也就是说将atomic_t类型的成员count的地址传递给了atomic_set函数。而我们在此函数中却要为count变量中的成员counter赋值。如果说我们当前要使用i,那么应该是如下的引用方法:t-》count.i。明白了吗? ok,通过上述两种方法就可以创建一个tasklet了。同时,你应该注意到不管是上述那种创建方式都有func参数。透过上述分析的源码,我们可以看到func参数是一个函数指针,它指向的是这样的一个函数: 如同上半部分的中断处理程序一样,这个函数需要我们自己来实现。 创建好之后,我们还要通过如下的方法对tasklet进行调度: 通过此函数的调用,我们的tasklet就会被挂起,等待机会被执行 从代码中可以看到,在上半部中通过调用tasklet,使得对时间要求宽松的那部分中断程序推后执行。
tasklet机制概述;tasklet机制的使用方法;一个阐述tasklet机制调用关系的举例。
本文适合那些人阅读?
想了解linuxer;学习驱动开发的beginner;学习内核模块编程beginner;其他super linux NBer;
参考书籍:
Linux内核设计与实现
Linux操作系统原理与应用tasklet的实现
tasklet(小任务)机制是中断处理下半部分最常用的一种方法,其使用也是非常简单的。正如在前文中你所知道的那样,一个使用tasklet的中断程序首先会通过执行中断处理程序来快速完成上半部分的工作,接着通过调用tasklet使得下半部分的工作得以完成。可以看到,下半部分被上半部分所调用,至于下半部分何时执行则属于内核的工作。对应到我们此刻所说的tasklet就是,在中断处理程序中,除了完成对中断的响应等工作,还要调用tasklet,如下图示。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_struct类型的变量。通常有两种方法:静态创建和动态创建。这样官方的说法仍然使我们不能理解这两种创建到底是怎么一回事。不够透过源码来分析倒是可以搞明白。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 }
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;
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}
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}
1
void
tasklet_handler(unsigned
long
data);
1
tasklet_schedule(&my_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
}
参考文件:
1. http://blogold.chinaunix.net/u3/117099/showart_2344767.html
2. http://edsionte.com/techblog/archives/1547
- 中断实例-tasklet
- 中断处理与【irqsoft】、【tasklet】和【work queue】使用实例
- globalfifo驱动实例(tasklet中断底半部机制)
- 中断处理与【irqsoft】、【tasklet】和【work queue】使用实例
- 实例:中断的下半部分之二tasklet
- 中断处理的tasklet
- 软中断及tasklet
- 中断控制---Tasklet
- linux tasklet/软中断
- 中断下半部-tasklet
- tasklet和软中断
- 9. 中断下半部---tasklet
- 软中断和TASKLET
- 嵌入式 中断处理与【irqsoft】、【tasklet】和【work queue】使用实例
- linux内核中断 ----- tasklet 分析
- 软中断/tasklet/工作队列
- 软中断/tasklet/工作队列
- linux中断延迟之tasklet
- struts+ajax+mysql制作的简单登录
- struts+ajax+mysql制作的简单登录
- 转:软件牛人与迷惘者
- 软件编程推荐书籍 大全
- W7下android IDE搭建指南
- 中断实例-tasklet
- 我的愿望这么 下载要扣分
- APUE学习笔记(03)-文件I/O
- [MFC]ADO查询语句中的一个问题
- 我在阿里
- JavaScript的七条准则
- JDKjdk1.4、jdk5.0、JDK6.0、 JDK7.0、JDK8.0、JDK9.0(2016年发布) 新特性
- POJ 2050 Searching the Web
- 使用JQuery解决图片自适应大小问题(比较好的解决图片从加载到完全显示的大小问题)