linux從2.6開始支援核心搶占,意味著即使程序執行在核心態也可以被搶占。為了支援核心搶占,**中為每個程序的 thread_info 引入了 preempt_count 計數器,數值為0的時候表示可以核心搶占,每當程序持有核心鎖的時候把 preempt_count 計數器加1,表示禁止核心搶占。此外還有一些其它禁止核心搶占的場景,也通過 preempt_counter 字段反應出來:preempt_counter 欄位是32位的,除了搶占計數器之外還包括其他標誌位,只要 preempt_counter 整體不為0,就不能進行核心搶占,這個設計一下子簡化了對眾多不能搶占的情況的檢測:
這篇筆記要講的是 preempt_active 標誌。preempt_active標誌的本意是表明正在進行核心搶占,設定了之後preempt_counter就不再為0,從而達到禁止核心搶占的效果,使得執行搶占工作的**不會被再搶占。它的乙個重要用途是防止非running狀態的程序被搶占過程錯誤地從run queue中移除
。這句話令人十分費解,已經不處於running狀態的程序本來就不應該留在run queue中,為什麼要防止它被移除?我用了很長時間才琢磨出來,要回答這個問題,首先要理解為什麼非running狀態的程序會被搶占?
所謂搶占,就是從乙個正在執行的程序手上把cpu搶過來,可是既然程序已經不是running狀態了,怎麼會還在cpu上,還被搶占?
這是因為程序從running變成非running要經過幾個步驟:在把自己放進wait queue、狀態置成非running之後,最後呼叫schedule()把自己從run queue中移除、並把cpu交給其他程序。設想一下,乙個程序恰好在呼叫schedule()之前就被搶占了,此時它仍然還在cpu上執行。這就是為什麼非running狀態的程序也會被搶占的原因。對這樣的程序,搶占流程不能擅自將之從run queue中移除,因為它的切換過程沒有完成,應該讓它有機會自己回頭接著做完。比如以下的**,是乙個典型的休眠過程:
1
2
3
4
5
6
for(;;
)
如果在第2行被搶占,剛把程序狀態設定為task_uninterruptible,本來馬上就要測試條件是否滿足了,這時被搶占,而搶占過程必定包含呼叫schedule()的步驟,導致該程序被移出執行佇列,失去了執行機會,隨後的條件判斷語句就無法執行了,假如此時condition條件是滿足的,它本來會跳出for迴圈、而不會去呼叫schedule()進入休眠,然而卻被搶占過程錯誤地呼叫schedule()導致它休眠了,也因此錯過了那個條件判斷語句,也許就永遠沒有被喚醒的機會了。正確的做法是:程序被搶占後還留在run queue中,下次還有機會繼續執行,恢復執行後繼續判斷condition,如果條件不滿足,在隨後主動呼叫的schedule()中會被移出執行佇列,這是不能由搶占代勞的。
下面我們詳細看看preempt_active是如何幫助實現上述的正確做法的。在核心裡,程序從執行態進入休眠態的最後一步是呼叫排程器schedule()——把自己從run queue中移除,把cpu交給其他程序,這在不支援核心搶占的時代沒有問題,因為整個過程不會被打斷,然而核心搶占的出現使情況變複雜了,現在從執行態進入休眠態的過程可能會被搶占所打斷,而搶占過程中會呼叫schedule(),導致schedule()的呼叫提前發生,有可能形成race condition。為了避免這種情況,核心搶占過程中不能直接呼叫schedule()排程器,而是呼叫preempt_schedule(),再通過它來呼叫schedule(),preempt_schedule()會在呼叫schedule()之前設定preempt_active標誌,呼叫之後再清除這個標誌。而schedule()會檢查這個標誌,如果設定了preempt_active標誌,意味著這是從搶占過程中進入schedule(),對於不是task_running(state != 0)的程序,就不會呼叫deactivate_task()把程序從run queue移除。原始碼如下: 1
2
3
4
5
6
7
8
9
10
11
12
13
asmlinkage
void
__sched
schedule
(void)
...這段**的邏輯含義是這樣的:
如果設定了preempt_active,說明該程序是由於核心搶占而被調離cpu的,這時不把它從run queue裡移除;如果preempt_active沒被設定(程序不是由於核心搶占而被調離),還要看一下它有沒有未處理的訊號,如果有的話,也不把它從run queue移除。
總之,只要不是主動呼叫schedule(),而是因被搶占而調離cpu的,程序就還在執行佇列中,還有機會執行。
壯志在我胸
今天由於雜訊的緣故,偶爾塞著耳機聽了聽歌,覺得這首老歌,感覺不錯,記錄下來.壯志在我胸 拍拍身上的灰塵 振作疲憊的精神 遠方也許盡是坎坷路 也許要孤孤單單走一程 早就習慣乙個人 少人關心少人問 就算無人為我付青春 至上我還保有乙份真 拍拍身上的灰塵 振作疲憊的精神 遠方也許盡是坎坷路 也許要孤孤單單...
冰晶畫技術志在何方
知曉了冰晶畫專案的初始地,明白了它的研發背景,我們還要明白這個專案這個專案到底是要幹什麼,也就是它志在何方?對於這個問題,實際上在對濟南廣發科技 的描述中就有冰晶畫專案研發的目的之一,即為創業投資者帶來商機,推動中國技術市場的發展,畢竟再好的技術只是在實驗室內,終究成不了先進的生產力。至於冰晶畫專案...
python獲取日誌 在Python中獲取日誌
不,您不能同時從python和c登入到同乙個檔案。可能是因為多個寫日誌的人沒有把日誌記錄在一起。在 如果您不擁有c dll,那麼您可能會走運,除非它允許您從c 程式配置日誌檔案 級別,否則python無法解決它。但是,如果您控制源 並且可以構建乙個新的dll,請考慮更改c 類以允許您傳入乙個委託 l...