中断子系统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;

}


你可能感兴趣的:(系统)