755
魔獸
中斷子係統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