Linux内核分析--操作系统是如何工作的
“平安的祝福 + 原創作品轉載請注明出處 + 《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000?”
一、初始化進程
操作系統內核啟動入口函數是void __init my_start_kernel(void);
在這里簡單定義進程的的兩個cpu狀態:
struct Thread {
??? unsigned long?? ??? ?ip; //表示eip指令
??? unsigned long?? ??? ?sp;//表示esp,棧頂指針
};
在此函數中初始化第一個進程--pid=0;一切進程都是以它為父進程。
在初始化第一個進程時,分配進程pid=0,指定棧頂指針,初始化pcb的命令即ip的值--進程my_process的入口地址。
運行第一個進程的流程
設置進程狀態為正在運行,通過嵌入式匯編程序使進程占據cpu運行
asm volatile(
?? ??? ?"movl %1,%%esp\n\t" ?? ?/* set task[pid].thread.sp to esp */
?? ??? ?"pushl %1\n\t" ?? ???????? /* push ebp */
?? ??? ?"pushl %0\n\t" ?? ???????? /* push task[pid].thread.ip */
?? ??? ?"ret\n\t" ?? ???????????? /* pop task[pid].thread.ip to eip */
?? ??? ?"popl %%ebp\n\t"
?? ??? ?:
?? ??? ?: "c" (task[pid].thread.ip),"d" (task[pid].thread.sp)?? ?/* input c or d mean %ecx/%edx*/
?? ?);
首先esp跳轉到該進程的棧頂位置,將該進程ebp壓入棧(由于第一個進程ebp==esp),將該進程的ip壓入棧頂。然后將ret指令,可以修改eip的值,使得該進程獲得cpu的指令權限。再彈出ebp,恢復棧底的位置。
?
二、進程的切換
本次小的時間片輪轉的采用的是時鐘中斷的方法進行調度。在my_process的進程中,檢測中斷的標志,有的話,就進行進程切換。
進程切換分兩種情況,一種是正在運行的進程切換,另一種是沒有運行的進程切換
正在運行的進程切換
通過下面的一段嵌入式匯編實現切換,然后使下一個進程轉換成正在運行的狀態
asm volatile(?? ?
?????? ??? ?"pushl %%ebp\n\t" ?? ???? /* save ebp */
?????? ??? ?"movl %%esp,%0\n\t" ?? ?/* save esp */
?????? ??? ?"movl %2,%%esp\n\t"???? /* restore? esp */
?????? ??? ?"movl $1f,%1\n\t"?????? /* save eip */?? ?
?????? ??? ?"pushl %3\n\t"
?????? ??? ?"ret\n\t" ?? ???????????? /* restore? eip */
?????? ??? ?"1:\t"????????????????? /* next process start here */
?????? ??? ?"popl %%ebp\n\t"
?????? ??? ?: "=m" (prev->thread.sp),"=m" (prev->thread.ip)
?????? ??? ?: "m" (next->thread.sp),"m" (next->thread.ip)
?? ??? ?);
首先保存原來的ebp,esp,ip,通過將ebp壓棧,進程cpu狀態保存esp的值和ip的值。
接下來將esp跳轉到要切換的棧頂,將其ip值壓棧,然后ret指令使eip獲得其cpu指令權,最后將ebp等于原來進程ebp的值。即棧底不變。
沒有在cpu上運行的進程切換
首先轉換進程的狀態成正在運行,然后通過下面的一段嵌入式匯編實現切換
asm volatile(?? ?
?????? ??? ?"pushl %%ebp\n\t" ?? ???? /* save ebp */
?????? ??? ?"movl %%esp,%0\n\t" ?? ?/* save esp */
?????? ??? ?"movl %2,%%esp\n\t"???? /* restore? esp */
?????? ??? ?"movl %2,%%ebp\n\t"???? /* restore? ebp */
?????? ??? ?"movl $1f,%1\n\t"?????? /* save eip */?? ?
?????? ??? ?"pushl %3\n\t"
?????? ??? ?"ret\n\t" ?? ???????????? /* restore? eip */
?????? ??? ?: "=m" (prev->thread.sp),"=m" (prev->thread.ip)
?????? ??? ?: "m" (next->thread.sp),"m" (next->thread.ip)
?? ??? ?);??????
首先保存原來的ebp,esp,ip,通過將ebp壓棧,進程cpu狀態保存esp的值和ip的值。
接下來將esp跳轉到要切換的棧頂,ebp跳轉到要切換的棧底,由于進程沒有運行所以ebp=esp,將其ip值壓棧,然后ret指令使eip獲得其cpu指令權。
下面是內核編譯完成的圖片:
下面這張是進程在切換時的圖片
?
三、總結
操作系統首先進入初始化啟動內核,在啟動內核時先完成第一個0號進程,然后根據需要不斷創建進程。并根據一定的調度算法進行進程的切換。
轉載于:https://www.cnblogs.com/pingandezhufu/p/4356546.html
總結
以上是生活随笔為你收集整理的Linux内核分析--操作系统是如何工作的的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【转】如何一直保持测试工作的热情
- 下一篇: Swift与Objective-C AP