亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費注冊 查看新帖 |

Chinaunix

  平臺 論壇 博客 文庫
最近訪問板塊 發(fā)新帖
查看: 1067 | 回復(fù): 0
打印 上一主題 下一主題

Linux 內(nèi)核軟中斷(softirq)執(zhí)行分析 [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報告]
發(fā)表于 2009-07-27 13:49 |只看該作者 |倒序瀏覽
引自:
http://www.whitecell.org/list.php?id=44


Linux 內(nèi)核軟中斷(softirq)執(zhí)行分析
Author:  sinister
Email:   sinister@whitecell.org
Homepage:http://www.whitecell.org
Date:    2007-01-11
本文對 Linux 內(nèi)核軟中斷的執(zhí)行流程進(jìn)行了分析,并盡可能的結(jié)合當(dāng)前運
行環(huán)境詳細(xì)地寫出我的理解,但這并不表明我的理解一定正確。這本是論壇
里的一篇帖子,發(fā)出來是為了拋磚引玉,如果您在閱讀本文時發(fā)現(xiàn)了我的錯
誤,還望得到您的指正。
今天無意中看了眼 2.6 內(nèi)核的軟中斷實現(xiàn),發(fā)現(xiàn)和以前我看到的大不相同
(以前也是走馬觀花,不大仔細(xì)),可以說改動很大。連 softirq 的調(diào)用
點都不一樣了,以前是三個調(diào)用點,今天搜索了一下源代碼,發(fā)現(xiàn)在多出了
ksoftirqd 后,softirq 在系統(tǒng)中的調(diào)用點僅是在 ISR 返回時和使用了
local_bh_enable() 函數(shù)后被調(diào)用了。網(wǎng)卡部分的顯示調(diào)用,我覺得應(yīng)該不
算是系統(tǒng)中的調(diào)用點。ksoftirqd 返回去調(diào)用 do_softirq() 函數(shù)應(yīng)該也只
能算是其中的一個分支,因為其本身從源頭上來講也還是在 ISR 返回時
irq_exit() 調(diào)用的。這樣一來就和前些日子寫的那份筆記(Windows/Linux
/Solaris 軟中斷機(jī)制)里介紹的 Linux 內(nèi)核部分的軟中斷有出處了,看來
以后討論 Linux kernel 代碼一定要以內(nèi)核版本為前題,要不非亂了不可。
得買本 Linux 方面的書了,每次上來直接看相關(guān)代碼也不是回事,時間也
不允許。
//
// do_IRQ 函數(shù)執(zhí)行完硬件 ISR 后退出時調(diào)用此函數(shù)。
//
void irq_exit(void)
{
        account_system_vtime(current);
        trace_hardirq_exit();
        sub_preempt_count(IRQ_EXIT_OFFSET);
        //
        // 判斷當(dāng)前是否有硬件中斷嵌套,并且是否有軟中斷在
        // pending 狀態(tài),注意:這里只有兩個條件同時滿足
        // 時,才有可能調(diào)用 do_softirq() 進(jìn)入軟中斷。也就是
        // 說確認(rèn)當(dāng)前所有硬件中斷處理完成,且有硬件中斷安裝了
        // 軟中斷處理時理時才會進(jìn)入。
        //
        if (!in_interrupt() && local_softirq_pending())
                //
                // 其實這里就是調(diào)用 do_softirq() 執(zhí)行
                //
                invoke_softirq();
        preempt_enable_no_resched();
}
#ifndef __ARCH_HAS_DO_SOFTIRQ
asmlinkage void do_softirq(void)
{
        __u32 pending;
        unsigned long flags;
        //
        // 這個函數(shù)判斷,如果當(dāng)前有硬件中斷嵌套,或者
        // 有軟中斷正在執(zhí)行時候,則馬上返回。在這個
        // 入口判斷主要是為了與 ksoftirqd 互斥。
        //
        if (in_interrupt())
                return;
        //
        // 關(guān)中斷執(zhí)行以下代碼
        //
        local_irq_save(flags);
        //
        // 判斷是否有 pending 的軟中斷需要處理。
        //
        pending = local_softirq_pending();
        //
        // 如果有則調(diào)用 __do_softirq() 進(jìn)行實際處理
        //
        if (pending)
                __do_softirq();
        //
        // 開中斷繼續(xù)執(zhí)行
        //
        local_irq_restore(flags);
}
//
// 最大軟中斷調(diào)用次數(shù)為 10 次。
//
#define MAX_SOFTIRQ_RESTART 10
asmlinkage void __do_softirq(void)
{
        //
        // 軟件中斷處理結(jié)構(gòu),此結(jié)構(gòu)中包括了 ISR 中
        // 注冊的回調(diào)函數(shù)。
        //
        struct softirq_action *h;
        __u32 pending;
        int max_restart = MAX_SOFTIRQ_RESTART;
        int cpu;
        //
        // 得到當(dāng)前所有 pending 的軟中斷。
        //
        pending = local_softirq_pending();
        account_system_vtime(current);
        //
        // 執(zhí)行到這里要屏蔽其他軟中斷,這里也就證明了
        // 每個 CPU 上同時運行的軟中斷只能有一個。
        //
        __local_bh_disable((unsigned long)__builtin_return_address(0));
        trace_softirq_enter();
        //
        // 針對 SMP 得到當(dāng)前正在處理的 CPU
        //
        cpu = smp_processor_id();
//
// 循環(huán)標(biāo)志
//
restart:
        //
        // 每次循環(huán)在允許硬件 ISR 強(qiáng)占前,首先重置軟中斷
        // 的標(biāo)志位。
        //
        /* Reset the pending bitmask before enabling irqs */
        set_softirq_pending(0);
        //
        // 到這里才開中斷運行,注意:以前運行狀態(tài)一直是關(guān)中斷
        // 運行,這時當(dāng)前處理軟中斷才可能被硬件中斷搶占。也就
        // 是說在進(jìn)入軟中斷時不是一開始就會被硬件中斷搶占。只有
        // 在這里以后的代碼才可能被硬件中斷搶占。
        //
        local_irq_enable();
        //
        // 這里要注意,以下代碼運行時可以被硬件中斷搶占,但
        // 這個硬件 ISR 執(zhí)行完成后,它的所注冊的軟中斷無法馬上運行,
        // 別忘了,現(xiàn)在雖是開硬件中斷執(zhí)行,但前面的 __local_bh_disable()
        // 函數(shù)屏蔽了軟中斷。所以這種環(huán)境下只能被硬件中斷搶占,但這
        // 個硬中斷注冊的軟中斷回調(diào)函數(shù)無法運行。要問為什么,那是因為
        // __local_bh_disable() 函數(shù)設(shè)置了一個標(biāo)志當(dāng)作互斥量,而這個
        // 標(biāo)志正是上面的 irq_exit() 和 do_softirq() 函數(shù)中的
        // in_interrupt() 函數(shù)判斷的條件之一,也就是說 in_interrupt()
        // 函數(shù)不僅檢測硬中斷而且還判斷了軟中斷。所以在這個環(huán)境下觸發(fā)
        // 硬中斷時注冊的軟中斷,根本無法重新進(jìn)入到這個函數(shù)中來,只能
        // 是做一個標(biāo)志,等待下面的重復(fù)循環(huán)(最大 MAX_SOFTIRQ_RESTART)
        // 才可能處理到這個時候觸發(fā)的硬件中斷所注冊的軟中斷。
        //
        //
        // 得到軟中斷向量表。
        //
        h = softirq_vec;
        //
        // 循環(huán)處理所有 softirq 軟中斷注冊函數(shù)。
        //
        do {
                //
                // 如果對應(yīng)的軟中斷設(shè)置 pending 標(biāo)志則表明
                // 需要進(jìn)一步處理它所注冊的函數(shù)。
                //
                if (pending & 1) {
                        //
                        // 在這里執(zhí)行了這個軟中斷所注冊的回調(diào)函數(shù)。
                        //
                        h->action(h);
                        rcu_bh_qsctr_inc(cpu);
                }
        //
        // 繼續(xù)找,直到把軟中斷向量表中所有 pending 的軟
        // 中斷處理完成。
        //
                h++;
                //
                // 從代碼里可以看出按位操作,表明一次循環(huán)只
                // 處理 32 個軟中斷的回調(diào)函數(shù)。
                //
                pending >>= 1;
        } while (pending);
        //
        // 關(guān)中斷執(zhí)行以下代碼。注意:這里又關(guān)中斷了,下面的
        // 代碼執(zhí)行過程中硬件中斷無法搶占。
        //
        local_irq_disable();
        //
        // 前面提到過,在剛才開硬件中斷執(zhí)行環(huán)境時只能被硬件中斷
        // 搶占,在這個時候是無法處理軟中斷的,因為剛才開中
        // 斷執(zhí)行過程中可能多次被硬件中斷搶占,每搶占一次就有可
        // 能注冊一個軟中斷,所以要再重新取一次所有的軟中斷。
        // 以便下面的代碼進(jìn)行處理后跳回到 restart 處重復(fù)執(zhí)行。
        //
        pending = local_softirq_pending();
        //
        // 如果在上面的開中斷執(zhí)行環(huán)境中觸發(fā)了硬件中斷,且每個都
        // 注冊了一個軟中斷的話,這個軟中斷會設(shè)置 pending 位,
        // 但在當(dāng)前一直屏蔽軟中斷的環(huán)境下無法得到執(zhí)行,前面提
        // 到過,因為 irq_exit() 和 do_softirq() 根本無法進(jìn)入到
        // 這個處理過程中來。這個在上面詳細(xì)的記錄過了。那么在
        // 這里又有了一個執(zhí)行的機(jī)會。注意:雖然當(dāng)前環(huán)境一直是
        // 處于屏蔽軟中斷執(zhí)行的環(huán)境中,但在這里又給出了一個執(zhí)行
        // 剛才在開中斷環(huán)境過程中觸發(fā)硬件中斷時所注冊的軟中斷的
        // 機(jī)會,其實只要理解了軟中斷機(jī)制就會知道,無非是在一些特
        // 定環(huán)境下調(diào)用 ISR 注冊到軟中斷向量表里的函數(shù)而已。
        //
        //
        // 如果剛才觸發(fā)的硬件中斷注冊了軟中斷,并且重復(fù)執(zhí)行次數(shù)
        // 沒有到 10 次的話,那么則跳轉(zhuǎn)到 restart 標(biāo)志處重復(fù)以上
        // 所介紹的所有步驟:設(shè)置軟中斷標(biāo)志位,重新開中斷執(zhí)行...
        // 注意:這里是要兩個條件都滿足的情況下才可能重復(fù)以上步驟。
        //
        if (pending && --max_restart)
                goto restart;
        //
        // 如果以上步驟重復(fù)了 10 次后還有 pending 的軟中斷的話,
        // 那么系統(tǒng)在一定時間內(nèi)可能達(dá)到了一個峰值,為了平衡這點。
        // 系統(tǒng)專門建立了一個 ksoftirqd 線程來處理,這樣避免在一
        // 定時間內(nèi)負(fù)荷太大。這個 ksoftirqd 線程本身是一個大循環(huán),
        // 在某些條件下為了不負(fù)載過重,它是可以被其他進(jìn)程搶占的,
        // 但注意,它是顯示的調(diào)用了 preempt_xxx() 和 schedule()
        // 才會被搶占和切換的。這么做的原因是因為在它一旦調(diào)用
        // local_softirq_pending() 函數(shù)檢測到有 pending 的軟中斷
        // 需要處理的時候,則會顯示的調(diào)用 do_softirq() 來處理軟中
        // 斷。也就是說,下面代碼喚醒的 ksoftirqd 線程有可能會回
        // 到這個函數(shù)當(dāng)中來,尤其是在系統(tǒng)需要響應(yīng)很多軟中斷的情況
        // 下,它的調(diào)用入口是 do_softirq(),這也就是為什么在 do_softirq()
        // 的入口處也會用 in_interrupt()  函數(shù)來判斷是否有軟中斷
        // 正在處理的原因了,目的還是為了防止重入。ksoftirqd 實現(xiàn)
        // 看下面對 ksoftirqd() 函數(shù)的分析。
        //
        if (pending)
               //
               // 此函數(shù)實際是調(diào)用 wake_up_process() 來喚醒 ksoftirqd
               //
                wakeup_softirqd();
        trace_softirq_exit();
        account_system_vtime(current);
        //
        // 到最后才開軟中斷執(zhí)行環(huán)境,允許軟中斷執(zhí)行。注意:這里
        // 使用的不是 local_bh_enable(),不會再次觸發(fā) do_softirq()
        // 的調(diào)用。
        //
        _local_bh_enable();
}
static int ksoftirqd(void * __bind_cpu)
{
        //
        // 顯示調(diào)用此函數(shù)設(shè)置當(dāng)前進(jìn)程的靜態(tài)優(yōu)先級。當(dāng)然,
        // 這個優(yōu)先級會隨調(diào)度器策略而變化。
        //
        set_user_nice(current, 19);
        //
        // 設(shè)置當(dāng)前進(jìn)程不允許被掛啟
        //
        current->flags |= PF_NOFREEZE;
        //
        // 設(shè)置當(dāng)前進(jìn)程狀態(tài)為可中斷的狀態(tài),這種睡眠狀
        // 態(tài)可響應(yīng)信號處理等。
        //
        set_current_state(TASK_INTERRUPTIBLE);
        //
        // 下面是一個大循環(huán),循環(huán)判斷當(dāng)前進(jìn)程是否會停止,
        // 不會則繼續(xù)判斷當(dāng)前是否有 pending 的軟中斷需
        // 要處理。
        //
        while (!kthread_should_stop()) {
                //
                // 如果可以進(jìn)行處理,那么在此處理期間內(nèi)禁止
                // 當(dāng)前進(jìn)程被搶占。
                //
                preempt_disable();
                //
                // 首先判斷系統(tǒng)當(dāng)前沒有需要處理的 pending 狀態(tài)的
                // 軟中斷
                //
                if (!local_softirq_pending()) {
                        //
                        // 沒有的話在主動放棄 CPU 前先要允許搶占,因為
                        // 一直是在不允許搶占狀態(tài)下執(zhí)行的代碼。
                        //
                        preempt_enable_no_resched();
                        //
                        // 顯示調(diào)用此函數(shù)主動放棄 CPU 將當(dāng)前進(jìn)程放入睡眠隊列,
                        // 并切換新的進(jìn)程執(zhí)行(調(diào)度器相關(guān)不記錄在此)
                        //
                        schedule();
                        //
                        // 注意:如果當(dāng)前顯示調(diào)用 schedule() 函數(shù)主動切換的進(jìn)
                        // 程再次被調(diào)度執(zhí)行的話,那么將從調(diào)用這個函數(shù)的下一條
                        // 語句開始執(zhí)行。也就是說,在這里當(dāng)前進(jìn)程再次被執(zhí)行的
                        // 話,將會執(zhí)行下面的 preempt_disable() 函數(shù)。
                        //
                        //
                        // 當(dāng)進(jìn)程再度被調(diào)度時,在以下處理期間內(nèi)禁止當(dāng)前進(jìn)程
                        // 被搶占。
                        //
                        preempt_disable();
                }
                //
                // 設(shè)置當(dāng)前進(jìn)程為運行狀態(tài)。注意:已經(jīng)設(shè)置了當(dāng)前進(jìn)程不可搶占
                // 在進(jìn)入循環(huán)后,以上兩個分支不論走哪個都會執(zhí)行到這里。一是
                // 進(jìn)入循環(huán)時就有 pending 的軟中斷需要執(zhí)行時。二是進(jìn)入循環(huán)時
                // 沒有 pending 的軟中斷,當(dāng)前進(jìn)程再次被調(diào)度獲得 CPU 時繼續(xù)
                // 執(zhí)行時。
                //
                __set_current_state(TASK_RUNNING);
                //
                // 循環(huán)判斷是否有 pending 的軟中斷,如果有則調(diào)用 do_softirq()
                // 來做具體處理。注意:這里又是一個 do_softirq() 的入口點,
                // 那么在 __do_softirq() 當(dāng)中循環(huán)處理 10 次軟中斷的回調(diào)函數(shù)
                // 后,如果還有 pending 的話,會又調(diào)用到這里。那么在這里則
                // 又會有可能去調(diào)用 __do_softirq() 來處理軟中斷回調(diào)函數(shù)。在前
                // 面介紹 __do_softirq() 時已經(jīng)提到過,處理 10 次還處理不完的
                // 話說明系統(tǒng)正處于繁忙狀態(tài)。根據(jù)以上分析,我們可以試想如果在
                // 系統(tǒng)非常繁忙時,這個進(jìn)程將會與 do_softirq() 相互交替執(zhí)行,
                // 這時此進(jìn)程占用 CPU 應(yīng)該會很高,雖然下面的 cond_resched()
                // 函數(shù)做了一些處理,它在處理完一輪軟中斷后當(dāng)前處理進(jìn)程可能會
                // 因被調(diào)度而減少 CPU 負(fù)荷,但是在非常繁忙時這個進(jìn)程仍然有可
                // 能大量占用 CPU。
                //
                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))
                                //
                                // 如果當(dāng)前被關(guān)聯(lián)的 CPU 無法繼續(xù)處理則跳轉(zhuǎn)
                                // 到 wait_to_die 標(biāo)記出,等待結(jié)束并退出。
                                //
                                goto wait_to_die;
                        //
                        // 執(zhí)行 do_softirq() 來處理具體的軟中斷回調(diào)函數(shù)。注
                        // 意:如果此時有一個正在處理的軟中斷的話,則會馬上
                        // 返回,還記得前面介紹的 in_interrupt() 函數(shù)么。
                        //
                        do_softirq();
                        //
                        // 允許當(dāng)前進(jìn)程被搶占。
                        //
                        preempt_enable_no_resched();
                        
                        //
                        // 這個函數(shù)有可能間接的調(diào)用 schedule() 來切換當(dāng)前
                        // 進(jìn)程,而且上面已經(jīng)允許當(dāng)前進(jìn)程可被搶占。也就是
                        // 說在處理完一輪軟中斷回調(diào)函數(shù)時,有可能會切換到
                        // 其他進(jìn)程。我認(rèn)為這樣做的目的一是為了在某些負(fù)載
                        // 超標(biāo)的情況下不至于讓這個進(jìn)程長時間大量的占用 CPU,
                        // 二是讓在有很多軟中斷需要處理時不至于讓其他進(jìn)程
                        // 得不到響應(yīng)。
                        //
                        cond_resched();
                        //
                        // 禁止當(dāng)前進(jìn)程被搶占。
                        //
                        preempt_disable();
                        //
                        // 處理完所有軟中斷了嗎?沒有的話繼續(xù)循環(huán)以上步驟
                        //
                }
                //
                // 待一切都處理完成后,允許當(dāng)前進(jìn)程被搶占,并設(shè)置
                // 當(dāng)前進(jìn)程狀態(tài)為可中斷狀態(tài),繼續(xù)循環(huán)以上所有過程。
                //
                preempt_enable();
                set_current_state(TASK_INTERRUPTIBLE);
        }
   
        //
        // 如果將會停止則設(shè)置當(dāng)前進(jìn)程為運行狀態(tài)后直接返回。
        // 調(diào)度器會根據(jù)優(yōu)先級來使當(dāng)前進(jìn)程運行。
        //
        __set_current_state(TASK_RUNNING);
        return 0;
//
// 一直等待到當(dāng)前進(jìn)程被停止
//
wait_to_die:
        //
        // 允許當(dāng)前進(jìn)程被搶占。
        //
        preempt_enable();
        /* Wait for kthread_stop */
        //
        // 設(shè)置當(dāng)前進(jìn)程狀態(tài)為可中斷的狀態(tài),這種睡眠狀
        // 態(tài)可響應(yīng)信號處理等。
        //
        set_current_state(TASK_INTERRUPTIBLE);
        //
        // 判斷當(dāng)前進(jìn)程是否會被停止,如果不是的話
        // 則設(shè)置進(jìn)程狀態(tài)為可中斷狀態(tài)并放棄當(dāng)前 CPU
        // 主動切換。也就是說這里將一直等待當(dāng)前進(jìn)程
        // 將被停止時候才結(jié)束。
        //
        while (!kthread_should_stop()) {
                schedule();
                set_current_state(TASK_INTERRUPTIBLE);
        }
        //
        // 如果將會停止則設(shè)置當(dāng)前進(jìn)程為運行狀態(tài)后直接返回。
        // 調(diào)度器會根據(jù)優(yōu)先級來使當(dāng)前進(jìn)程運行。
        //
        __set_current_state(TASK_RUNNING);
        return 0;
}
參考:
linux kernel source 2.6.19.1
/kernel/softirq.c
WSS(Whitecell Security Systems),一個非營利性民間技術(shù)組織,致力于各種系統(tǒng)安全技術(shù)的研究。堅持傳統(tǒng)的hacker精神,追求技術(shù)的精純。
WSS 主頁:http://www.whitecell.org/
WSS 論壇:http://www.whitecell.org/forums/

本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u1/40214/showart_2008871.html
您需要登錄后才可以回帖 登錄 | 注冊

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報專區(qū)
中國互聯(lián)網(wǎng)協(xié)會會員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP