第八章 下半部和推後執行的工作

1. 中斷處理程序的侷限

  • 以異步方式執行,並且有可能打斷其他重要代碼。所以爲了避免被打斷的代碼的停止時間過長,中斷處理程序應該執行得越快越好
  • 如果當前有一個中斷處理程序在運行,在最好的情況下(如果IRQF_DISABLED沒有被設置),與該中斷同級的其他中斷會被屏蔽,最壞的情況下(設置IRQF_DISABLED),當前CPU上所有的其他中斷都會被屏蔽。縮短中斷被屏蔽的時間對系統的響應能力性能都至關重要,所以中斷處理程序執行得越快越好
  • 由於中斷處理程序往往需要對硬件進行操作,所以對它們通常有很強的時限要求
  • 中斷上下文不能阻塞,這限制了它們所做的事情

2. 劃分頂半部(中斷處理函數)和下半部任務的一些借鑑:

  • 如果一個任務對時間非常敏感,將其放在頂半部執行
  • 如果一個任務跟硬件相關,將其放在頂半部執行
  • 如果一個任務要保證不被其他中斷(特別是相同的中斷)打斷,將其放在中斷處理程序中執行
  • 其他所有任務,考慮放在下半部執行

3. 下半部執行的時機

  • 下半部並不需要指明一個確切時間,只要把這些任務推遲一點,讓他們在系統不太繁忙並且中斷恢復後執行。
  • 通常下半部在中斷處理程序一返回就會馬上執行。
  • 下半部執行的關鍵在於當它們運行的時候,允許響應所有的中斷

4. 三種下半部機制

所有用於實現將工作推後執行的內核機制都被稱爲“下半部機制”。

  • 軟中斷(kernel/softirq.c)
    • 編譯期間靜態分配,有32個。
    • 一個軟中斷不會搶佔另一個軟中斷。唯一可以搶佔軟中斷的是中斷處理程序。其他的軟中斷(甚至是相同類型的軟中斷)可以在其他CPU上同時執行
    • 軟中斷處理程序執行的時候,允許響應中斷,但它自己不能休眠。
    • 在一個軟中斷處理程序運行的時候,當前CPU上的軟中斷被禁止,但其他CPU仍可以執行別的軟中斷
    • 如果同一個軟中斷在它被執行的同時再次被觸發了,那麼另一個CPU可以同時運行其處理程序。其中就涉及到共享數據的保護,爲了獲得更出色的性能,大部分軟中斷處理程序都通過單處理器數據或者其他一些技巧來避免顯示地加鎖
    • 執行時機、
      • 一個軟中斷在被標記後纔會執行,成爲觸發軟中斷。在中斷處理程序中觸發軟中斷是最常見的形式。
      • 從一個硬件中斷代碼處返回時
      • 在ksoftirqd內核線程中,每一個CPU都有這樣的線程,名字是ksoftirqd/n,n是CPU編號
      • 在那些顯示檢查和執行待處理的軟中斷的代碼中,如網絡子系統
  • tasklet
    • 基於軟中斷實現,可以動態創建和註銷,兩個不同的tasklet可以在不同的CPU上同時執行,但是同類型的tasklet不能同時執行
    • 因爲是基於軟中斷實現的,所以tasklet不能睡眠
    • 由於tasklet允許響應中斷,所以如果你的tasklet跟中斷處理函數之間共享了某些數據的話,可以屏蔽中斷然後獲得一個鎖。(屏蔽本地中斷,可以防止被當前CPU的中斷打斷,獲得鎖是爲了避免其他CPU在執行中斷處理函數的併發訪問)
    • 如果你的tasklet和其他的tasklet或者軟中斷共享了數據,必須使用適當的自旋鎖保護。(此時不用關閉中斷,因爲軟中斷不會被另一個軟中斷搶佔)
    • 在tasklet還沒有得到運行機會之前,如果有一個相同的tasklet又被調度了,那麼仍然只會運行一次。而如果已經在另一個CPU上開始運行了,那麼這個新的tasklet會被重新調度並再次運行。一般tasklet總在調度它的CPU上執行
  • 工作隊列 work queue
    • 可以把推後的工作交由一個內核線程去執行——這個下半部在進程上下文
    • 允許重新調度和睡眠
    • 缺省的工作者線程叫做 events/n,其中n是CPU的編號,每個CPU都對應一個線程
    • 工作隊列對應的處理函數雖然在進程上下文,但是不能訪問用戶空間,因爲內核線程在用戶空間沒有相關的內存映射。通常在發生系統調用時,內核纔會代表用戶空間的進程運行,此時它才能訪問用戶空間,也只有在此時他纔會映射用戶空間的內存

5. 內核定時器也可以一個將工作推後執行的機制

  • 內核定時器也是建立在軟中斷的基礎上的

6. 下半部上下文

下半部 頂半部 執行順序保障
軟中斷 中斷 沒有
tasklet 中斷 同類型不能同時執行
工作隊列 進程 沒有(和進程上下文一樣)

上面想說一下爲什麼軟中斷是在中斷上下文,我們知道軟中斷是在中斷處理函數返回後執行的,此時也沒用對應有task_struct。

7. 下半部加鎖

  • 如果進程上下文跟下半部共享數據,在訪問這些數據之前,需要禁止下半部的處理並得到鎖的使用權。以軟中斷爲例,進程上下文會可能會被當前CPU上的軟中斷打斷,導致併發,而禁止下半部只能做到禁止當前CPU的軟中斷。而使用自旋鎖的目的是,防止跟其他CPU上的軟中斷併發,而軟中斷中不能睡眠,故只能用自旋鎖
  • 如果中斷上下文和一個下半部共享數據,在訪問數據之前,你需要禁止中斷並得到鎖的使用權。以軟中斷爲例,因爲中斷會打斷下半部,導致併發,而禁止中斷只能影響到本地CPU,而其他CPU上的中斷並沒有禁止,故需要使用自旋鎖。
  • 任何在工作隊列中被共享的數據也需要使用鎖機制。其中有關鎖的要點和一般內核代碼中沒有區別,因爲工作隊列本來就是在進程上下文中執行的。

8. 禁止下半部(tasklet和軟中斷)

常見的做法:先得到一個鎖然後再禁止下半部

函數 描述
void local_bh_disable() 禁止本地CPU的軟中斷和tasklet的處理
void local_bh_enable() 激活本地CPU的軟中斷和tasklet的處理

如果調用了第一次調用local_bh_disable關閉了本地CPU的下半部,如果local_bh_disable又被調用三次,那麼當第四次調用local_bh_enable時,本地CPU的下半部處理才重新被激活

其實這兩個函數是通過修改preempt_count實現的,這個變量每個進程都有一個,存放在thread_info中,當這個變量爲0時,下半部才能夠被處理。

asm_do_IRQ

----> __handle_domain_irq

----> generic_handle_irq

----> irq_exit

  1. /*
  2. * Exit an interrupt context. Process softirqs if needed and possible:
  3. */
  4. void irq_exit(void)
  5. {
  6. #ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED
  7. local_irq_disable();
  8. #else
  9. WARN_ON_ONCE(!irqs_disabled());
  10. #endif
  11. account_irq_exit_time(current);
  12. preempt_count_sub(HARDIRQ_OFFSET);
  13. if(!in_interrupt()&& local_softirq_pending())
  14. invoke_softirq();
  15. tick_irq_exit();
  16. rcu_irq_exit();
  17. trace_hardirq_exit();/* must be last! */
  18. }

来自为知笔记(Wiz)

时间: 2024-08-27 00:17:54

第八章 下半部和推後執行的工作的相关文章

GitHub for Windows 內建 Git Shell 執行時顏色所代表的意義

在使用指令列版控的過程中,經常有機會用到 Git Shell 這套優異的 Git 版控環境,一來他使用 Windows PowerShell 為核心,其訊息顯示與輸入都支援 Unicode,比較不會有中文字集轉換的問題:二來輸入命令或分支名稱的時候還有 IntelliSense 功能協助,非常貼心的設計:三來在版控的過程中,可以看出當下工作目錄位於哪個分支上,這個提示也很棒:四來常會看到他透過顏色與一些特殊符號提示你目前工作目錄的狀態,但不特別看文件還真的不太容易知道它顏色代表的意義,因此特別撰

[Batch檔案筆記] 在UNC路徑中執行Batch檔

為了讓其他人可以免安裝又可以執行python程式所以我把python portable版本 winpython 放在samba的空間共享但是使用者如果要開 winpython cammand prompt .exe 打指令執行程式的話又太麻煩 所以寫了batch檔來直接執行我的python程式 因為是共享空間 所以使用 pushd%~dp0 是當前路徑接下來就是 python 再加上要執行檔案的路徑就可以了~ pushd %~dp0\python-2.7.10 python Project_Ev

Unity strip engine code 遇到執行不能之問題與解決

遊戲發布在 WebGL 平台發現檔案還是太大,因此在 IL2CPP 的環境下,開啟 Strip engine code 編譯功能,嘗試看看能不能減少一些檔案容量. 但由於我們另外有載入 Scene stream assetbundles 的機制,因此遇到開啟 Strip engine code 後,無法正常執行的情形. 經過 Kelvin Lo 技術支援以及時間測試後,終究能夠正常執行,留下整件事情的經過.技術問題以及相關解法支援等等資料. 測試環境 Unity5.5.1f1,Windows 1

執行shell script與subshell

兩種方法 喚起新shell再執行shell scripts 在目前shell執行shell scripts 喚起另一個shell來執行的scripts在scripts檔頭最前面前要加 #! /bin/sh 第一種方法是在shell script 文字檔前指出shell scripts解讀的程式在那(也就是 我們的shell)然後把文字檔的執行權限打開,照一般執行可執行檔方式執行或者叫 一個shell來解釋文字檔test.sh. $ test.sh $ /bin/sh test.sh $ ( .

Ubuntu-14.04. sh .py腳本双击無法執行问题的解决方法

Ubuntu-14.04中默认文件用gedit文本打开,而不是BT5里面的默认双击打开四个选择,如下图(这是配置完毕后的结果,就不换BT5系统了): 直接文本打开,虽然很安全,实际生产中肯定是不行的!而默认执行这更是不可取,所以,需要配置成如上图所示结果. 配置方法 1.首先使用sudo apt-get install dconf-editor命令安装dconf-editor,默认是没有安装的: 2.安装完成后直接运行dconf-editor命令呼出窗口,按org->gnome->nautil

【转】Visual Studio單元測試小應用-測執行時間

[转]Visual Studio單元測試小應用-測執行時間 Visual Studio的單元測試會記錄每一個測試的執行時間,如果有幾個Method要測效能,以前我會用Stopwatch,最近我都改用單元測試來測,快又簡單. Visual Studio的單元測試會記錄每一個測試的執行時間,如果有幾個Method要測效能,以前我會用Stopwatch,最近我都改用單元測試來測,快又簡單. 範例程式:有人說Catch不加Expection,因為不用匹配會比較快,我不相信,就來測測看. { for (i

[转]如何使用VS 2013發布一個可以在Windows XP中獨立運行的可執行文件

https://read01.com/Mg337.html (台/湾的论坛,需要f/q) 1. 閱讀此文章的同學先看看我的另外一篇文章: 現在,我們深入探討一下: <如何使用VS 2013發布一個可以在Windows XP中獨立運行的可執行文件>. 這個問題是比較常見且容易造成初學者困惑的,作為曾經撞了無數次南牆的初級代碼狗終於看到了自己能夠回答的問題,那麼就讓我來簡單闡述一下造成這個問題的簡單原理極其簡單解決方法,如有錯誤紕漏敬請指正. /*我們討論的是非託管的C++程序.*/ 為了方便說明

PreparedStatement執行sql語句

import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import org.junit.Test; import util.JdbcUtil; /** * PreparedStatement執行sql語句 * @author APPle * */ public class Demo1 { /** * 增加 */ @Test public void testInsert()

非靜態初始化塊與夠着函數的 執行順序

題目: 子類A繼承父類B,A a=new A();則父類B夠着函數.父類B靜態代碼塊.父類B非靜態代碼塊執行的先後順序是? 正確的執行順序是:杜磊B靜態代碼塊->子類A靜態代碼塊->父類B非靜態代碼塊->父類B構造函數->子類A非靜態代碼塊->子類A構造函數 也就是説非靜態初始化塊的執行順序要在構造函數之前. 1 class SuperClass{ 2 private static String str="Spuer Class Static Variable&qu