week 8 進程的切換和系統的通常執行過程
1、進程調度與進程調度的時機分析
- 操做系統原理中介紹了大量進程調度算法,這些算法從實現的角度看僅僅是從運行隊列中選擇一個新進程,選擇的過程當中運用了不一樣的策略而已。對於理解操做系統的工做機制,反而是進程的調度時機與進程的切換機制更爲關鍵。
- 不一樣類型的進程有不一樣的調度需求
-
第一種分類:算法
-
I/O-boundshell
- 頻繁的進行I/O
- 一般會花費不少時間等待I/O操做的完成
-
CPU-bound架構
-
第二種分類函數
- 批處理進程
- 沒必要與用戶交互,一般在後臺運行
- 沒必要很快響應
- 典型的批處理程序:編譯程序、科學計算
- 實時進程
- 有實時要求,不該被低優先級的進程阻塞
- 響應時間要短、要穩定
- 典型的實時進程:視頻/音頻、機械控制等
- 交互式進程
- 須要常常與用戶交互,所以要花很長時間等待用戶輸入操做
- 響應時間要快,平均延遲要低於50~150ms
- 典型的交互式程序:shell、文本編輯程序、圖形應用程序等
-
Linux既支持普通的分時進程,也支持實時進程操作系統
- Linux中的調度是多種調度策略和調度算法的混合
- 什麼事調度策略?
- 是一組規則,他們決定何時以怎樣的方式選擇一個新進程運行
- Linux的調度基於分時和優先級
- Linux的進程根據優先級排隊
- 根據特定的算法計算出進程的優先級,用一個值表示
- 這個值表示把進程如何適當的分配給CPU
- Linux中進程的優先級是動態的
- 調度程序會根據進程的行爲週期性的調整進程的優先級
- 較長時間未分配到CPU的進程,一般往上
- 已經在CPU上運行了較長時間的進程一般往下
- 內核中的調度算法相關代碼使用了相似OOD中的策略模式
- 將調度算法與其餘部分耦合了
-
****進程調度的時機線程
• 中斷處理過程(包括時鐘中斷、I/O中斷、系統調用和異常)中,直接調用schedule(),或者返回用戶態時根據need_resched標記調用schedule();rest
• 內核線程能夠直接調用schedule()進行進程切換,也能夠在中斷處理過程當中進行調度,也就是說內核線程做爲一類的特殊的進程能夠主動調度,也能夠被動調度;視頻
• 用戶態進程沒法實現主動調度,僅能經過陷入內核態後的某個時機點進行調度,即在中斷處理過程當中進行調度。blog
- 用戶態進程只能被動調度
- 內核線程是隻有內核態沒有用戶態的特殊進程
- 內核線程能夠主動調度也能夠被動調度
2、進程上下文代碼的相關分析
-
進程的切換隊列
• 爲了控制進程的執行,內核必須有能力掛起正在CPU上執行的進程,並恢復之前掛起的某個進程的執行,這叫作進程切換、任務切換、上下文切換;
• 掛起正在CPU上執行的進程,與中斷時保存現場是不一樣的,中斷先後是在同一個進程上下文中,只是由用戶態轉向內核態執行;
• 進程上下文包含了進程執行須要的全部信息
• 用戶地址空間: 包括程序代碼,數據,用戶堆棧等
• 控制信息 :進程描述符,內核堆棧等
• 硬件上下文(注意中斷也要保存硬件上下文只是保存的方法不一樣)
- schedule()函數選擇一個新的進程來運行,並調用contextswitch進行上下文的切換,這個宏調用switchto來進行關鍵上下文切換
• next = picknexttask(rq, prev);//進程調度算法都封裝這個函數內部
• context_switch(rq, prev, next);//進程上下文切換
• switchto利用了prev和next兩個參數:prev指向當前進程,next指向被調度的進程 ```1. 31#define switchto(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 * _switchto()) \
- 39 */ \
- 40 unsigned long ebx, ecx, edx, esi, edi; \
- 41 \
- 42 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 _switchcanary \
- 49 "jmp _switchto\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 switchcanaryoparam \
- 64 \
- 65 /* input parameters: */ \
- 66 : [next_sp] "m" (next->thread.sp), \
- 67 [next_ip] "m" (next->thread.ip), \
- 68 \
- 69 /* regparm parameters for _switchto(): */ \
- 70 [prev] "a" (prev), \
- 71 [next] "d" (next) \
- 72 \
- 73 switchcanaryiparam \
- 74 \
- 75 : /* reloaded segment registers */ \
- 76 "memory"); \
-
77} while (0)
-
nextip通常是¥1f,對於新建立的子進程是retfrom_fork
3、Linux系統的通常執行過程分析
4、Linux系統執行過程當中的幾個特殊狀況
幾種特殊狀況
• 經過中斷處理過程當中的調度時機,用戶態進程與內核線程之間互相切換和內核線程之間互相切換,與最通常的狀況很是相似,只是內核線程運行過程當中發生中斷沒有進程用戶態和內核態的轉換;
• 內核線程主動調用schedule(),只有進程上下文的切換,沒有發生中斷上下文的切換,與最通常的狀況略簡略;
• 建立子進程的系統調用在子進程中的執行起點及返回用戶態,如fork;(nextip = retfrom_fork)
• 加載一個新的可執行程序後返回到用戶態的狀況,如execve;
5、內核與舞女
內核是各類中斷處理過程和內核線程的組合。
6、Linux操做系統架構概覽
-
操做系統的基本概念
-
典型的Linux操做系統的結構
-
最簡單也是最複雜的操做
-
站在CPU執行指令的角度
-
從內存的角度來看
7、最簡單也是最複雜的操做--執行ls命令
8、從CPU和內存的角度看Linux系統的執行
- 執行gets()函數;
- 執行系統調用,陷入內核;
- 等待輸入,CPU會調度其餘進程執行,同時wait一個I/O中斷;
- 敲擊ls,發I/O中斷給CPU,中斷處理程序進行現場保存、壓棧等等;
- 中斷處理程序發現X進程在等待這個I/O(此時X已經變成阻塞態),處理程序將X設置爲WAKE_UP;
- 進程管理可能會把進程X設置爲next進程,這樣gets系統調用得到數據,再返回用戶態堆棧
- 從內存角度看,全部的物理地址都會被映射到3G以上的地址空間:由於這部分對全部進程來講都是共享的