乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      Linux 內(nèi)核軟中斷執(zhí)行分析|Linux,內(nèi)核,軟中斷,softirq,分析,編程

       todaytomo 2007-09-28
      今天無(wú)意中看了眼 2.6 內(nèi)核的軟中斷實(shí)現(xiàn),發(fā)現(xiàn)和以前我看到的大不相同
      (以前也是走馬觀花,不大仔細(xì)),可以說(shuō)改動(dòng)很大。連 softirq 的調(diào)用
      點(diǎn)都不一樣了,以前是三個(gè)調(diào)用點(diǎn),今天搜索了一下源代碼,發(fā)現(xiàn)在多出了
      ksoftirqd 這個(gè)東西后,softirq 在系統(tǒng)中的調(diào)用點(diǎn)僅是在 ISR 返回時(shí)和
      使用了 local_bh_enable() 函數(shù)后被調(diào)用了。網(wǎng)卡部分的顯示調(diào)用,我覺(jué)
      得應(yīng)該不算是系統(tǒng)中的調(diào)用點(diǎn)。ksoftirqd 返回去調(diào)用 do_softirq() 函數(shù)
      應(yīng)該也只能算是其中的一個(gè)分支,因?yàn)槠浔旧韽脑搭^上來(lái)講也還是在 ISR 返
      回時(shí) irq_exit() 調(diào)用的。這樣一來(lái)就和前些日子寫(xiě)的那份筆記
      (Windows/Linux/Solaris 軟中斷機(jī)制)里介紹的 Linux 內(nèi)核部分的軟中
      斷有出處了,看來(lái)以后討論 Linux kernel 代碼一定要以?xún)?nèi)核版本為前題來(lái)
      說(shuō),要不非亂了不可??磥?lái)得買(mǎi)本 Linux 方面的書(shū)了,每次上來(lái)直接看相
      關(guān)代碼也不是回事,時(shí)間也不允許。


      linux kernel source 2.6.19.1
      /kernel/softirq.c

      //
      // do_IRQ 函數(shù)執(zhí)行完硬件 ISR 后退出時(shí)調(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),注意:這里只有兩個(gè)條件同時(shí)滿(mǎn)足
      // 時(shí),才有可能調(diào)用 do_softirq() 進(jìn)入軟中斷。也就是
      // 說(shuō)確認(rèn)當(dāng)前所有硬件中斷處理完成,且有硬件中斷安裝了
      // 軟中斷處理時(shí)理時(shí)才會(huì)進(jìn)入。
      //
      if (!in_interrupt() && local_softirq_pending())

      //
      // 其實(shí)這里就是調(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;

      //
      // 這個(gè)函數(shù)判斷,如果當(dāng)前有硬件中斷嵌套,或者
      // 有軟中斷正在執(zhí)行時(shí)候,則馬上返回。在這個(gè)
      // 入口判斷主要是為了與 ksoftirqd 互斥。
      //
      if (in_interrupt())
      return;

      //
      // 關(guān)中斷執(zhí)行以下代碼
      //
      local_irq_save(flags);

      //
      // 判斷是否有 pending 的軟中斷需要處理。
      //
      pending = local_softirq_pending();

      //
      // 如果有則調(diào)用 __do_softirq() 進(jìn)行實(shí)際處理
      //
      if (pending)
      __do_softirq();

      //
      // 開(kāi)中斷繼續(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 中
      // 注冊(cè)的回調(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í)行到這里要屏蔽其他軟中斷,這里也就證明了
      // 每個(gè) CPU 上同時(shí)運(yùn)行的軟中斷只能有一個(gè)。
      //
      __local_bh_disable((unsigned long)__builtin_return_address(0));
      trace_softirq_enter();

      //
      // 針對(duì) 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);

      //
      // 到這里才開(kāi)中斷運(yùn)行,注意:以前運(yùn)行狀態(tài)一直是關(guān)中斷
      // 運(yùn)行,這時(shí)當(dāng)前處理軟中斷才可能被硬件中斷搶占。也就
      // 是說(shuō)在進(jìn)入軟中斷時(shí)不是一開(kāi)始就會(huì)被硬件中斷搶占。只有
      // 在這里以后的代碼才可能被硬件中斷搶占。
      //
      local_irq_enable();

      //
      // 這里要注意,以下代碼運(yùn)行時(shí)可以被硬件中斷搶占,但
      // 這個(gè)硬件 ISR 執(zhí)行完成后,它的所注冊(cè)的軟中斷無(wú)法馬上運(yùn)行,
      // 別忘了,現(xiàn)在雖是開(kāi)硬件中斷執(zhí)行,但前面的 __local_bh_disable()
      // 函數(shù)屏蔽了軟中斷。所以這種環(huán)境下只能被硬件中斷搶占,但這
      // 個(gè)硬中斷注冊(cè)的軟中斷回調(diào)函數(shù)無(wú)法運(yùn)行。要問(wèn)為什么,那是因?yàn)?br>// __local_bh_disable() 函數(shù)設(shè)置了一個(gè)標(biāo)志當(dāng)作互斥量,而這個(gè)
      // 標(biāo)志正是上面的 irq_exit() 和 do_softirq() 函數(shù)中的
      // in_interrupt() 函數(shù)判斷的條件之一,也就是說(shuō) in_interrupt()
      // 函數(shù)不僅檢測(cè)硬中斷而且還判斷了軟中斷。所以在這個(gè)環(huán)境下觸發(fā)
      // 硬中斷時(shí)注冊(cè)的軟中斷,根本無(wú)法重新進(jìn)入到這個(gè)函數(shù)中來(lái),只能
      // 是做一個(gè)標(biāo)志,等待下面的重復(fù)循環(huán)(最大 MAX_SOFTIRQ_RESTART)
      // 才可能處理到這個(gè)時(shí)候觸發(fā)的硬件中斷所注冊(cè)的軟中斷。
      //


      //
      // 得到軟中斷向量表。
      //
      h = softirq_vec;

      //
      // 循環(huán)處理所有 softirq 軟中斷注冊(cè)函數(shù)。
      //
      do {
      //
      // 如果對(duì)應(yīng)的軟中斷設(shè)置 pending 標(biāo)志則表明
      // 需要進(jìn)一步處理它所注冊(cè)的函數(shù)。
      //
      if (pending & 1) {
      //
      // 在這里執(zhí)行了這個(gè)軟中斷所注冊(cè)的回調(diào)函數(shù)。
      //
      h->action(h);
      rcu_bh_qsctr_inc(cpu);
      }
      //
      // 繼續(xù)找,直到把軟中斷向量表中所有 pending 的軟
      // 中斷處理完成。
      //
      h++;

      //
      // 從代碼里可以看出按位操作,表明一次循環(huán)只
      // 處理 32 個(gè)軟中斷的回調(diào)函數(shù)。
      //
      pending >>= 1;
      } while (pending);

      //
      // 關(guān)中斷執(zhí)行以下代碼。注意:這里又關(guān)中斷了,下面的
      // 代碼執(zhí)行過(guò)程中硬件中斷無(wú)法搶占。
      //
      local_irq_disable();

      //
      // 前面提到過(guò),在剛才開(kāi)硬件中斷執(zhí)行環(huán)境時(shí)只能被硬件中斷
      // 搶占,在這個(gè)時(shí)候是無(wú)法處理軟中斷的,因?yàn)閯偛砰_(kāi)中
      // 斷執(zhí)行過(guò)程中可能多次被硬件中斷搶占,每搶占一次就有可
      // 能注冊(cè)一個(gè)軟中斷,所以要再重新取一次所有的軟中斷。
      // 以便下面的代碼進(jìn)行處理后跳回到 restart 處重復(fù)執(zhí)行。
      //
      pending = local_softirq_pending();

      //
      // 如果在上面的開(kāi)中斷執(zhí)行環(huán)境中觸發(fā)了硬件中斷,且每個(gè)都
      // 注冊(cè)了一個(gè)軟中斷的話,這個(gè)軟中斷會(huì)設(shè)置 pending 位,
      // 但在當(dāng)前一直屏蔽軟中斷的環(huán)境下無(wú)法得到執(zhí)行,前面提
      // 到過(guò),因?yàn)?irq_exit() 和 do_softirq() 根本無(wú)法進(jìn)入到
      // 這個(gè)處理過(guò)程中來(lái)。這個(gè)在上面詳細(xì)的記錄過(guò)了。那么在
      // 這里又有了一個(gè)執(zhí)行的機(jī)會(huì)。注意:雖然當(dāng)前環(huán)境一直是
      // 處于屏蔽軟中斷執(zhí)行的環(huán)境中,但在這里又給出了一個(gè)執(zhí)行
      // 剛才在開(kāi)中斷環(huán)境過(guò)程中觸發(fā)硬件中斷時(shí)所注冊(cè)的軟中斷的
      // 機(jī)會(huì),其實(shí)只要理解了軟中斷機(jī)制就會(huì)知道,無(wú)非是在一些特
      // 定環(huán)境下調(diào)用 ISR 注冊(cè)到軟中斷向量表里的函數(shù)而已。
      //

      //
      // 如果剛才觸發(fā)的硬件中斷注冊(cè)了軟中斷,并且重復(fù)執(zhí)行次數(shù)
      // 沒(méi)有到 10 次的話,那么則跳轉(zhuǎn)到 restart 標(biāo)志處重復(fù)以上
      // 所介紹的所有步驟:設(shè)置軟中斷標(biāo)志位,重新開(kāi)中斷執(zhí)行...
      // 注意:這里是要兩個(gè)條件都滿(mǎn)足的情況下才可能重復(fù)以上步驟。
      //
      if (pending && --max_restart)
      goto restart;

      //
      // 如果以上步驟重復(fù)了 10 次后還有 pending 的軟中斷的話,
      // 那么系統(tǒng)在一定時(shí)間內(nèi)可能達(dá)到了一個(gè)峰值,為了平衡這點(diǎn)。
      // 系統(tǒng)專(zhuān)門(mén)建立了一個(gè) ksoftirqd 線程來(lái)處理,這樣避免在一
      // 定時(shí)間內(nèi)負(fù)荷太大。這個(gè) ksoftirqd 線程本身是一個(gè)大循環(huán),
      // 在某些條件下為了不負(fù)載過(guò)重,它是可以被其他進(jìn)程搶占的,
      // 但注意,它是顯示的調(diào)用了 preempt_xxx() 和 schedule()
      // 才會(huì)被搶占和切換的。這么做的原因是因?yàn)樵谒坏┱{(diào)用
      // local_softirq_pending() 函數(shù)檢測(cè)到有 pending 的軟中斷
      // 需要處理的時(shí)候,則會(huì)顯示的調(diào)用 do_softirq() 來(lái)處理軟中
      // 斷。也就是說(shuō),下面代碼喚醒的 ksoftirqd 線程有可能會(huì)回
      // 到這個(gè)函數(shù)當(dāng)中來(lái),尤其是在系統(tǒng)需要響應(yīng)很多軟中斷的情況
      // 下,它的調(diào)用入口是 do_softirq(),這也就是為什么在 do_softirq()
      // 的入口處也會(huì)用 in_interrupt() 函數(shù)來(lái)判斷是否有軟中斷
      // 正在處理的原因了,目的還是為了防止重入。ksoftirqd 實(shí)現(xiàn)
      // 看下面對(duì) ksoftirqd() 函數(shù)的分析。
      //
      if (pending)

      //
      // 此函數(shù)實(shí)際是調(diào)用 wake_up_process() 來(lái)喚醒 ksoftirqd
      //
      wakeup_softirqd();

      trace_softirq_exit();

      account_system_vtime(current);

      //
      // 到最后才開(kāi)軟中斷執(zhí)行環(huán)境,允許軟中斷執(zhí)行。注意:這里
      // 使用的不是 local_bh_enable(),不會(huì)再次觸發(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)先級(jí)。當(dāng)然,
      // 這個(gè)優(yōu)先級(jí)會(huì)隨調(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)信號(hào)處理等。
      //
      set_current_state(TASK_INTERRUPTIBLE);

      //
      // 下面是一個(gè)大循環(huán),循環(huán)判斷當(dāng)前進(jìn)程是否會(huì)停止,
      // 不會(huì)則繼續(xù)判斷當(dāng)前是否有 pending 的軟中斷需
      // 要處理。
      //
      while (!kthread_should_stop()) {

      //
      // 如果可以進(jìn)行處理,那么在此處理期間內(nèi)禁止
      // 當(dāng)前進(jìn)程被搶占。
      //
      preempt_disable();

      //
      // 首先判斷系統(tǒng)當(dāng)前沒(méi)有需要處理的 pending 狀態(tài)的
      // 軟中斷
      //
      if (!local_softirq_pending()) {

      //
      // 沒(méi)有的話在主動(dòng)放棄 CPU 前先要允許搶占,因?yàn)?br>// 一直是在不允許搶占狀態(tài)下執(zhí)行的代碼。
      //
      preempt_enable_no_resched();

      //
      // 顯示調(diào)用此函數(shù)主動(dòng)放棄 CPU 將當(dāng)前進(jìn)程放入睡眠隊(duì)列,
      // 并切換新的進(jìn)程執(zhí)行(調(diào)度器相關(guān)不記錄在此)
      //
      schedule();

      //
      // 注意:如果當(dāng)前顯示調(diào)用 schedule() 函數(shù)主動(dòng)切換的進(jìn)
      // 程再次被調(diào)度執(zhí)行的話,那么將從調(diào)用這個(gè)函數(shù)的下一條
      // 語(yǔ)句開(kāi)始執(zhí)行。也就是說(shuō),在這里當(dāng)前進(jìn)程再次被執(zhí)行的
      // 話,將會(huì)執(zhí)行下面的 preempt_disable() 函數(shù)。
      //

      //
      // 當(dāng)進(jìn)程再度被調(diào)度時(shí),在以下處理期間內(nèi)禁止當(dāng)前進(jìn)程
      // 被搶占。
      //
      preempt_disable();
      }

      //
      // 設(shè)置當(dāng)前進(jìn)程為運(yùn)行狀態(tài)。注意:已經(jīng)設(shè)置了當(dāng)前進(jìn)程不可搶占
      // 在進(jìn)入循環(huán)后,以上兩個(gè)分支不論走哪個(gè)都會(huì)執(zhí)行到這里。一是
      // 進(jìn)入循環(huán)時(shí)就有 pending 的軟中斷需要執(zhí)行時(shí)。二是進(jìn)入循環(huán)時(shí)
      // 沒(méi)有 pending 的軟中斷,當(dāng)前進(jìn)程再次被調(diào)度獲得 CPU 時(shí)繼續(xù)
      // 執(zhí)行時(shí)。
      //
      __set_current_state(TASK_RUNNING);

      //
      // 循環(huán)判斷是否有 pending 的軟中斷,如果有則調(diào)用 do_softirq()
      // 來(lái)做具體處理。注意:這里又是一個(gè) do_softirq() 的入口點(diǎn),
      // 那么在 __do_softirq() 當(dāng)中循環(huán)處理 10 次軟中斷的回調(diào)函數(shù)
      // 后,如果還有 pending 的話,會(huì)又調(diào)用到這里。那么在這里則
      // 又會(huì)有可能去調(diào)用 __do_softirq() 來(lái)處理軟中斷回調(diào)函數(shù)。在前
      // 面介紹 __do_softirq() 時(shí)已經(jīng)提到過(guò),處理 10 次還處理不完的
      // 話說(shuō)明系統(tǒng)正處于繁忙狀態(tài)。根據(jù)以上分析,我們可以試想如果在
      // 系統(tǒng)非常繁忙時(shí),這個(gè)進(jìn)程將會(huì)與 do_softirq() 相互交替執(zhí)行,
      // 這時(shí)此進(jìn)程占用 CPU 應(yīng)該會(huì)很高,雖然下面的 cond_resched()
      // 函數(shù)做了一些處理,它在處理完一輪軟中斷后當(dāng)前處理進(jìn)程可能會(huì)
      // 因被調(diào)度而減少 CPU 負(fù)荷,但是在非常繁忙時(shí)這個(gè)進(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 無(wú)法繼續(xù)處理則跳轉(zhuǎn)
      // 到 wait_to_die 標(biāo)記出,等待結(jié)束并退出。
      //
      goto wait_to_die;

      //
      // 執(zhí)行 do_softirq() 來(lái)處理具體的軟中斷回調(diào)函數(shù)。注
      // 意:如果此時(shí)有一個(gè)正在處理的軟中斷的話,則會(huì)馬上
      // 返回,還記得前面介紹的 in_interrupt() 函數(shù)么。
      //
      do_softirq();

      //
      // 允許當(dāng)前進(jìn)程被搶占。
      //
      preempt_enable_no_resched();

      //
      // 這個(gè)函數(shù)有可能間接的調(diào)用 schedule() 來(lái)切換當(dāng)前
      // 進(jìn)程,而且上面已經(jīng)允許當(dāng)前進(jìn)程可被搶占。也就是
      // 說(shuō)在處理完一輪軟中斷回調(diào)函數(shù)時(shí),有可能會(huì)切換到
      // 其他進(jìn)程。我認(rèn)為這樣做的目的一是為了在某些負(fù)載
      // 超標(biāo)的情況下不至于讓這個(gè)進(jìn)程長(zhǎng)時(shí)間大量的占用 CPU,
      // 二是讓在有很多軟中斷需要處理時(shí)不至于讓其他進(jìn)程
      // 得不到響應(yīng)。
      //
      cond_resched();

      //
      // 禁止當(dāng)前進(jìn)程被搶占。
      //
      preempt_disable();

      //
      // 處理完所有軟中斷了嗎?沒(méi)有的話繼續(xù)循環(huán)以上步驟
      //
      }

      //
      // 待一切都處理完成后,允許當(dāng)前進(jìn)程被搶占,并設(shè)置
      // 當(dāng)前進(jìn)程狀態(tài)為可中斷狀態(tài),繼續(xù)循環(huán)以上所有過(guò)程。
      //
      preempt_enable();
      set_current_state(TASK_INTERRUPTIBLE);
      }

      //
      // 如果將會(huì)停止則設(shè)置當(dāng)前進(jìn)程為運(yùn)行狀態(tài)后直接返回。
      // 調(diào)度器會(huì)根據(jù)優(yōu)先級(jí)來(lái)使當(dāng)前進(jìn)程運(yù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)信號(hào)處理等。
      //
      set_current_state(TASK_INTERRUPTIBLE);

      //
      // 判斷當(dāng)前進(jìn)程是否會(huì)被停止,如果不是的話
      // 則設(shè)置進(jìn)程狀態(tài)為可中斷狀態(tài)并放棄當(dāng)前 CPU
      // 主動(dòng)切換。也就是說(shuō)這里將一直等待當(dāng)前進(jìn)程
      // 將被停止時(shí)候才結(jié)束。
      //
      while (!kthread_should_stop()) {
      schedule();
      set_current_state(TASK_INTERRUPTIBLE);
      }

      //
      // 如果將會(huì)停止則設(shè)置當(dāng)前進(jìn)程為運(yùn)行狀態(tài)后直接返回。
      // 調(diào)度器會(huì)根據(jù)優(yōu)先級(jí)來(lái)使當(dāng)前進(jìn)程運(yùn)行。
      //
      __set_current_state(TASK_RUNNING);
      return 0;
      }

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶(hù)發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶(hù) 評(píng)論公約

        類(lèi)似文章 更多