内核源码分析之tasklet(基于3.16-rc4)
tasklet是在HI_SOFTIRQ和TASKLET_SOFTIRQ两个软中断的基础上实现的(它们是在同一个源文件中实现,由此可见它们的关系密切程度),它的数据结构和软中断比较相似,这篇博文将分析tasklet的初始化过程。
1.和tasklet相关的数据结构
tasklet_vec和tasklet_hi_vec数组(kernel/softirq.c)
static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);
第1行中为所有cpu创建了名为tasklet_vec数组,每个元素和一个cpu相关联,数组元素类型为struct tasklet_head。第2行和第1行类似,创建出的tasklet_hi_vec数组存放的是每个cpu上优先级更高的tasklet小任务。下面看下struct tasklet_head结构体(kernel/softirq.c)。
struct tasklet_head {
struct tasklet_struct *head;
struct tasklet_struct **tail;
};
内核会为每个cpu分配一个这样的结构体变量,从而每个cpu都拥有一个小任务函数的链表。再看下结构体(kernel/softirq.c)。
struct tasklet_struct
{
struct tasklet_struct *next;
unsigned long state;
atomic_t count;
void (*func)(unsigned long);
unsigned long data;
};
第1行next指向小任务链表下一个节点,第6行func变量指向了小任务函数。
2.tasklet初始化
小任务是基于HI_SOFTIRQ和TASKLET_SOFTIRQ两个软中断来实现的。HI_SOFTIRQ所对应的软中断函数是tasklet_action,如下(kernel/softirq.c):
static void tasklet_action(struct softirq_action *a)
{
struct tasklet_struct *list; local_irq_disable();
list = __this_cpu_read(tasklet_vec.head);
__this_cpu_write(tasklet_vec.head, NULL);
__this_cpu_write(tasklet_vec.tail, &__get_cpu_var(tasklet_vec).head);
local_irq_enable(); while (list) {
struct tasklet_struct *t = list; list = list->next; if (tasklet_trylock(t)) {
if (!atomic_read(&t->count)) {
if (!test_and_clear_bit(TASKLET_STATE_SCHED,
&t->state))
BUG();
t->func(t->data);
tasklet_unlock(t);
continue;
}
tasklet_unlock(t);
} local_irq_disable();
t->next = NULL;
*__this_cpu_read(tasklet_vec.tail) = t;
__this_cpu_write(tasklet_vec.tail, &(t->next));
__raise_softirq_irqoff(TASKLET_SOFTIRQ);
local_irq_enable();
}
}
第6行中tasklet_vec数组中和本地cpu相关的元素的head域值,保存在list变量中,实际上把当前cpu的tastlet任务链表卸下来,list成为链表头指针。第7,8行把tasklet_vec数组和本地cpu相关的元素的head域置为NULL,tail域指向head域。第11-26行用while循环执行所有的tasklet函数。第21行是tasklet函数的执行。第30-31行把执行之后的struct tasklet_struct链表节点重新挂到tasklet_vec数组中,由此可见装tasklet函数的结构体不用程序员手动创建,由系统来提供。第32行重新设置软中断掩码表的相应位。TASKLET_SOFTIRQ所对应的软中断函数是tasklet_hi_action,和tasklet_action执行过程类似,不再分析。
来看下tasklet_action函数初始化过程(kernel/softirq.c)。
void __init softirq_init(void)
{
int cpu; for_each_possible_cpu(cpu) {
per_cpu(tasklet_vec, cpu).tail =
&per_cpu(tasklet_vec, cpu).head;
per_cpu(tasklet_hi_vec, cpu).tail =
&per_cpu(tasklet_hi_vec, cpu).head;
} open_softirq(TASKLET_SOFTIRQ, tasklet_action);
open_softirq(HI_SOFTIRQ, tasklet_hi_action);
}
第5-10行,初始化tasklet_vec和tasklet_hi_vec两个数组的元素,使每个元素的tail域指向head域。cpu编号作为两个数组的下标。第12-13行将负责处理tasklet任务的两个软中断函数tasklet_action和tasklet_hi_action分别存入软中断数组softirq_vec[NR_SOFTIRQS]的相应元素中。来看下open_softirq函数(kernel/softirq.c)。
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
softirq_vec[nr].action = action;
}
相信你一看就明白了,不用解释了~
再看看tasklet的初始化过程(kernel/softirq.c):
void tasklet_init(struct tasklet_struct *t,
void (*func)(unsigned long), unsigned long data)
{
t->next = NULL;
t->state = ;
atomic_set(&t->count, );
t->func = func;
t->data = data;
}
该函数接收tasklet_struct结构体指针和小任务函数指针,然后对tasklet_struct结构体进行初始化,并将函数指针赋给t->func域。tasklet_init函数在tasklet_hrtimer_init函数中被调用。
3.tasklet调度(这两个函数分别在include/linux/interrupt.h和kernel/softirq.c文件中)
static inline void tasklet_schedule(struct tasklet_struct *t)
{
if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
__tasklet_schedule(t);
}
void __tasklet_schedule(struct tasklet_struct *t)
{
unsigned long flags; local_irq_save(flags);
t->next = NULL;
*__this_cpu_read(tasklet_vec.tail) = t;
__this_cpu_write(tasklet_vec.tail, &(t->next));
raise_softirq_irqoff(TASKLET_SOFTIRQ);
local_irq_restore(flags);
}
EXPORT_SYMBOL(__tasklet_schedule);
在__tasklet_schedule函数第7-8行,将struct tasklet_struct类型的tasklet挂到taskeletvec数组中,然后第9行进行软中断掩码置位。之后当软中断被执行时,tasklet函数就可以被执行了。
至此,tasklet的初始化就分析完了。
内核源码分析之tasklet(基于3.16-rc4)的更多相关文章
- Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7)
http://blog.chinaunix.net/uid-20543672-id-3157283.html Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3 ...
- Linux内核源码分析方法
一.内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径.我们都 ...
- Linux内核源码分析 day01——内存寻址
前言 Linux内核源码分析 Antz系统编写已经开始了内核部分了,在编写时同时也参考学习一点Linux内核知识. 自制Antz操作系统 一个自制的操作系统,Antz .半图形化半命令式系统,同时嵌入 ...
- 【转】Linux内核源码分析方法
一.内核源码之我见 Linux内核代码的庞大令不少人“望而生畏”,也正因为如此,使得人们对Linux的了解仅处于泛泛的层次.如果想透析Linux,深入操作系统的本质,阅读内核源码是最有效的途径.我们都 ...
- Linux内核源码分析方法_转
Linux内核源码分析方法 转自:http://www.cnblogs.com/fanzhidongyzby/archive/2013/03/20/2970624.html 一.内核源码之我见 Lin ...
- 鸿蒙内核源码分析(文件句柄篇) | 深挖应用操作文件的细节 | 百篇博客分析OpenHarmony源码 | v69.01
百篇博客系列篇.本篇为: v69.xx 鸿蒙内核源码分析(文件句柄篇) | 深挖应用操作文件的细节 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说 ...
- 鸿蒙内核源码分析(VFS篇) | 文件系统和谐共处的基础 | 百篇博客分析OpenHarmony源码 | v68.01
子曰:"质胜文则野,文胜质则史.文质彬彬,然后君子." <论语>:雍也篇 百篇博客系列篇.本篇为: v68.xx 鸿蒙内核源码分析(VFS篇) | 文件系统和谐共处的基 ...
- 鸿蒙内核源码分析(字符设备篇) | 字节为单位读写的设备 | 百篇博客分析OpenHarmony源码 | v67.01
百篇博客系列篇.本篇为: v67.xx 鸿蒙内核源码分析(字符设备篇) | 字节为单位读写的设备 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...
- 鸿蒙内核源码分析(文件系统篇) | 用图书管理说文件系统 | 百篇博客分析OpenHarmony源码 | v63.01
百篇博客系列篇.本篇为: v63.xx 鸿蒙内核源码分析(文件系统篇) | 用图书管理说文件系统 | 51.c.h.o 文件系统相关篇为: v62.xx 鸿蒙内核源码分析(文件概念篇) | 为什么说一 ...
随机推荐
- 嵌入式控制(0)----linux系统网络配置
嵌入式系统本身具有操作系统的全部属性,但收到其硬件条件制约,故需要主机通过串口/网口等方式与其通信.今日下午的工作主要是linux系统的ssh传输配置,nfs服务器配置,tftp服务器配置. ip的概 ...
- Java API —— Collections类
1.Collections类概述 针对集合操作 的工具类,都是静态方法 2.Collections成员方法 public static <T> void ...
- Pig简单入门
pig是hadoop客户端,使用类似于SQL的面向数据流的语言pig latin,这个语言可以完成排序,过滤,求和,关联等操作,可以支持自定义函数.Pig自动把pig latin 映射为Map-Red ...
- 面试题_76_to_81_Java 最佳实践的面试问题
包含 Java 中各个部分的最佳实践,如集合,字符串,IO,多线程,错误和异常处理,设计模式等等. 76)Java 中,编写多线程程序的时候你会遵循哪些最佳实践?(答案)这是我在写Java 并发程序的 ...
- CentOS6.2下fastDFS的完整安装和配置步骤
centos6.2系统下安装配置FastDFS步骤: 1:安装libevent(libevent-2.0.16-stable) ##卸载系统自带libevent rpm -qa|grep libeve ...
- HDU 1233 还是畅通工程(最小生成树,prim)
题意:中文题目 思路:prim实现,因为有n*(n-1)/2条边,已经是饱和的边了,prim比较合适. (1)将点1置为浏览过,点1可以到达其他每个点,所以用low[i]数组记录下目前到达i点的最小长 ...
- Content-Type
HTTP Content-type .*( 二进制流,不知道下载文件类型) application/octet-stream .txt text/plain 没有csv这种类型
- 随机变量的方差variance & 随机向量的协方差矩阵covariance matrix
1.样本矩阵 如果是一个随机变量,那么它的样本值可以用一个向量表示.相对的,如果针对一个随机向量,那么就需要利用矩阵表示,因为向量中的每一个变量的采样值,都可以利用一个向量表示. 然后,一个矩阵可以利 ...
- 两个简单的python文件,实现删除本地文件夹和mongodb数据库的内容
删除本地文件夹: import os , string , datetime ; str = '/home/niuguoqin/tmp/tomcat/'; b = (datetime.datetime ...
- 两个android程序间的相互调用(apk互调)
通常我们用到的只是activity之间的互相跳转和调用,很少会用到apk级别的互相调用. 往往在一些应用上会用到,比如一个支付系统,可能会有很多的一系列的程序调用到:彩票系统.订票系统.团购网……全部 ...