有關程序的知識在前面的部落格中已經提到了,有不懂的地方請參考我前面的部落格,今天我直接從程序排程和切換開始講。
Linux一個較大的優勢就是程序排程,因為Linux是一個多程序系統,它怎麼進行程序排程直接影響這個系統的效能,而Linux系統的一個優勢就是它的系統在程序排程這裡做的很好。
在講程序排程前,我們先來看下有關Linux知識(以下4張圖片摘自孟寧老師課件)。
圖1.Linux核心架構
圖2.Linux執行過程
圖3.CPU執行指令角度
圖4.從記憶體角度看待Linux系統執行
首先一起來看下Linux的程序的型別,一般將程序分為三種,一種為I/O消耗型程序,另一種是處理器消耗型程序,還有一種是混合型,也就是I/O消耗型程序和處理器消耗型程序混合在一起的。從他們的名字可以看出,這是以程序消耗資源的種類來進行分類的。
在Linux系統中,是按照什麼規則來進行排程的呢?我們所知的有優先順序排程,還有時間片排程。其中優先順序指的是程序的優先順序,而時間片則指的是程序所需要消耗的時間。
那麼Linux系統中程序排程的過程到底是一個什麼流程呢?主要是以下幾個方面
1.從schedule()函式開始,進行排程選擇
2.從CPU的值變化上,解讀switch_to宏執行分析
3.到堆疊發生切換位置,在切換堆疊前後,current_thread_info變化
4.再到地址空間發生切換,解釋地址空間的切換不會影響後續切換程式碼的執行
5.Current宏代表的程序發生變化的原始碼位置
6.任務狀態段中關於核心堆疊的資訊發生變化的原始碼位置
下面來詳細的講解一下各個環節
在Linux核心中,schedule()函式選擇一個新的程序來執行,並呼叫context_switch進行上下文的切換,這個宏呼叫switch_to來進行關鍵上下文切換。部分函式具體程式碼如下,一個排程新程序,一個是進行上下文切換,還有相關堆疊資訊的儲存。
next= pick_next_task(rq, prev);//程序排程演算法都封裝這個函式內部
context_switch(rq,prev, next);//程序上下文切換
switch_to利用了prev和next兩個引數:prev指向當前程序,next指向被排程的程序
Schedule:主要負責幫助系統選定下一個執行的程序
排程時機:
1.程序狀態轉換的時刻,程序終止、程序睡眠。
2.當前程序的時間片用完時。
3.裝置驅動程式呼叫。
4.程序從中斷、異常及系統呼叫返回到使用者態時。
程序的從睡眠狀態到喚醒狀態,完成了一次程序的排程,中間有儲存相應的程序資訊,有相應的佇列進行儲存。
程序排程中還有一個現象是搶佔,就是優先順序高的程序進行搶佔低優先順序的執行機會,使用者搶佔發生在兩種情況下,一個是從系統呼叫返回使用者空間,另一個是從中斷處理程式返回使用者空間。
而核心搶佔發生在:
1.當從中斷處理程式正在執行,且返回核心空間之前;
2.當核心程式碼再一次具有可搶佔性的時候;
3.如果核心中的任務顯式呼叫;
4.核心中的任務被阻塞。
上下文的切換也是程序呼叫中一個比較重要的問題,其中有一個context_switch()函式完成以下工作,switch_mm()——該函式負責把虛擬記憶體從上一個程序對映切換到新程序中。而switch_to()——負責從上一個程序的處理器狀態切換到新程序的處理器狀態。切換的過程包括儲存、恢復棧資訊和暫存器資訊。
其中各種程序之間的排程又有很多方法,主要有先進先出、時間片輪轉等方式,這裡就不具體分析,有興趣的可以自行查閱相應的排程方法。
下面來看下具體實驗過程:
圖5.相關指令操作,建立檔案
圖6.檔案內部修改處
圖7.檔案內部修改處
圖8.除錯啟動
圖9.設定斷點
圖10.檢視context_switch處相關點程式碼
圖11.中途的程式碼除錯過程
總結:從上面可以看出,Linux系統的程序切換的一般執行過程是這樣的,從程序X轉向程序Y的過程是這樣的。
1.正在執行的使用者態程序X 。
2.發生中斷——save cs:eip/esp/eflags(current)to kernel stack,then load cs:eip(entry of a specific ISR) and
ss:esp(point tokernel stack)。
3.SAVE_ALL//儲存現場。
4.中斷處理過程中或中斷返回前呼叫了schedule(),其中的switch_to做了關鍵的程序上下文切換。
5.標號1之後開始執行使用者態程序Y(這裡Y曾經透過以上步驟被切換出去過因此可以從標號1繼續執行)。
6.restore_all //恢復現場。
7.iret- pop cs:eip/ss:esp/eflags from kernel stack //恢復。
8.繼續執行使用者態程序Y
好了,從上面可以看到,整個Linux系統的程序切換的執行流程就是這個樣子的!
有關程序的知識在前面的部落格中已經提到了,有不懂的地方請參考我前面的部落格,今天我直接從程序排程和切換開始講。
Linux一個較大的優勢就是程序排程,因為Linux是一個多程序系統,它怎麼進行程序排程直接影響這個系統的效能,而Linux系統的一個優勢就是它的系統在程序排程這裡做的很好。
在講程序排程前,我們先來看下有關Linux知識(以下4張圖片摘自孟寧老師課件)。
圖1.Linux核心架構
圖2.Linux執行過程
圖3.CPU執行指令角度
圖4.從記憶體角度看待Linux系統執行
首先一起來看下Linux的程序的型別,一般將程序分為三種,一種為I/O消耗型程序,另一種是處理器消耗型程序,還有一種是混合型,也就是I/O消耗型程序和處理器消耗型程序混合在一起的。從他們的名字可以看出,這是以程序消耗資源的種類來進行分類的。
在Linux系統中,是按照什麼規則來進行排程的呢?我們所知的有優先順序排程,還有時間片排程。其中優先順序指的是程序的優先順序,而時間片則指的是程序所需要消耗的時間。
那麼Linux系統中程序排程的過程到底是一個什麼流程呢?主要是以下幾個方面
1.從schedule()函式開始,進行排程選擇
2.從CPU的值變化上,解讀switch_to宏執行分析
3.到堆疊發生切換位置,在切換堆疊前後,current_thread_info變化
4.再到地址空間發生切換,解釋地址空間的切換不會影響後續切換程式碼的執行
5.Current宏代表的程序發生變化的原始碼位置
6.任務狀態段中關於核心堆疊的資訊發生變化的原始碼位置
下面來詳細的講解一下各個環節
在Linux核心中,schedule()函式選擇一個新的程序來執行,並呼叫context_switch進行上下文的切換,這個宏呼叫switch_to來進行關鍵上下文切換。部分函式具體程式碼如下,一個排程新程序,一個是進行上下文切換,還有相關堆疊資訊的儲存。
next= pick_next_task(rq, prev);//程序排程演算法都封裝這個函式內部
context_switch(rq,prev, next);//程序上下文切換
switch_to利用了prev和next兩個引數:prev指向當前程序,next指向被排程的程序
Schedule:主要負責幫助系統選定下一個執行的程序
排程時機:
1.程序狀態轉換的時刻,程序終止、程序睡眠。
2.當前程序的時間片用完時。
3.裝置驅動程式呼叫。
4.程序從中斷、異常及系統呼叫返回到使用者態時。
程序的從睡眠狀態到喚醒狀態,完成了一次程序的排程,中間有儲存相應的程序資訊,有相應的佇列進行儲存。
程序排程中還有一個現象是搶佔,就是優先順序高的程序進行搶佔低優先順序的執行機會,使用者搶佔發生在兩種情況下,一個是從系統呼叫返回使用者空間,另一個是從中斷處理程式返回使用者空間。
而核心搶佔發生在:
1.當從中斷處理程式正在執行,且返回核心空間之前;
2.當核心程式碼再一次具有可搶佔性的時候;
3.如果核心中的任務顯式呼叫;
4.核心中的任務被阻塞。
上下文的切換也是程序呼叫中一個比較重要的問題,其中有一個context_switch()函式完成以下工作,switch_mm()——該函式負責把虛擬記憶體從上一個程序對映切換到新程序中。而switch_to()——負責從上一個程序的處理器狀態切換到新程序的處理器狀態。切換的過程包括儲存、恢復棧資訊和暫存器資訊。
其中各種程序之間的排程又有很多方法,主要有先進先出、時間片輪轉等方式,這裡就不具體分析,有興趣的可以自行查閱相應的排程方法。
下面來看下具體實驗過程:
圖5.相關指令操作,建立檔案
圖6.檔案內部修改處
圖7.檔案內部修改處
圖8.除錯啟動
圖9.設定斷點
圖10.檢視context_switch處相關點程式碼
圖11.中途的程式碼除錯過程
總結:從上面可以看出,Linux系統的程序切換的一般執行過程是這樣的,從程序X轉向程序Y的過程是這樣的。
1.正在執行的使用者態程序X 。
2.發生中斷——save cs:eip/esp/eflags(current)to kernel stack,then load cs:eip(entry of a specific ISR) and
ss:esp(point tokernel stack)。
3.SAVE_ALL//儲存現場。
4.中斷處理過程中或中斷返回前呼叫了schedule(),其中的switch_to做了關鍵的程序上下文切換。
5.標號1之後開始執行使用者態程序Y(這裡Y曾經透過以上步驟被切換出去過因此可以從標號1繼續執行)。
6.restore_all //恢復現場。
7.iret- pop cs:eip/ss:esp/eflags from kernel stack //恢復。
8.繼續執行使用者態程序Y
好了,從上面可以看到,整個Linux系統的程序切換的執行流程就是這個樣子的!