閱讀755 返回首頁    go 魔獸


中斷子係統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;
}

最後更新:2017-04-03 14:54:23

  上一篇:go Mysql純命令行添加用戶
  下一篇:go 如何停止JAVA線程