storage R&D guy.
全部博文(1000)
分类: LINUX
2014-05-07 08:41:14
现在的Linux系统中bottom_half功能大多数都已通过softirq或tasklet实现,tasklet是建立在softirq上的,通常由中断处理函数发出。softirq中的HI_SOFTIRQ主要用于实现高优先级的任务,而TASKLET_SOFTIRQ通常用于实现低优先级的任务。
当需要延迟执行的任务,则建立一个tasklet_struct结构的实例,插入HI_SOFTIRQ的列表,或TASKLET_SOFTIRQ的列表。由于softirq是由每个CPU各自独自处理的,所以每个CPU都有自己的HI_SOFTIRQ列表和TASKLET_SOFTIRQ列表。
void __init softirq_init(void)
{
int cpu;
for_each_possible_cpu(cpu) {
int i;
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;
for (i = 0; i < NR_SOFTIRQS; i++)
INIT_LIST_HEAD(&per_cpu(softirq_work_list[i], cpu));
}
register_hotcpu_notifier(&remote_softirq_cpu_notifier);
open_softirq(TASKLET_SOFTIRQ, tasklet_action);
open_softirq(HI_SOFTIRQ, tasklet_hi_action);
}
每个CPU都有自己的tasklet_vec和tasklet_hi_vec链表:
struct tasklet_head
{
struct tasklet_struct *head;
struct tasklet_struct **tail;
};
static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);
softirq_work_list其实是每个CPU的NR_SOFTIRQS个双向链表头数组,每个CPU针对每个softirq都有自己的链表:
DEFINE_PER_CPU(struct list_head [NR_SOFTIRQS], softirq_work_list);
tasklet_action和tasklet_hi_action分别是TASKLET_SOFTIRQ和HI_SOFTIRQ任务的入口执行函数。
tasklet结构为:
struct tasklet_struct
{
struct tasklet_struct *next; //将任务加入对应的softirq链表
unsigned long state;
atomic_t count; //可以暂时关闭或开启这个tasklet,0表示关闭
void (*func)(unsigned long);
unsigned long data;
};
state对应的状态包括:
enum
{
TASKLET_STATE_SCHED, //这个tasklet已进入调度准备执行,相同的任务不能同时在不同的CPU上调度,当第一个tasklet还没开始执行前,其他此tasklet任务请求到来时会被丢弃
TASKLET_STATE_RUN //此tasklet正在被执行中,用于防止相同的tasklet的多个实例被同时执行
};
这几个函数用来互斥地设置tasklet的TASKLET_STATE_RUN标识:
static inline int tasklet_trylock(struct tasklet_struct *t)
{
return !test_and_set_bit(TASKLET_STATE_RUN, &(t)->state);
}
static inline void tasklet_unlock(struct tasklet_struct *t)
{
smp_mb__before_clear_bit();
clear_bit(TASKLET_STATE_RUN, &(t)->state);
}
static inline void tasklet_unlock_wait(struct tasklet_struct *t)
{
while (test_bit(TASKLET_STATE_RUN, &(t)->state)) { barrier(); }
}
tasklet相关的函数:
void tasklet_init(struct tasklet_struct *t,
void (*func)(unsigned long), unsigned long data)
{
t->next = NULL;
t->state = 0;
atomic_set(&t->count, 0);
t->func = func;
t->data = data;
}
2.分别执行tasklet和hi_tasklet的任务
static void tasklet_action(struct softirq_action *a)
{
struct tasklet_struct *list;
local_irq_disable(); //关闭中断
list = __this_cpu_read(tasklet_vec.head); //取tasklet的链表得值,然后重置链表头
__this_cpu_write(tasklet_vec.head, NULL);
__this_cpu_write(tasklet_vec.tail, &__get_cpu_var(tasklet_vec).head);
local_irq_enable();
while (list) { //遍历,执行tasklet
struct tasklet_struct *t = list;
list = list->next;
if (tasklet_trylock(t)) { //锁定task
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(); //将未执行完的task,加入链表尾
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();
}
}
对hi_softirq的task一样:
static void tasklet_hi_action(struct softirq_action *a)
{
struct tasklet_struct *list;
local_irq_disable();
list = __this_cpu_read(tasklet_hi_vec.head);
__this_cpu_write(tasklet_hi_vec.head, NULL);
__this_cpu_write(tasklet_hi_vec.tail, &__get_cpu_var(tasklet_hi_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_hi_vec.tail) = t;
__this_cpu_write(tasklet_hi_vec.tail, &(t->next));
__raise_softirq_irqoff(HI_SOFTIRQ);
local_irq_enable();
}
}
3.分别enable和disable task
//enable是一样的,用于开启tasklet
static inline void tasklet_enable(struct tasklet_struct *t)
{
smp_mb__before_atomic_dec();
atomic_dec(&t->count);
}
static inline void tasklet_hi_enable(struct tasklet_struct *t)
{
smp_mb__before_atomic_dec();
atomic_dec(&t->count);
}
//diable共用一样的,关闭tasklet
static inline void tasklet_disable(struct tasklet_struct *t)//同步,tasklet终止执行后才返回
{
tasklet_disable_nosync(t);
tasklet_unlock_wait(t);
smp_mb();
}
static inline void tasklet_disable_nosync(struct tasklet_struct *t) //异步
{
atomic_inc(&t->count);
smp_mb__after_atomic_inc();
}
4.为低优先级和高优先级的tasklet调度,准备执行,将tasklet_struct结构添加到本地CPU管理的任务链表中,然后为softirq的TASKLET_SOFTIRQ或HI_SOFTIRQ调度,若tasklet已进入调度,则不做任何事。
static inline void tasklet_schedule(struct tasklet_struct *t)
{
if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) //设置tasklet_struct的state值,为TASKLET_STATE_SCHED,若原来未设置,则将task加入链表
__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); //设置TASKLET_SOFTIRQ softirq的调度尾
local_irq_restore(flags);
}
//同理
static inline void tasklet_hi_schedule(struct tasklet_struct *t)
{
if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
__tasklet_hi_schedule(t);
}
void __tasklet_hi_schedule(struct tasklet_struct *t)
{
unsigned long flags;
local_irq_save(flags);
t->next = NULL;
*__this_cpu_read(tasklet_hi_vec.tail) = t;
__this_cpu_write(tasklet_hi_vec.tail, &(t->next));
raise_softirq_irqoff(HI_SOFTIRQ);
local_irq_restore(flags);
}