張嘉琪 原創做品轉載請註明出處 《Linux內核分析》MOOC課程http://mooc.study.163.com/course/USTC-1000029000算法
中斷處理過程(包括時鐘中斷、I/O中斷、系統調用和異常)中,直接調用schedule(),或者返回用戶態時根據need_resched標記調用schedule();架構
內核線程能夠直接調用schedule()進行進程切換,也能夠在中斷處理過程當中進行調度,也就是說內核線程做爲一類的特殊的進程能夠主動調度,也能夠被動調度;函數
用戶態進程沒法實現主動調度,僅能經過陷入內核態後的某個時機點進行調度,即在中斷處理過程當中進行調度。post
爲了控制進程的執行,內核必須有能力掛起正在CPU上執行的進程,並恢復之前掛起的某個進程的執行,這叫作進程切換、任務切換、上下文切換; 掛起正在CPU上執行的進程,與中斷時保存現場是不一樣的,中斷先後是在同一個進程上下文中,只是由用戶態轉向內核態執行;操作系統
進程上下文包含了進程執行須要的全部信息線程
用戶地址空間:包括程序代碼,數據,用戶堆棧等rest
控制信息:進程描述符,內核堆棧等blog
硬件上下文(注意中斷也要保存硬件上下文只是保存的方法不一樣)進程
schedule()函數選擇一個新的進程來運行,並調用contextswitch進行上下文的切換,這個宏調用switchto來進行關鍵上下文切換ip
next = picknexttask(rq, prev);//進程調度算法都封裝這個函數內部
context_switch(rq, prev, next);//進程上下文切換
switch_to利用了prev和next兩個參數:prev指向當前進程,next指向被調度的進程
最通常的狀況:正在運行的用戶態進程X切換到運行用戶態進程Y的過程
經過中斷處理過程當中的調度時機,用戶態進程與內核線程之間互相切換和內核線程之間互相切換,與最通常的狀況很是相似,只是內核線程運行過程當中發生中斷沒有進程用戶態和內核態的轉換;
內核線程主動調用schedule(),只有進程上下文的切換,沒有發生中斷上下文的切換,與最通常的狀況略簡略;
建立子進程的系統調用在子進程中的執行起點及返回用戶態,如fork; 加載一個新的可執行程序後返回到用戶態的狀況,如execve;
理解Linux系統中進程調度的時機,能夠在內核代碼中搜索schedule()函數,看都是哪裏調用了schedule()
使用gdb跟蹤分析一個schedule()函數 ,驗證您對Linux系統進程調度與進程切換過程的理解;推薦在實驗樓Linux虛擬機環境下完成實驗。 特別關注並仔細分析switch_to中的彙編代碼,理解進程上下文的切換機制,以及與中斷上下文切換的關係;
博客內容中須要仔細分析進程的調度時機、switch_to及對應的堆棧狀態等。
1.打開qemu和gdb
2.設置斷點
3.用list查看代碼
4.單步執行發現__schedule()
5.進入函數
6.繼續單步執行直到發現pick_nexi_task()
7.在pick_next_task處設立斷點,執行
8.在context_switch處設立斷點,執行
對「Linux系統通常執行過程」的理解
Linux內核中實現進程的切換主要經過保存進程相關的信息實現,這裏須要注意進程切換中內核級進程的切換和用戶態進程切換的不一樣。內核態能夠直接調用schedule函數並不須要陷入中斷這個過程。而用戶態則須要陷入內核態才能實現進程的切換。從switch_to這個函數當中也能夠驗證咱們進程切換時會保存相關信息的推斷。