中断子系统8_软中断入口处理

//	irq统计信息
1.1 typedef struct {
	unsigned int __softirq_pending;//softirq标志位,32种softirq
	unsigned long idle_timestamp;
	unsigned int __nmi_count;	//nmi中断发生次数
	unsigned int apic_timer_irqs;	/* arch dependent */
} ____cacheline_aligned irq_cpustat_t;

//	检查softirq标志是否被置位
1.2 #define local_softirq_pending() \
	__IRQ_STAT(smp_processor_id(), __softirq_pending)

//	per-cpu irq统计信息
1.3 #define __IRQ_STAT(cpu, member)	(irq_stat[cpu].member)



//	软中断入口函数
//	调用路径 __do_IRQ->irq_exit->do_softirq
//	函数主要任务:
//		1.确保没有hardirq,softirq运行情况,否则直接退出
//		2.关中断,检查是否有raise的softirq
//			2.1 执行软中断处理函数
//		3.恢复中断状态
//	注:
//		1.软中断执行过程中,开中断,关软中断,禁止内核抢占
//		2.do_softirq会在中断、softirqd两条路径上被调用,同时只有一个在执行
2.1 asmlinkage void do_softirq(void)
{
	__u32 pending;
	unsigned long flags;

	//如果当前有hardirq,softirq在运行中,直接退出
	if (in_interrupt())
		return;
	//关中断下检查softirq标志
	local_irq_save(flags);
	pending = local_softirq_pending();
	//执行softirq处理函数
	if (pending)
		__do_softirq();
	//恢复之前的中断状态
	local_irq_restore(flags);
}


//	执行软中断处理函数
//	调用路径 __do_IRQ->irq_exit->do_softirq->__do_softirq
//	函数主要任务:
//		1.获取raise的softirq比特位
//		2.禁止本cpu的softirq
//		3.清除softirq标志位
//		4.开中断		
//		5.遍历softirq_vec,执行被raise的softirq_action的处理函数
//		6.关中断
//		7.检查softirq标志位
//			7.1 如果有raise的softirq,并且没有超过最大的遍历次数,重复步骤3
//			7.2 否则,唤醒softirq核心进程处理softirq
//		8.开启本cpu的softirq
2.2 asmlinkage void __do_softirq(void)
{
	struct softirq_action *h;
	__u32 pending;
	//最大遍历次数10次
	int max_restart = MAX_SOFTIRQ_RESTART;
	int cpu;
	//本cpu被raise的softirq
	pending = local_softirq_pending();
	//禁止本cpu softirq
	local_bh_disable();
	cpu = smp_processor_id();
restart:
	//softirq标志位清空
	local_softirq_pending() = 0;
	//开中断
	local_irq_enable();

	h = softirq_vec;

	do {
		if (pending & 1) {
			h->action(h);
			rcu_bh_qsctr_inc(cpu);
		}
		h++;
		pending >>= 1;
	} while (pending);

	local_irq_disable();

	pending = local_softirq_pending();
	if (pending && --max_restart)
		goto restart;
	//超过最大的调用次数,唤醒softirq核心进程
	if (pending)
		wakeup_softirqd();
	//开启软中断
	__local_bh_enable();
}

//	禁止本cpu softirq
2.2 #define local_bh_disable() \
		do { add_preempt_count(SOFTIRQ_OFFSET); barrier(); } while (0)


//	唤醒softirq进程
//	函数主要任务:
//		1.获取本cpu的softirq进程
//		2.如果进程未执行,唤醒其
//	注:
//		关中断,关软中断状态下唤醒softirq进程
3.1 static inline void wakeup_softirqd(void)
{
	//per cpu进程
	struct task_struct *tsk = __get_cpu_var(ksoftirqd);
	//softirq进程非就绪状态
	if (tsk && tsk->state != TASK_RUNNING)
	{
		wake_up_process(tsk);//唤醒进程
	}
}

//	softirq核心进程function
//	函数主要任务:
//		1.检查softirq标志
//		2.禁止内核抢占
//		3.通过do_softirq执行软中断处理函数
//		4.开启内核抢占
//	注:
//		1.软中断执行过程中,开中断,关软中断,禁止内核抢占
//		2.do_softirq会在中断、softirqd两条路径上被调用,同时只有一个在执行
3.2 static int ksoftirqd(void * __bind_cpu)
{
	//设置静态优先级
	set_user_nice(current, 19);
	//当前进程不允许被frozen
	current->flags |= PF_NOFREEZE;
	//可中断睡眠
	set_current_state(TASK_INTERRUPTIBLE);
	while (!kthread_should_stop()) {
		//没有raised的softirq,调度
		if (!local_softirq_pending())
		{
			schedule();
		}	
		//进程被唤醒
		__set_current_state(TASK_RUNNING);
		//检查softirq标志
		while (local_softirq_pending()) {
			//禁止内核抢占
			preempt_disable();
			//与中断路径执行相同的处理函数,二者同时只有一个在执行
			do_softirq();
			//开启内核抢占
			preempt_enable();
			//检查是否need reschedule
			cond_resched();
		}

		set_current_state(TASK_INTERRUPTIBLE);
	}
	//设置进程为运行状态,然后退出
	//此进程不再会被wakeup_softirqd唤醒执行
	__set_current_state(TASK_RUNNING);
	return 0;
}

//	softirq数组
//		irq_cpustat_t->__softirq_pending只有32bit,因此共有32种软中断
4.1 static struct softirq_action softirq_vec[32] __cacheline_aligned_in_smp;

//	softirq描述符
4.2 struct softirq_action
{
	void	(*action)(struct softirq_action *);
	void	*data;
};

//	静态编译的软中断类型
4.3 enum
{
	HI_SOFTIRQ=0,
	TIMER_SOFTIRQ,
	NET_TX_SOFTIRQ,
	NET_RX_SOFTIRQ,
	SCSI_SOFTIRQ,
	TASKLET_SOFTIRQ
};

//	raise softirq
//	注:
//		调用者负责调用前禁止中断
5.1 inline fastcall void raise_softirq_irqoff(unsigned int nr)
{
	//设置对应的bit位
	__raise_softirq_irqoff(nr);
	//当前不在中断上下文中,唤醒softirq进程
	if (!in_interrupt())
		wakeup_softirqd();
}
//	raise softirq
//	注:
//		本函数会负责关闭中断
5.2 void fastcall raise_softirq(unsigned int nr)
{
	unsigned long flags;
	//关中断
	local_irq_save(flags);
	raise_softirq_irqoff(nr);
	local_irq_restore(flags);
}
//	注册softirq
5.3 void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
{
	softirq_vec[nr].data = data;
	softirq_vec[nr].action = action;
}


转载于:https://www.cnblogs.com/riasky/p/3429350.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值