1. 程式人生 > >20179223《Linux內核原理與分析》第九周學習筆記

20179223《Linux內核原理與分析》第九周學習筆記

3.18 用戶 通過 linux內核 良好的 數據 context from inux

視頻學習

進程調度與進程調度的時機分析

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

第一種分類:
——I/O-bound:1.頻繁的進行I/O;2.通常會花費很多時間等待I/O操作的完成
——CPU-bound:1.計算密集型;2.需要大量的CPU時間進行計算

第二種分類:
——批處理進程:1.不必與用戶交互,通常在後臺運行;2.不必很快響應;3.典型的批處理程序:編譯程序、科學計算
——實時進程:1.有實時需求,不應被低優先級的進程阻塞;2.響應時間要短、要穩定;3.典型的實時進程:視頻/音頻、機械控制等
——交互式進程:1.需要經常與用戶交互,因此要花很多時間等待用戶輸入操作;2.響應時間要快,平均延遲要低於50~150ms;3.典型的交互式程序:shell、文本編輯程序、圖形應用程序等

Linux既支持普通的分時進程,也支持實時進程。

Linux中的調度是多種調度策略和調度算法的混合。

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

Linux的調度基於分時和優先級
--隨著版本的變化,分時技術在不斷變化

Linux的進程根據優先級排隊
——根據特定的算法計算出進程的優先級,用一個值表示
——這個值表示把進程如何適當的分配給CPU

Linux中進程的優先級是動態的
——調度程序會根據進程的行為周期性的調整進程的優先級:1.較長時間未分配到CPU的進程,通常↑;2.已經在CPU上運行了較長時間的進程,通常↓。

schedule函數
schedule函數實現調度
目的:在運行隊列中找到一個進程,把CPU分配給它
調用方法:1.直接調用schedule();2.松散調用,根據need_resched標記

進度調度時機
1.中斷處理過程(包括時鐘中斷、I/O中斷、系統調用和異常)中,直接調用schedule(),或者返回用戶態時根據need_resched標記調用schedule()
2.內核線程可以直接調用schedule()進行進程切換,也可以在中斷處理過程中進行調度,也就是說內核線程作為一類的特殊的進程可以主動調度,也可以被動調度
3.用戶態進程無法實現主動調度,僅能通過陷入內核態後的某個時機點進行調度,即在中斷處理過程中進行調度

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

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

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

——進程上下文包含了進程執行需要的所有信息
1.用戶地址空間:包括程序代碼,數據,用戶堆棧等
2.控制信息:進程描述符,內核堆棧等
3.硬件上下文(註意中斷也要保存硬件上下文只是保存的方法不同)

——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指向被調度的進程

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.通過中斷處理過程中的調度時機,用戶態進程與內核線程之間互相切換和內核線程之間互相切換,與最一般的情況非常相似,只是內核線程運行過程中發生中斷沒有進程用戶態和內核態的轉換
2.內核線程主動調用schedule(),只有進程上下文的切換,沒有發生中斷上下文的切換,與最一般的情況略簡略
3.創建子進程的系統調用在子進程中的執行起點及返回用戶態,如fork
4.加載一個進的可執行程序後返回到用戶態的情況,如execve

內核與舞女

內核是各種中斷處理過程和內核線程的集合

Linux操作系統架構概覽

任何計算機系統都包含一個基本的程序集合,稱為操作系統。
——內核(進程管理,進程調度,進程間通訊機制,內存管理,中斷異常處理,文件系統,I/O系統,網絡部分)
——其他程序(例如函數庫、shell程序、系統程序等等)

操作系統的目的
——與硬件交互,管理所有的硬件資源
——與用戶程序(應用程序)提供一個良好的執行環境

實驗

$ cd LinuxKernel
$ rm -rf menu
$ git clone http://github.com/mengning/menu.git
$ cd menu

修改menu目錄下的test.c文件,把上節課自己寫的系統調用代碼加進去,做成兩個菜單命令,跟之前的實驗一樣
然後make rootfs進行編譯
技術分享圖片

使用qumu命令重新啟動內核並使用-s和-S參數“凍結”系統執行,命令如下:

$ qemu -kernel ..//linux-3.18.6/arch/x86/boot/bzImage -initrd ..//rootfs.img -s -S

此時為了使用gdb進行調試,需要水平分割一個窗口,輸入如下命令:

 gdb
 file ..//linux-3.18.6/vmlinux
 target remote:1234

使用gdb跟蹤schedule()函數,設置斷點
技術分享圖片
技術分享圖片
繼續執行,如圖所示
技術分享圖片
找下個運行的進程
技術分享圖片
schedule()函數內部判斷是否需要進行上下文切換的語句。context_switch()進程上下文切換。
技術分享圖片

課本第15、16章學習

進程地址空間

進程地址空間是指用戶空間中進程的內存,是每個用戶空間進程所看到的內存。Linux采用虛擬內存技術,進程之間以虛擬的方式共享內存,每個進程好像都可以訪問整個系統的所有物理內存。
進程地址空間由進程可尋址的虛擬內存組成。可以被訪問的合法地址空間稱為內存區域,進程只能訪問有效內存區域內的內存地址。訪問了不在有效範圍內的內存區域或者以不正確的方式訪問了有效地址的進程會被內存終止,並返回“段錯誤”信息。

內存區域包含各種內存對象:

代碼段,即可執行文件代碼的內存映射。
數據段,即可執行文件的已初始化全局變量的內存映射。
包含未初始化全局變量即bss段的零頁的內存映射。
用於進程用戶空間棧的零頁的內存映射。
每一個諸如C庫或動態鏈接程序等共享庫的代碼段、數據段和bss段也會被載入進程的地址空間。
任何內存映射文件。
任何共享內存段。
任何匿名的內存映射,如malloc分配的內存。

頁高速緩存和頁回寫

寫緩存有三種策略:

1.不緩存,高速緩存不緩存任何寫操作,跳過緩存寫到磁盤上,同時使緩存中數據失效。
2.寫透緩存,自動更新內存緩存,同時也更新磁盤文件。
3.“回寫”,寫操作直接寫到緩存中,後端存儲不會立刻直接更新,將頁高速緩存中被寫入的頁面標記成“臟”,由回寫進程將臟頁寫回磁盤。(Flusher內核線程負責)

20179223《Linux內核原理與分析》第九周學習筆記