linux softirq tasklet 软中断实现

linux内核中断管理分为上下半部机制(top half,bottom half)。中断上半部主要关注中断的响应,而把具体需要关注的任务放到中断下半部中来处理,其中网卡MAC控制器中断的处理是使用软中断来进行下半部处理的典型。

硬件中断属于上半部的范畴,而软中断,tasklet和工作队列等为下半部机制。中断处理程序ISR中不允许进行睡眠,同理在软中断中也是不允许进行睡眠。

1、SoftIRQ软中断

软中断是linux内核很早引入的机制。软中断是预留给系统中对时间要求最为严格和最重要的下半部使用的,而且目前驱动中只有块设备和网络子系统使用了软中断。

系统静态定义了若干种软中断类型,并且linux内核开发者不希望用户再扩充新的软中断类型,如有需要,建议使用tasklet机制。

1.1、数据结构

/* PLEASE, avoid to allocate new softirqs, if you need not _really_ high
   frequency threaded job scheduling. For almost all the purposes
   tasklets are more than enough. F.e. all serial device BHs et
   al. should be converted to tasklets, not to softirqs.
 */

enum
{
	HI_SOFTIRQ=0,
	TIMER_SOFTIRQ,
	NET_TX_SOFTIRQ,
	NET_RX_SOFTIRQ,
	BLOCK_SOFTIRQ,
	BLOCK_IOPOLL_SOFTIRQ,
	TASKLET_SOFTIRQ,
	SCHED_SOFTIRQ,
	HRTIMER_SOFTIRQ,
	RCU_SOFTIRQ,    /* Preferable RCU should always be the last softirq */

	NR_SOFTIRQS
};
通过枚举类型来静态声明软中断,并且每一种软中断都使用索引来表示一种相对的优先级,索引号越小,中断优先级越高,并在一轮软中断中得到优先执行。

struct softirq_action
{
	void	(*action)(struct softirq_action *);
};

static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;

typedef struct {
	unsigned int __softirq_pending;
#ifdef CONFIG_SMP
	unsigned int ipi_irqs[NR_IPI];
#endif
} ____cacheline_aligned irq_cpustat_t;

irq_cpustat_t irq_stat[NR_CPUS] ____cacheline_aligned;

1.2、接口说明

/*注册软中断,nr为软中断序号*/
void open_softirq(int nr, void (*action)(struct softirq_action *))
{
	softirq_vec[nr].action = action;
}


/*主动触发一个软中断*/
void raise_softirq(unsigned int nr)
{
	unsigned long flags;

	local_irq_save(flags); /*关本地中断*/
	raise_softirq_irqoff(nr);
	local_irq_restore(flags); /*开本地中断*/
}

/*
 * This function must run with irqs disabled!
 */
inline void raise_softirq_irqoff(unsigned int nr)
{
	__raise_softirq_irqoff(nr);

	/*
	 * If we're in an interrupt or softirq, we're done
	 * (this also catches softirq-disabled code). We will
	 * actually run the softirq once we return from
	 * the irq or softirq.
	 *
	 * Otherwise we wake up ksoftirqd to make sure we
	 * schedule the softirq soon.
	 */
	if (!in_interrupt()) /*非中断上下文即运行在进程上下文*/
		wakeup_softirqd(); /*唤醒ksoftirqd%u*/
}


raise_softirq和raise_softirq_irqoff差别在于是否关闭本地中断。

void __raise_softirq_irqoff(unsigned int nr)
{
	trace_softirq_raise(nr);
	or_softirq_pending(1UL << nr);
}

#define __IRQ_STAT(cpu, member)	(irq_stat[cpu].member)
#define local_softirq_pending() __IRQ_STAT(smp_processor_id(), __softirq_pending)
	
#define set_softirq_pending(x) (local_softirq_pending() = (x))
#define or_softirq_pending(x)  (local_softirq_pending() |= (x))

raise_softirq:主动设置softirq处于pending状态,如果当前处于非中断上下文时(非硬中断也非软中断上下文)唤醒ksoftirqd%u内核线程来处理软中断事件。

 中断退出时,irq_exit()函数会检查当前是否有pending等待的软中断。

/*
 * Exit an interrupt context. Process softirqs if needed and possible:
 */
void irq_exit(void)
{
#ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED
	local_irq_disable();
#else
	WARN_ON_ONCE(!irqs_disabled());
#endif

	account_irq_exit_time(current);
	/*preempt_count上退出硬中断*/
	preempt_count_sub(HARDIRQ_OFFSET);

	if (!in_interrupt()/*非中断上下文*/ && local_softirq_pending()/*存在本地软中断pending*/)
		invoke_softirq();

	tick_irq
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值