欧美一区二区三区,国内熟女精品熟女A片视频小说,日本av网,小鲜肉男男GAY做受XXX网站

Linux主動調度是如何發(fā)生的

林子帆2年前11瀏覽0評論

Linux主動調度是如何發(fā)生的?

有關進程的知識在前面的博客中已經提到了,有不懂的地方請參考我前面的博客,今天我直接從進程調度和切換開始講。

Linux一個較大的優(yōu)勢就是進程調度,因為Linux是一個多進程系統(tǒng),它怎么進行進程調度直接影響這個系統(tǒng)的性能,而Linux系統(tǒng)的一個優(yōu)勢就是它的系統(tǒng)在進程調度這里做的很好。

在講進程調度前,我們先來看下有關Linux知識(以下4張圖片摘自孟寧老師課件)。

圖1.Linux內核架構

圖2.Linux執(zhí)行過程

圖3.CPU執(zhí)行指令角度

圖4.從內存角度看待Linux系統(tǒng)執(zhí)行

首先一起來看下Linux的進程的類型,一般將進程分為三種,一種為I/O消耗型進程,另一種是處理器消耗型進程,還有一種是混合型,也就是I/O消耗型進程和處理器消耗型進程混合在一起的。從他們的名字可以看出,這是以進程消耗資源的種類來進行分類的。

在Linux系統(tǒng)中,是按照什么規(guī)則來進行調度的呢?我們所知的有優(yōu)先級調度,還有時間片調度。其中優(yōu)先級指的是進程的優(yōu)先級,而時間片則指的是進程所需要消耗的時間。

那么Linux系統(tǒng)中進程調度的過程到底是一個什么流程呢?主要是以下幾個方面

1.從schedule()函數開始,進行調度選擇

2.從CPU的值變化上,解讀switch_to宏執(zhí)行分析

3.到堆棧發(fā)生切換位置,在切換堆棧前后,current_thread_info變化

4.再到地址空間發(fā)生切換,解釋地址空間的切換不會影響后續(xù)切換代碼的執(zhí)行

5.Current宏代表的進程發(fā)生變化的源碼位置

6.任務狀態(tài)段中關于內核堆棧的信息發(fā)生變化的源碼位置

下面來詳細的講解一下各個環(huán)節(jié)

在Linux內核中,schedule()函數選擇一個新的進程來運行,并調用context_switch進行上下文的切換,這個宏調用switch_to來進行關鍵上下文切換。部分函數具體代碼如下,一個調度新進程,一個是進行上下文切換,還有相關堆棧信息的保存。

next= pick_next_task(rq, prev);//進程調度算法都封裝這個函數內部

context_switch(rq,prev, next);//進程上下文切換

switch_to利用了prev和next兩個參數:prev指向當前進程,next指向被調度的進程

Schedule:主要負責幫助系統(tǒng)選定下一個執(zhí)行的進程

調度時機:

1.進程狀態(tài)轉換的時刻,進程終止、進程睡眠。

2.當前進程的時間片用完時。

3.設備驅動程序調用。

4.進程從中斷、異常及系統(tǒng)調用返回到用戶態(tài)時。

進程的從睡眠狀態(tài)到喚醒狀態(tài),完成了一次進程的調度,中間有保存相應的進程信息,有相應的隊列進行保存。

進程調度中還有一個現象是搶占,就是優(yōu)先級高的進程進行搶占低優(yōu)先級的執(zhí)行機會,用戶搶占發(fā)生在兩種情況下,一個是從系統(tǒng)調用返回用戶空間,另一個是從中斷處理程序返回用戶空間。

而內核搶占發(fā)生在:

1.當從中斷處理程序正在執(zhí)行,且返回內核空間之前;

2.當內核代碼再一次具有可搶占性的時候;

3.如果內核中的任務顯式調用;

4.內核中的任務被阻塞。

上下文的切換也是進程調用中一個比較重要的問題,其中有一個context_switch()函數完成以下工作,switch_mm()——該函數負責把虛擬內存從上一個進程映射切換到新進程中。而switch_to()——負責從上一個進程的處理器狀態(tài)切換到新進程的處理器狀態(tài)。切換的過程包括保存、恢復棧信息和寄存器信息。

其中各種進程之間的調度又有很多方法,主要有先進先出、時間片輪轉等方式,這里就不具體分析,有興趣的可以自行查閱相應的調度方法。

下面來看下具體實驗過程:

圖5.相關指令操作,創(chuàng)建文件

圖6.文件內部修改處

圖7.文件內部修改處

圖8.調試啟動

圖9.設置斷點

圖10.查看context_switch處相關點代碼

圖11.中途的代碼調試過程

總結:從上面可以看出,Linux系統(tǒng)的進程切換的一般執(zhí)行過程是這樣的,從進程X轉向進程Y的過程是這樣的。

1.正在運行的用戶態(tài)進程X 。

2.發(fā)生中斷——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之后開始運行用戶態(tài)進程Y(這里Y曾經通過以上步驟被切換出去過因此可以從標號1繼續(xù)執(zhí)行)。

6.restore_all //恢復現場。

7.iret- pop cs:eip/ss:esp/eflags from kernel stack //恢復。

8.繼續(xù)運行用戶態(tài)進程Y

好了,從上面可以看到,整個Linux系統(tǒng)的進程切換的執(zhí)行流程就是這個樣子的!