书本上tasklet就是基于softirq来实现的,下面的就从代码看看他们是怎么实现的。首先搞清楚softirq是怎么一回事,linux内核里面定义这几种softirq(可能内核版本不同,定义不同)
enum { HI_SOFTIRQ=0, TIMER_SOFTIRQ, NET_TX_SOFTIRQ, NET_RX_SOFTIRQ, SCSI_SOFTIRQ, TASKLET_SOFTIRQ };
然后在看看怎么去注册一个softirq
void open_softirq(int nr, void (*action)(struct softirq_action*), void *data) { softirq_vec[nr].data = data; softirq_vec[nr].action = action; }
其中的action就是softirq的handler,那么我们再看看内核启动的过程中已经注册哪些softirq(目前只关注tasklet基于的HI_SOFTIRQ,TASKLET_SOFTIRQ)void __init softirq_init(void) { open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL); open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL); }
这里很明显地看到,内核注册了TASKLET_SOFTIRQ和HI_SOFTIRQ这两个类型的softirq,而其对于的handler分别是tasklet_action,tasklet_hi_action。其实tasklet的实现就关键这两个handler里面,那么我就进入其中一个看看
static void tasklet_action(struct softirq_action *a) { struct tasklet_struct *list; local_irq_disable(); list = __get_cpu_var(tasklet_vec).list; __get_cpu_var(tasklet_vec).list = NULL; 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 = __get_cpu_var(tasklet_vec).list; __get_cpu_var(tasklet_vec).list = t; __raise_softirq_irqoff(TASKLET_SOFTIRQ); local_irq_enable(); } }
从代码可以看出,这个handler关键获取list = __get_cpu_var(tasklet_vec).list; 然后就执行里面的的函数,而这个链表就是tasklet的链表。那么我先看看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; }
struct tasklet_struct { struct tasklet_struct *next; unsigned long state; atomic_t count; void (*func)(unsigned long); unsigned long data; };
static inline void tasklet_schedule(struct tasklet_struct *t) { if (!test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) __tasklet_schedule(t); }
void fastcall __tasklet_schedule(struct tasklet_struct *t) { unsigned long flags; local_irq_save(flags); t->next = __get_cpu_var(tasklet_vec).list; __get_cpu_var(tasklet_vec).list = t; raise_softirq_irqoff(TASKLET_SOFTIRQ); local_irq_restore(flags); }
上面几条函数分别初始化和注册一个tasklet,而注册一个tasklet就是把tasklet对于的结构体插入链表里。
总的来说,就是注册一个softirq,然后在这个softirq的handler里面找到tasklet链表,然后再执行相应的函数,严格来说这里是注册两个softirq,因为有两个不同类型的tasklet。所以说tasklet的实现就是基于softirq。
linux softirq和tasklet的关系
最新推荐文章于 2024-01-08 22:03:34 发布