|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
常常有些朋友在Linux论坛问一些问题,不过,其中大多数的问题都是很基的。
tasklet是Linux内核中“可提早实行”机制、或“中止下半部”的一种。基于软中止完成,但比软中止天真,tasklet有的中央翻译作“义务蕾”,年夜部分书本没找到符合的辞汇往翻译它。本篇博客次要先容tasklet的计划道理、利用办法。
本篇博客耗时8小时。
1、tasklet办理甚么成绩?
先看下tasklet在一些书本上的先容:
- tasklet是I/O驱动程序中完成可提早函数的首选办法(我猜某个内核版本入手下手,块设备从tasklet中自力出来成为独自的软中止BLOCK_SOFTIRQ和BLOCK_IOPOLL_SOFTIRQ)——ULK。
- tasklet和事情行列是延期实行事情的机制,实在现基于软中止,但他们更容易于利用,因此更合适与设备驱动程序...tasklet是“小历程”,实行一些迷你义务,对这些人物利用全功效历程大概对照华侈——PLKA。
- tasklet是并行可实行(可是是锁麋集型的)软件中止和旧下半区的一种夹杂体,这里既谈不上并行性,也谈不上功能。引进tasklet是为了替换本来的下半区。
上面这段来自于PLKA的话我也很想留在这里:软中止是将操纵推延到将来时候实行的最无效的办法。但该延期机制处置起来十分庞大。由于多个处置器能够同时且自力的处置软中止,统一个软中止的处置程序能够在几个CPU上同时运转。对软中止的效力来讲,这是一个关头,多处置器体系上的收集完成明显沾恩于此。但处置程序的计划必需是完整可重进且线程平安的。别的,临界区必需用自旋锁回护(或其他IPC机制),而这必要大批谨慎的思索。
我本人的了解,因为软中止以ksoftirqd的情势与用户历程配合调剂,这将干系到OS全体的功能,因而软中止在Linux内核中也仅仅就几个(收集、时钟、调剂和Tasklet等),在内核编译时断定。软中止这类办法明显不是面向硬件驱动的,而是驱动更上一层:不体贴怎样从详细的网卡吸收数据包,可是从一切的网卡吸收的数据包都要经由内核协定栈的处置。并且软中止对照“硬”——数目流动、编译时断定、操纵函数必需可重进、必要稳重思索锁的成绩,不合适驱动间接挪用,因而Linux内核为驱动间接供应了一种利用软中止的办法,就是tasklet。
2、tasklet数据布局
tasklet经由过程软中止完成,软中止中有两品种型属于tasklet,分离是级别最高的HI_SOFTIRQ和TASKLET_SOFTIRQ。
Linux内核接纳两个PER_CPU的数组tasklet_vec[]和tasklet_hi_vec[]保护体系种的一切tasklet(kernel/softirq.c),分离保护TASKLET_SOFTIRQ级别和HI_SOFTIRQ级其余tasklet:
1
2
3
4
5
6
7
8
structtasklet_head
{
structtasklet_struct*head;
structtasklet_struct**tail;
};
staticDEFINE_PER_CPU(structtasklet_head,tasklet_vec);
staticDEFINE_PER_CPU(structtasklet_head,tasklet_hi_vec);
<br>
tasklet的中心布局体以下(include/linux/interrupt.h):
1
2
3
4
5
6
7
8
structtasklet_struct
{
structtasklet_struct*next;
unsignedlongstate;
atomic_tcount;
void(*func)(unsignedlong);
unsignedlongdata;
};
习气上称之为tasklet形貌符,func指针是详细的处置函数指针,data为可选参数,state暗示该tasklet的形态,分离利用分歧的bit暗示两个形态:TASKLET_STATE_SCHED和TASKLET_STATE_RUN:
- TASKLET_STATE_SCHED置位暗示已被调剂(挂起),也意味着tasklet形貌符被拔出到了tasklet_vec和tasklet_hi_vec数组的个中一个链表中,能够被实行。
- TASKLET_STATE_RUN置位暗示该tasklet正在某个CPU上实行,单个处置器体系上其实不校验该标记,由于没需要反省特定的tasklet是不是正在运转。
count为原子计数器,用于禁用已调剂的tasklet,假如该值不为0,则不予以实行。
3、tasklet操纵接口
tasklet对驱动开放的经常使用操纵包含:
- 初始化,tasklet_init(),初始化一个tasklet形貌符。
- 调剂,tasklet_schedule()和tasklet_hi_schedule(),将taslet置位TASKLET_STATE_SCHED,并实验激活地点的软中止。
- 禁用/启动,tasklet_disable_nosync()、tasklet_disable()、task_enable(),经由过程count计数器完成。
- 实行,tasklet_action()和tasklet_hi_action(),详细的实行软中止。
- 杀逝世,tasklet_kill(),。。。
tasklet_int()函数完成以下(kernel/softirq.c):
1
2
3
4
5
6
7
8
9
voidtasklet_init(structtasklet_struct*t,
void(*func)(unsignedlong),unsignedlongdata)
{
t->next=NULL;
t->state=0;
atomic_set(&t->count,0);
t->func=func;
t->data=data;
}
tasklet_schedule()函数与tasklet_hi_schedule()函数的完成很相似,这里只列tasklet_schedule()函数的完成(kernel/softirq.c),都挺分明就不形貌了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
staticinlinevoidtasklet_schedule(structtasklet_struct*t)
{
if(!test_and_set_bit(TASKLET_STATE_SCHED,&t->state))
__tasklet_schedule(t);
}
void__tasklet_schedule(structtasklet_struct*t)
{
unsignedlongflags;
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);
}
tasklet_disable()函数、task_enable()函数和tasklet_disable_nosync()函数(include/linux/interrupt.h),不说了只列代码:
<p>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
staticinlinevoidtasklet_disable_nosync(structtasklet_struct*t)
{
atomic_inc(&t->count);
smp_mb__after_atomic_inc();
}
<p>staticinlinevoidtasklet_disable( |
|