歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux綜合 >> Linux內核 >> Linux內核分析——進程的切換和系統的一般執行過程

Linux內核分析——進程的切換和系統的一般執行過程

日期:2017/3/2 17:15:09   编辑:Linux內核

            進程的切換和系統的一般執行過程

一、進程切換的關鍵代碼switch_to分析

(一)進程調度與進程調度的時機分析

  1、不同類型的進程有不同的調度需求

  第一種分類:

    (1)I/O-bound:頻繁進行I/O,花費很多時間等待I/O操作的完成。

    (2)CPU-bound:計算密集型,需要大量CPU時間進行計算。

  第二種分類:

    (1)批處理進程:不必交互、很快響應。

    (2)實時進程:要求響應時間短。

    (3)交互式進程(shell)。

  2、調度策略:是一組規則,它們決定什麼時候以怎樣的方式選擇一個新進程運行。

  3、linux進程調度是基於分時和優先級的。

  4、Linux的進程根據優先級排隊。

  5、Linux中進程的優先級是動態的。

  6、內核中的調度算法相關代碼使用了類似OOD中的策略模式。

  7、進程調度的時機:

    (1)中斷處理過程(包括時鐘中斷、I/O中斷、系統調用和異常)中,直接調用schedule(),或者返回用戶態時根據need_resched標記調用schedule();

    (2)內核線程(只有內核態沒有用戶態的特殊進程)可以直接調用schedule()進行進程切換,也可以在中斷處理過程中進行調度,也就是說內核線程作為一類的特殊的進程可以主動調度,也可以被動調度;

    (3)用戶態進程無法實現主動調度,只能被動調度,僅能通過陷入內核態後的某個時機點進行調度,即在中斷處理過程中進行調度。

(二)進程上下文切換相關代碼分析

  1、進程的切換

    (1)為了控制進程的執行,內核必須有能力掛起正在CPU上執行的進程,並恢復以前掛起的某個進程的執行,這叫做進程切換、任務切換、上下文切換;

    (2)掛起正在CPU上執行的進程,與中斷時保存現場是不同的,中斷前後是在同一個進程上下文中,只是由用戶態轉向內核態執行;

    (3)進程上下文包含了進程執行需要的所有信息

        1)用戶地址空間:包括程序代碼,數據,用戶堆棧等

        2)控制信息:進程描述符,內核堆棧等

        3)硬件上下文(注意中斷也要保存硬件上下文只是保存的方法不同)

  2、schedule()函數選擇一個新的進程來運行,並調用context_switch進行上下文的切換,這個宏調用switch_to來進行關鍵上下文切換

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

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

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

  3、schedule()中:

  

  

  4、context_switch中:

  

  5、switch_to中:

31#define switch_to(prev, next, last)

32do {

33 /*

34 * Context-switching clobbers all registers, so we clobber

35 * them explicitly, via unused output variables.

36 * (EAX and EBP is not listed because EBP is saved/restored

37 * explicitly for wchan access and EAX is the return value of

38 * __switch_to())

39 */

40 unsigned long ebx, ecx, edx, esi, edi;

41

42 asm volatile("pushfl\n\t" /* save flags */ //保存當前進程的flags

43 "pushl %%ebp\n\t" /* save EBP */ //把當前進程的堆棧基址壓棧

44 "movl %%esp,%[prev_sp]\n\t" /* save ESP */ //把當前的棧頂保存到prev->thread.sp

45 "movl %[next_sp],%%esp\n\t" /* restore ESP */ //把下一個進程的棧頂保存到esp中,這兩句完成了內核堆棧的切換

46 "movl $1f,%[prev_ip]\n\t" /* save EIP */ //保存當前進程的EIP,可以從這恢復

47 "pushl %[next_ip]\n\t" /* restore EIP */ //把下一個進程的起點位置壓到堆棧,就是next進程的棧頂。next_ip一般是$1f,對於新創建的子進程是ret_from_fork

//一般用return直接把next_ip pop出來

48 __switch_canary

49 "jmp __switch_to\n" /* regparm call */ //jmp通過寄存器傳遞參數,即後面的a,d。 函數__switch_to也有return把next_ip pop出來

50 "1:\t" //認為從這開始執行next進程(EIP角度),第一條指令是next_ip這個起點,但前面已經完成內核堆棧的切換,早就是next進程的內核堆棧(算prev進程,比較模糊)

51 "popl %%ebp\n\t" /* restore EBP */ //next進程曾經是prev進程,壓棧過ebp

52 "popfl\n" /* restore flags */

53

54 /* output parameters */

55 : [prev_sp] "=m" (prev->thread.sp), //當前進程的,在中斷內部,在內核態,sp是內核堆棧的棧頂

56 [prev_ip] "=m" (prev->thread.ip), //當前進程的EIP

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");

77} while (0)

二、Linux系統的一般執行過程

(一)Linux系統的一般執行過程分析

  1、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 to kernel 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系統執行過程中的幾個特殊情況

  1、幾種特殊情況

    (1)通過中斷處理過程中的調度時機,用戶態進程與內核線程之間互相切換和內核線程之間互相切換,與最一般的情況非常類似,只是內核線程運行過程中發生中斷沒有進程用戶態和內核態的轉換;

    (2)內核線程主動調用schedule(),只有進程上下文的切換,沒有發生中斷上下文的切換,與最一般的情況略簡略;

    (3)創建子進程的系統調用在子進程中的執行起點及返回用戶態,如fork;

    (4)加載一個新的可執行程序後返回到用戶態的情況,如execve;

三、Linux系統架構和執行過程概覽

(一)Linux操作系統架構概覽

  

  

(二)最簡單也是最復雜的操作--執行ls命令

  

(三)從CPU和內存的角度看Linux系統的執行

  1、CPU執行指令的角度:

  

  2、內存的角度:

  

四、實驗

  1、環境搭建

    cd LinuxKernel

    rm menu -rf

    git clone https://github.com/mengning/menu.git

    cd menu

    mv test_exec.c test.c

    make rootfs

  

  

  2、gdb調試

    Qemu –kernel ../linux-3.18.6/arch/x86/boot/bzImage -initrd ../rootfs.img -s -S

    gdb

    file ../linux-3.18.6/vmlinux

    target remote:1234

  3、設置斷點

    b schedule

    b pick_next_task

    b context_switch

    b switch_to

  

  

  

  

五、總結

  1、Linux進程調度是基於分時和優先級的。

  2、Linux中,內核線程是只有內核態沒有用戶態的特殊進程。

  3、內核可以看作各種中斷處理過程和內核線程的集合。

  4、Linux系統的一般執行過程 可以抽象成正在運行的用戶態進程X切換到運行用戶態進程Y的過程。

  5、Linux中,內核線程可以主動調度,主動調度時不需要中斷上下文的切換。

  6、Linux內核調用schedule()函數進行調度,並調用context_switch進行上下文的切換,這個宏調用switch_to來進行關鍵上下文切換。

Copyright © Linux教程網 All Rights Reserved