• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            風雨兼程

            ring my bells
            posts - 49, comments - 14, trackbacks - 0, articles - 0

            下半部和推后執行的工作

            Posted on 2008-04-09 22:52 silentneil 閱讀(161) 評論(0)  編輯 收藏 引用
            1、中斷處理程序的局限:

                * 中斷處理程序以異步方式執行并且它有可能會打斷其他重要代碼的執行。因此,它們應該執行得越快越好。
                * 如果當前有一個中斷處理程序正在執行,在最好的情況下,與該中斷同級的其他中斷會被屏蔽,在最壞的情況下,所有其他中斷都會被屏蔽。因此,仍應該讓它們執行得越快越好。
                * 由于中斷處理程序往往需要對硬件進行操作,所以它們通常有很高的時限要求。
                * 中斷處理程序不在進程上下文中運行,所以它們不能阻塞。

            2、下半部的任務就是執行與中斷處理密切相關但中斷處理程序本身不執行的工作。

            3、并不存在嚴格明確的規定來說明到底什么任務應該在哪個部分中完成,如何做決定完全取決于驅動程序開發者自己的判斷。對于在上半部和下半部之間劃分工作,盡管不存在某種嚴格的規則,但還是有一些提示可供借鑒:

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

            4、和上半部分只能通過中斷處理程序實現不同,下半部可以通過多種機制實現。最早的Linux只提供"bottom half"這種機制用于實現下半部,這種機制也被稱為"BH"。不久,內核開發者們就引入了任務隊列機制來實現工作的推后執行,并用來代替BH機制。目前這兩種機制已經在2.5之后的版本中被去除。在2.6版本中,內核提供了三種不同形式的下半部實現機制:軟中斷、tasklet和工作隊列。其實還有另外一個可以用于將工作推后執行的機制是內核定時器。它可以把操作推遲到某個確定的時間段之后執行。也就是說,當你必須保證在一個確定的時間段過去后再運行時,你應該使用內核定時器。

            5、軟中斷是一組靜態定義的下半部接口,有32個,可以在所有處理器上同時執行-即使兩個類型相同也可以。其適合于像網絡這樣對性能要求非常高的情況。此外,軟中斷必須在編譯期間就進行靜態注冊。

            6、軟中斷的實現:軟中斷的代碼位于kernel/softirq.c文件中。其由softirq_action結構表示,定義在< linux/interrupt.h>中。在kernel/softirq.c中定義了一個包含有32個該結構體的數組。目前這32個項中只用到6 個。一個軟中斷不會搶占另外一個軟中斷。實際上,唯一可以搶占軟中斷的是中斷處理程序。一個注冊的軟中斷必須在被標記后才會執行。這被稱作觸發軟中斷。通常,中斷處理程序會在返回前標記它的軟中斷,使其在稍后被執行。在下列地方,待處理的軟中斷會被檢查和執行:

                * 在處理完一個硬件中斷以后。
                * 在ksoftirqd內核線程中。
                * 在那些顯式檢查和執行待處理的軟中斷的代碼中,如網絡子系統中。

            不管用什么辦法喚起,軟中斷都要在do_softirq()中執行。該函數很簡單,如果有待處理的軟中斷,do_softirq()就會循環遍歷每一個,調用它們的處理程序。

            7、使用軟中斷:軟中斷保留給系統中對時間要求最嚴格以及最重要的下半部使用。目前只有兩個子系統-網絡和SCSI直接使用軟中斷。此外,內核定時器和tasklets都是建立在軟中斷上的。對于時間要求嚴格并能自己高效地完成加鎖工作的應用,軟中斷會是正確的選擇。

               1)分配索引

               在編譯期間,通過<linux/interrupt.h>中定義的一個枚舉類型來靜態地聲明軟中斷。內核用這些從0開始的索引來表示一種相對優先級。索引號小的軟中斷在索引號大的軟中斷之前執行。建立一個新的軟中斷必須在此枚舉類型中加入新的項。而加入時,不能像在其他地方一樣,簡單地把新項加到列表的末尾。相反,你必須根據你希望賦予它的優先級來決定加入的位置。

               2)注冊你的處理程序

               接著,在運行時通過調用open_softirq()注冊軟中斷處理程序。軟中斷處理程序執行的時候,允許響應中斷,但它自己不能休眠。在一個處理程序運行的時候,當前處理器上的軟中斷被禁止。但其他處理器仍可以執行別的軟中斷。實際上,如果一個軟中斷在它被執行的同時再次被觸發了,那么另外一個處理器可以同時運行其處理程序。這意味著任何共享數據-甚至是僅在軟中斷處理程序內部使用的全局變量都需要嚴格的鎖保護。如果僅僅通過互斥的加鎖方式來防止它自身的并發執行,那么使用軟中斷就沒有任何意義。因此大部分軟中斷處理程序都通過采取單處理器數據或其他一些技巧來避免顯式地加鎖,從而提供更出色的性能。

               3)觸發你的軟中斷

               raise_softirq()函數可以將一個軟中斷設置為掛起狀態,讓它在下次調用do_softirq()函數時投入運行。該函數在觸發一個軟中斷之前先要禁止中斷,觸發后再恢復回原來的狀態。如果中斷已經被禁止了,那可以調用另一函數raise_softirq_irqoff(),這會帶來一些優化效果。在中斷處理程序中觸發軟中斷是最常見的形式。在這種情況下,中斷處理程序執行硬件設備的相關操作,然后觸發相應的軟中斷,最后退出。內核在執行完中斷處理程序以后,馬上就會調用do_softirq()函數。于是軟中斷開始執行中斷處理程序留給它去完成的剩余任務。

            8、Tasklets是利用軟中斷實現的一種下半部機制。它和進程沒有任何關系。Tasklets和軟中斷在本質上很相似,行為表現也相近,但是它的接口更簡單,鎖保護也要求較低。選擇到底是用軟中斷還是tasklets其實很簡單:通常你應該用tasklets,軟中斷的使用者屈指可數。它只在那些執行頻率很高和連續性要求很高的情況下才需要。

            9、tasklet是通過軟中斷實現的,所以它們本身也是軟中斷。Tasklets由tasklet_struct結構表示。每個結構體單獨代表一個tasklet,其定義在<linux/interrupt.h>中。已調度的tasklet(等同于被觸發的軟中斷)存放在兩個單處理器數據結構:tasklet_vec(普通tasklet)和tasklet_hi_vec(高優先級tasklet)中。這兩個數據結構都是由 tasklet_struct結構體構成的鏈表。Tasklets由tasklet_schedule()和tasklet_hi_schedule() 函數進行調度。

            10、使用Tasklets

               1)聲明自己的Tasklet

               既可以使用<linux/interrupt.h>中定義的兩個宏中的一個DECLARE_TASKLET或 DECLARE_TASKLET_DISABLED來靜態創建tasklet,前者把創建的tasklet的引用計數器設置為0,該tasklet處于激活狀態。另一個把引入計數器設為1,所以該tasklet處于禁止狀態。還可以使用tasklet_init()動態創建一個tasklet。

               2)編寫自己的tasklet處理程序

               tasklet處理程序必須符合規定的函數類型:void tasklet_handler(unsigned long data)。因為是靠軟中斷實現,所以tasklet不能睡眠。這意味著你不能在tasklet中使用信號量或其他什么阻塞式函數。如果你的 tasklet和其他的tasklet或軟中斷共享了數據,你必須進行適當的鎖保護。

               3)調度自己的tasklet

               通過調用tasklet_schedule()函數來調度。在tasklet被調度以后在其還沒有得到運行機會之前,如果一個相同的tasklet又被調度了,那么它仍只會運行一次。而如果這時它已經開始運行了,那么這個新的tasklet會被重新調度并再次運行。作為一種優化措施,一個tasklet總在調度它的處理器上執行-這是希望更好地利用處理器的高速緩存。可以調用tasklet_disable()函數來禁止某個指定的tasklet,也可以調用tasklet_enable()函數激活一個tasklet。還可以調用tasklet_kill()函數從掛起的隊列中去掉一個tasklet。

            11、每個處理器都有一組輔助處理軟中斷的內核線程。當內核中出現大量軟中斷的時候,這些內核進程就會輔助處理它們。這些內核線程在最低的優先級上運行(nice值是19),這能避免它們跟其他重要的任務搶奪資源,但它們最終肯定會被執行。

            12、工作隊列是另外一種將工作推后執行的形式,它和我們之前討論過的所有其他形式都不相同。工作隊列可以把工作推后,交由一個內核線程去執行-該工作總是會在進程上下文執行。如果你需要用一個可以重新調度的實體來執行你的下半部處理,你應該使用工作隊列。它是唯一能在進程上下文運行的下半部實現的機制,也只有它才可以睡眠。這意味著在你需要獲得大量的內存時、在你需要獲取信號量時,在你需要執行阻塞式的I/O操作時,它都會非常有用。

            13、工作隊列子系統是一個用于創建內核線程的接口,通過它創建的進程負責執行由內核其他部分排到隊列里的任務。它創建的這些內核線程被稱作工作者線程。工作隊列子系統提供了一個缺省的工作者線程來處理需要推后的工作。不過如果需要在工作者線程中執行大量的處理操作,也可以創建屬于自己的工作者線程。這么做有助于減輕缺省線程的負擔,避免工作隊列中其他需要完成的工作處于饑餓狀態。

            14、下半部機制的選擇:簡單地說,一般的驅動程序編寫者需要做兩個選擇。首先,你是不是需要一個可調度的實體來執行需要推后完成的工作-你有休眠的需要嗎?要是有,工作隊列就是你的唯一選擇。否則最好用tasklet。要是必須專注于性能的提高,那么就考慮軟中斷吧。
            99久久无码一区人妻| 久久综合噜噜激激的五月天| 91久久香蕉国产熟女线看| 国产精品亚洲美女久久久| 中文精品99久久国产| 久久精品国产亚洲av水果派 | 久久久久久九九99精品| 国产精品久久久久影院色| 国产福利电影一区二区三区久久老子无码午夜伦不 | 国产亚洲精品自在久久| 精品水蜜桃久久久久久久| 人妻无码中文久久久久专区| 久久精品免费大片国产大片| 性欧美大战久久久久久久久| 久久人妻少妇嫩草AV蜜桃| 色综合久久中文综合网| 久久综合狠狠综合久久| 狠狠色丁香婷婷久久综合五月| 夜夜亚洲天天久久| 国产精品岛国久久久久| 久久精品久久久久观看99水蜜桃 | 日日狠狠久久偷偷色综合96蜜桃| 九九久久自然熟的香蕉图片| 香蕉久久夜色精品国产2020| 久久国产视屏| 国产精品女同一区二区久久| 亚洲国产成人久久综合碰碰动漫3d| 亚洲国产精品无码久久SM| 久久国内免费视频| 伊人久久无码精品中文字幕| 国产亚洲色婷婷久久99精品91| 久久久久久综合一区中文字幕| 久久精品中文无码资源站| 无码国内精品久久人妻蜜桃| 久久精品国产亚洲AV忘忧草18| 久久成人小视频| 一本久道久久综合狠狠躁AV| 欧美亚洲国产精品久久久久| 99久久国产精品免费一区二区| 精产国品久久一二三产区区别 | 99久久综合国产精品免费|