Softirqs
在编译期间静态分配,一般采用tasklet会更好,Softirq适用于对于时间要求严格并能自己高效地完成加锁工作的应用。
目前只有网络和SCSI两个子系统直接使用软中断,内核定时器和tasklet都是基于softirq实现的。
softirq 的类型
enum
{
HI_SOFTIRQ=0,
TIMER_SOFTIRQ,
NET_TX_SOFTIRQ,
NET_RX_SOFTIRQ,
BLOCK_SOFTIRQ,
TASKLET_SOFTIRQ,
SCHED_SOFTIRQ,
#ifdef CONFIG_HIGH_RES_TIMERS
HRTIMER_SOFTIRQ,
#endif
RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */
};
注册softirq
void open_softirq(int nr, void (*action)(struct softirq_action *))
如:
open_softirq(NET_TX_SOFTIRQ, net_tx_action);
open_softirq(NET_RX_SOFTIRQ, net_rx_action);
执行softirq
asmlinkage void do_softirq(void)
触发softirq
void raise_softirq(unsigned int nr)
此函数可将一个软中断设置为挂起状态,并让它在下次do_softirq()被调用时投入运行,使用该函数之前须先禁止中断。
常见的softirq触发一般在ISR中进行,ISR执行完硬件设备的相关操作后,然后触发相应的软中断,最后退出ISR,接着内核在执行完ISR退出以后,马上调用do_softirq函数,让sotfirq完成ISR剩下的工作。
softirq的处理程序如net_tx_action在执行时,本地的硬件中断是激活的,而本地软中断是被禁止的, 但它自己不能休眠。
相同类型和不同类型的软中断可以在其它处理器上同时执行,这表明任何共享数据,包括软中断处理程序内部使用的全局变量,都需要严格的锁保护。
-------------------------------------------------------------------------------------------------------------------------
Tasklets
基于softirq实现的,分别为 HI_SOFTIRQ 和 TASKLET_SOFTIRQ 两种。
HI_SOFTIRQ 先于 TASKLET_SOFTIRQ 运行。
Tasklets有两种状态定义:
TASKLET_STATE_SCHED, /* Tasklet is scheduled for execution */
TASKLET_STATE_RUN /* Tasklet is running (SMP only) */
创建Tasklets
静态方式:
DECLARE_TASKLET(name, func, data)
DECLARE_TASKLET_DISABLED(name, func, data)
动态方式:
tasklet_init(struct tasklet_struct *t,
void (*func)(unsigned long), unsigned long data);
调度、执行tasklet:
HI_SOFTIRQ 类型:
static inline void tasklet_hi_schedule(struct tasklet_struct *t)
--> 唤醒Softirq
static void tasklet_hi_action(struct softirq_action *a)
--> 执行softirq
TASKLET_SOFTIRQ 类型:
static inline void tasklet_schedule(struct tasklet_struct *t)
--> 唤醒Softirq
static void tasklet_action(struct softirq_action *a)
--> 执行softirq
使能、禁止和杀死tasklet
static inline void tasklet_enable(struct tasklet_struct *t)
static inline void tasklet_disable(struct tasklet_struct *t)
static inline void tasklet_disable_nosync(struct tasklet_struct *t)
void tasklet_kill(struct tasklet_struct *t);
void tasklet_kill_immediate(struct tasklet_struct *t, unsigned int cpu);
同一时间里,相同类型的tasklet只能有一个执行,即使在SMP下,相同的tasklet不能同时在不同的CPU上执行,但不同的的tasklet则可以在不同的CPU上同时执行。因此,如果tasklet和其他tasklet或者softirq共享了数据,则必须采取适当的锁保护。
tasklet不能睡眠,因此不能在其中使用信号量或者阻塞式的函数。
tasklet运行时允许响应中断,因此如果tasklet和ISR之间共享数据时,需要采取关中断,获取锁等措施。
在tasklet被调度以后,只要有机会,它就会尽可能早地运行。在没有运行之前,如果有一个相同的tasklet被调度了,那么它仍然只运行一次;如果此时它已经在另一个CPU开始运行了,那么这个新的tasklet会被重新调度并再次运行。
阅读(738) | 评论(0) | 转发(0) |