1. 程式人生 > >Linux中程序排程與程序切換

Linux中程序排程與程序切換

Linux程序排程與程序切換

在這篇部落格裡,我們將分析在Linux中程序是如何排程和切換的。程序切換需要進行程序上下文進行排程,注意中斷也會有中斷上下文,這個跟程序上下文還有有一定區別的,中斷上下文,還是在同一個程序,不過程序上下文就是在不同程序了。下面,我們先看一下原始碼,分析一下流程。接著我們在做一下實驗,驗證一下確實是這樣走的。最後我們重點來分析一下程序下文切換的程式碼。

大概流程

通過前面幾周的分析,我們知道排程都需要呼叫schedule()函式,在這個函式裡面有很多不同的排程演算法啊,進行排程選擇,比如next = pick_next_task(rq, prev);就會根據某個排程演算法來選擇下一個準備排程到的程序。選擇一個後,我們要呼叫這個函式context_switch進行上下文的相關切換,在這個函式裡面,我們先呼叫prepare_task_switch進行任務切換的相關準備。接著,我們會呼叫switch_to函式,這個函式是進行暫存器狀態和堆疊的切換,這個函式很重要,我們第一週的作業的作業切換就是模仿這段寫的,後面,我們將會仔細分析這段程式碼。

實驗

下面,我們開始要gdb進行相關的除錯。
首先,像往常一樣,我們先make rootfs,然後開啟gdb,進行除錯。如下圖:
1
接著,我們在下面幾個地方加幾個斷點,如下圖。
4
再接著,我們執行,一步步進行相關的函式,如下圖。
4
4
4

switch_to程式碼分析

下面,我們就來分析一下switch_to這段內斂彙編程式碼。程式碼如下:

    asm volatile("pushfl\n\t"       /* save    flags */ \
43           "pushl %%ebp\n\t"      /* save    EBP   */ \
44 "movl %%esp,%[prev_sp]\n\t" /* save ESP */ \ 45 "movl %[next_sp],%%esp\n\t" /* restore ESP */ \ 46 "movl $1f,%[prev_ip]\n\t" /* save EIP */ \ 47 "pushl %[next_ip]\n\t" /* restore EIP */ \ 48 __switch_canary \ 49 "jmp __switch_to\n
" /* regparm call */ \ 50 "1:\t" \ 51 "popl %%ebp\n\t" /* restore EBP */ \ 52 "popfl\n" /* restore flags */ \ 53 \ 54 /* output parameters */ \ 55 : [prev_sp] "=m" (prev->thread.sp), \ 56 [prev_ip] "=m" (prev->thread.ip), \ 57 "=a" (last), \ 58 \ 59 /* clobbered output registers: */ \ 60 "=b" (ebx), "=c" (ecx), "=d" (edx), \ 61 "=S" (esi), "=D" (edi) \ 62 \ 63 __switch_canary_oparam \ 64 \ 65 /* input parameters: */ \ 66 : [next_sp] "m" (next->thread.sp), \ 67 [next_ip] "m" (next->thread.ip), \ 68 \ 69 /* regparm parameters for __switch_to(): */ \ 70 [prev] "a" (prev), \ 71 [next] "d" (next) \ 72 \ 73 __switch_canary_iparam \ 74 \ 75 : /* reloaded segment registers */ \ 76 "memory"); \

首先儲存當前程序的flags,ebp和棧指標esp到當前的棧裡,接著切換到下一個程序的核心棧,儲存當前的eip,因為這個當前程序當再次被排程到時,就會從這裡開始執行。接著,恢復eip,然後eip就會指向標示1f這個位置,恢復ebp,恢復flags,總之這段程式碼和我們第一週所看的那段程式碼很相似,功能也差不多,就是程序切換。

總結

程序排程和程序切換是現代作業系統中非常重要的一個概念,如果沒有程序切換和排程,那麼系統就會退化到單道處理系統。正因為有了程序切換,才大大提高了cpu的效率,減少了cpu的空閒時間,充分了挖掘了cpu的潛力,提高了計算機的吞吐率