首頁>Club>
4
回覆列表
  • 1 # java樂園

    有關程序的知識在前面的部落格中已經提到了,有不懂的地方請參考我前面的部落格,今天我直接從程序排程和切換開始講。

    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系統的程序切換的執行流程就是這個樣子的!

  • 中秋節和大豐收的關聯?
  • 延長工作時間和加班幾小時算一個班?