tasklet
有的时候内核同步的场景不需disable所有的softirq和tasklet,而仅仅是disable该tasklet,这时候,tasklet_disable和tasklet_enable就派上用场了。其实现即是给对应tasklet结构体的count成员变量加减1。如果count等于0那么该tasklet是处于enable的,如果大于0,表示该tasklet是disable的。
struct tasklet_struct
{
struct tasklet_struct *next;
unsigned long state;
atomic_t count;
void (*func)(unsigned long);
unsigned long data;
};
系统中的每个cpu都会维护一个tasklet的链表:
static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);
调度一个tasklet使用接口:tasklet_schedule。程序在多个上下文中可以多次调度同一个tasklet执行(也可能来自多个cpu core),不过实际上该tasklet只会一次挂入首次调度到的那个cpu的tasklet链表,也就是说,即便是多次调用tasklet_schedule,实际上tasklet只会挂入一个指定CPU的tasklet队列中(而且只会挂入一次),也就是说只会调度一次执行。这是通过TASKLET_STATE_SCHED这个flag来完成的
softirq的执行时机:
(1)在中断返回用户空间(进程上下文)的时候,如果有pending的softirq,那么将执行该softirq的处理函数。
(2)上面的描述缺少了一种场景:中断返回内核态的进程上下文的场景。进程上下文中调用local_bh_enable的时候
(3)系统太繁忙了,不断的产生中断,raise softirq,由于bottom half的优先级高,从而导致进程无法调度执行。这种情况下,softirq会推迟到softirqd这个内核线程中去执行。