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