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

2021-09-26 09:10:48 字數 3485 閱讀 6282

中斷處理程式作為上半部,執行時要麼禁用所有中斷,要麼禁用當前線上的中斷,要麼禁用當前處理機上的同級中斷來保證當前中斷處理的正常執行

下半部用於處理中斷服務的其它任務,允許推後執行,包括軟中斷tasklet(基於軟中斷)工作佇列

靜態編譯,只有32個軟中斷,目前只用到了9個。靜態結構體陣列中都可含有該軟中斷對應的程式指標,以便執行。

struct softirq_action;   //單一軟中斷結構,其實也就是繫結執行函式

static struct softirq_action  softirq_vec[nr_softirqs];//32個靜態軟中斷向量

軟中斷不會搶占另乙個軟中斷(可以看出是序列執行的,當然在多處理機的情況下是可以多個軟中斷同時執行的),唯一可以搶占軟中斷的只有中斷處理程式。軟中斷不允許休眠,因為乙個休眠將引發之後連續滯後,同乙個軟中斷可能會被再次觸發,所以對於共享資料需要加鎖處理。

執行軟中斷時刻:乙個硬體中斷**返回之時;ksoftirqd核心執行緒中;顯式檢查和執行待處理的軟中斷**(網路子系統而非核心規劃)。通過執行do_softirq(),按照0-31的優先順序順序來依次執行已經註冊的軟中斷(通過軟中斷點陣圖來檢視)。

使用軟中斷:使用軟中斷的子系僅有網路和scsi,首先得註冊處理程式open_softirq(索引號,下半部執行實體),之後使用raise_softirq(索引號)來將索引號的軟中斷觸發為執行態(這個函式不能被中斷打擾所以具有關中斷的效果,一般執行的地點位於中斷處理程式處,一般已經關閉中斷了,因此使用raise_softirq_irqoff(索引號)來不用額外中斷)(這樣下次呼叫do_softirq()的時刻就可以執行這個軟中斷了)

優勢:適用於執行頻率很高,連續性要求很高的情況。

實質是兩個軟中斷,高低優先順序各乙個。

struct tasklet_struct

已經排程的tasklet存放在tasklet_vec和tasklet_hi_vec(高優先順序)這兩個鍊錶中,保證先執行高優先順序的。由tasklet_schedule()和tasklet_hi_schedule()分別進行排程(也就是置位就緒狀態,不是直接執行,並將之掛在鍊錶上,最終喚起相應的兩個軟中斷)在這個過程中需要關中斷保證資料安全。

執行過程:同樣的,通過軟中斷執行函式do_softirq()來呼叫tasklet_action()和tasklet_hi_action()來遍歷那兩個鍊錶,進而依次執行所有已經就緒的tasklet,步驟如下:

1.  先關中斷檢索鍊錶,清空狀態

2.  遍歷所有鍊錶,執行可以執行的tasklet(處於就緒態的保證多處理機不同時執行乙個tasklet(互斥性),且引用計數=0,),喚起乙個tasklet時就會喚起兩個軟中斷中的乙個(當即動態完成繫結軟中斷,並立即顯式執行軟中斷),保證乙個時間段裡只有乙個給定類別的tasklet會執行(也就是最多一次執行兩個tasklet?)。

建立tasklet:通過靜態或者動態按照傳入引數建立乙個tasklet_struct結構體,並在結構體裡匯入自己的tasklet處理函式。通過tasklet_schedule()將該結構體傳入完成啟用排程,tasklet_disable(),tasklet_disable_nosync()用來禁止tasklet,tasklet_enable()啟用使能,tasklet_kill()從佇列中刪除。

tasklet機制基於軟中斷,所以不可處於睡眠狀態,所以不可呼叫訊號量等阻塞機制!!

ksoftirqd機制:每個處理器都有的乙個輔助處理軟中斷的核心執行緒,用於在大量軟中斷的情況下輔助處理,

於是引入這種核心執行緒,優先順序很低的,平時處於訊號響應狀態(interruptible),一旦系統檢測出負載比較大就傳遞訊號量予以喚醒,用於檢視自己cpu下的軟中斷狀態,呼叫do_softirq(),這作為一種折衷,既可以保證軟中斷執行,也可以保證正常程序的執行。 

當do_softirq()發現已經執行過的核心執行緒重新觸發了自己,這就會觸發訊號量通知軟中斷核心執行緒喚醒。

本質就是將下半部置於乙個核心執行緒中,唯一可以在程序上下文執行的下半部實體,因此唯一的可以睡眠,用於獲得大量記憶體,或者需要進行阻塞式i/o操作時,忙等會消耗時間,所以此時需要睡眠機制。

實現形式:將需要推後的任務交給特定的通用執行緒的介面,預設的工作者執行緒叫events/n,其中n對應於cpu編號,每乙個cpu對應乙個執行緒。也可以自己按照需要建立專門用於處理特定下半部的工作者執行緒,這可能有助於減輕預設執行緒的負擔(將當前任務重的下半部單獨提出來,這樣就使得其餘比較輕的下半部不至於飢餓),提高執行效率。

a.工作者執行緒結構,乙個表示一種工作者,其意思就是有多種工作者執行緒,目前只有一種event這種執行緒,可以按照需要自己建立新的執行緒專門處理某一類下半部:

struct workqueue_struct

建立方法:struct workqueue_struct    *create_workqueue(名字);    相當於是建立自己的執行緒,在建立之後就可以使用queue_work( struct workqueue_struct *(工作者執行緒),work_struct *work(與之對應的執行緒執行實體鍊錶)),還有一些,總之能實現預設執行緒的功能。

b.其中裝載工作者執行緒的結構體:struct cpu_workqueue_struct

c.裝載下半部執行實體的:struct work_struct

d.執行緒中執行worker_thread()函式,目的就是執行的時候判斷下半部實體的鍊錶是否為空,為空則進入睡眠,不為空則一一取出執行(呼叫下半部執行實體的函式),執行完畢之後從佇列上面摘下來,並修改相關標誌,直到將佇列上的下半部全部執行完成為止。

實現方法:首先使用靜態方法(巨集)或者傳入指標動態地建立乙個work_struct結構體用於裝載自己的下半部程式(指標)。傳入的下半部程式只能**自己的事情,不能訪問使用者空間

排程:schedule_work(work_struct *work),將傳入的下半部實體載入到某乙個cup所對應的工作者執行緒上,當該執行緒執行的時候就能安排執行這個執行緒了。也可以延遲schedule_delayed_work(work,delay)。

還有一種重新整理操作:類似於記憶體屏障,這個重新整理等待指定工作佇列(怎麼傳入,指定等待的不知道)完成,取消延遲執行的工作 int cancel_delayed_work(work_struct *work)。

注意:沒有給定struct workqueue_struct的函式均是針對於預設執行緒的。

1.軟中斷對於順序執行保證沒有(相同的軟中斷,先後繫結執行,可以在多個不同處理器上面執行),必須小心設定邏輯,但是效能高,可選擇性多

2.tasklet占用兩個軟中斷,所以相同型別的tasklet不能併發執行(互斥性的原因),保證了單個tasklet的按序執行。

3.工作佇列實現容易,在程序中安排了,允許睡眠,要善用這種特性。

加鎖:上下文和下半部共享資料:禁止下半部,兩個函式用於禁止可啟用,

上下文和中斷共享資料:關中斷

上下文和工作佇列:通用的鎖機制即可。

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

8.2 軟中斷 討論從實際的下半部實現 軟中斷方法開始。軟中斷使用得比較少 而tasklet是下半部更常用的一種形式。但是,由於tasklet是通過軟中斷實現的,先來研究軟中斷。軟中斷的 位於kernel softirq.c檔案中。8.2.1 軟中斷的實現 軟中斷是在編譯期間靜態分配的。它不像tas...

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

中斷處理程式的侷限 1 中斷處理程式以非同步的方式執行,並且它有可能會打斷其他重要 的執行。2 如果當前有乙個中斷處理程式正在執行,最好的情況是,與該中斷同級的其他中斷會被遮蔽,最壞情況下,當預處理器上所有其他中斷都會被遮蔽。3 中斷處理程式往往需要對硬體進行操作,所以他們不能阻塞。這限制了他們所作...

第8章 條件和迴圈 1

8.1 if語句 8.1.1 多重條件表示式 單個if語句可以通過使用布林操作符and or和not實現多重判斷條件或是否定判斷條件。8.1.2 單一語句的 塊 如果乙個復合語句的 塊僅僅包含一行 那麼它可以和前面的語句寫在同一行上。8.2 else語句 8.3 elif 即else if 語句 p...