linux中斷處理子(zǐ)系統小結
發表時(shí)間:2020-10-19
發布人(rén):融晨科技
浏覽次數:60
前面的(de)博文中, 大(dà)年夜緻分散介紹了(le/liǎo)一些中斷相幹的(de)器械, 然則對軟中斷的(de)部分沒有細心介紹, 在(zài)這(zhè)裏同一總結一下.
中斷上(shàng)半部的(de)處理,彙編到(dào)request_irq的(de)handle之(zhī)間的(de)過程.
http://blog.csdn.net/jackjones_008/article/details/42387241
MIPS平台的(de)一點記錄
http://blog.csdn.net/jackjones_008/article/details/41945909
tasklet/workqueue的(de)介紹鄙人(rén)面這(zhè)篇博文中有比較具體的(de)介紹.
http://blog.csdn.net/jackjones_008/article/details/42295411
中斷的(de)處理, 起首當然是(shì)硬件中斷産生後彙編部分的(de)處理, 然後在(zài)hardirq處理完之(zhī)後, 在(zài)函數irq_exit中, 如不(bù)雅發明當前沒有hardirq并且softirq沒有被禁止,
也(yě)沒有pending的(de)本地(dì / de)softirq, 則會顯示的(de)調用do_softirq 去處理softirq. 在(zài)處理softirq的(de)過程中, 是(shì)會樊籬硬件中斷的(de).
asmlinkage void do_softirq(void) { __u32 pending; unsigned long flags; if (in_interrupt()) return; local_irq_save(flags); pending = local_softirq_pending(); if (pending) __do_softirq(); local_irq_restore(flags); }
在(zài)__do_softirq 琅绫擎, 在(zài)獲得pending的(de)softirq後, 又會打開硬件中斷. 然後會去依次處理pending 的(de)softirq.
這(zhè)個(gè)依次, 其實就(jiù)是(shì)根據enum中的(de)定義大(dà)年夜 HI_SOFTIRQ 履行到(dào) RCU_SOFTIRQ.
再多煩瑣一下, 爲(wéi / wèi)什麽會有pending的(de)softirq呢, 因爲(wéi / wèi)代碼有些處所去調用了(le/liǎo) __raise_softirq_irqoff .
我們還可以(yǐ)留意到(dào), __do_softirq 琅绫擎定義了(le/liǎo)一個(gè)max_restart, 這(zhè)個(gè)值是(shì)10, 是(shì)體系的(de)一個(gè)折中, 處理軟中斷, 然則不(bù)克不(bù)及過度的(de)影響其他(tā)過程的(de)履行.
完成不(bù)了(le/liǎo)的(de), 可以(yǐ)交給 ksoftirqd 這(zhè)個(gè)内核thread去做.
asmlinkage void __do_softirq(void) { struct softirq_action *h; __u32 pending; int max_restart = MAX_SOFTIRQ_RESTART; int cpu; pending = local_softirq_pending(); account_system_vtime(current); __local_bh_disable((unsigned long)__builtin_return_address(0)); trace_softirq_enter(); cpu = smp_processor_id(); restart: /* Reset the pending bitmask before enabling irqs */ set_softirq_pending(0); local_irq_enable(); h = softirq_vec; do { if (pending & 1) { int prev_count = preempt_count(); h->action(h); if (unlikely(prev_count != preempt_count())) { printk(KERN_ERR "huh, entered softirq %td %p" "with preempt_count %08x," " exited with %08x?\n", h - softirq_vec, h->action, prev_count, preempt_count()); preempt_count() = prev_count; } rcu_bh_qsctr_inc(cpu); } h++; pending >>= 1; } while (pending); local_irq_disable(); pending = local_softirq_pending(); if (pending && --max_restart) goto restart; if (pending) wakeup_softirqd(); trace_softirq_exit(); account_system_vtime(current); _local_bh_enable(); }
enum { HI_SOFTIRQ=0, TIMER_SOFTIRQ, NET_TX_SOFTIRQ, NET_RX_SOFTIRQ, BLOCK_SOFTIRQ, TASKLET_SOFTIRQ, SCHED_SOFTIRQ, HRTIMER_SOFTIRQ, RCU_SOFTIRQ, /* Preferable RCU should always be the last softirq */ NR_SOFTIRQS };
接上(shàng), restart 中處理完後, 還有pending的(de)softirq的(de)話, 就(jiù)交給内核過程 ksoftirqd 去做. 這(zhè)個(gè)内核過程也(yě)揮菰式的(de)調用 do_softirq 去處理.
static int ksoftirqd(void * __bind_cpu) { set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { preempt_disable(); if (!local_softirq_pending()) { preempt_enable_no_resched(); schedule(); preempt_disable(); } __set_current_state(TASK_RUNNING); while (local_softirq_pending()) { /* Preempt disable stops cpu going offline. If already offline, we'll be on wrong CPU: don't process */ if (cpu_is_offline((long)__bind_cpu)) goto wait_to_die; do_softirq(); preempt_enable_no_resched(); cond_resched(); preempt_disable(); rcu_qsctr_inc((long)__bind_cpu); } preempt_enable(); set_current_state(TASK_INTERRUPTIBLE); } __set_current_state(TASK_RUNNING); return 0; wait_to_die: preempt_enable(); /* Wait for kthread_stop */ set_current_state(TASK_INTERRUPTIBLE); while (!kthread_should_stop()) { schedule(); set_current_state(TASK_INTERRUPTIBLE); } __set_current_state(TASK_RUNNING); return 0; }
這(zhè)時(shí), 又弗成避免的(de)回到(dào)了(le/liǎo)中斷上(shàng)半部和(hé / huò)下半部的(de)話題, 上(shàng)半部我們可以(yǐ)懂得爲(wéi / wèi)一向履行到(dào) request_irq 中注冊的(de)那個(gè) handle 爲(wéi / wèi)止. 而(ér)softirq 開端的(de)處理都是(shì)屬于(yú)下半部的(de)處理.
鄙人(rén)半部的(de)處理中, 根據睡眠與否可以(yǐ)應用tasklet和(hé / huò)workqueue的(de)機制.
其實tasklet也(yě)是(shì)屬于(yú)softirq的(de)一種, 并且弗成睡眠. workqueue的(de)機制則是(shì)交給了(le/liǎo)内核thread去履行, 可以(yǐ)許可睡眠.