2017-2018-1 20179209《Linux內核原理與分析》第七週做業

一.實驗

1.1task_struct數據結構

Linux內核經過一個被稱爲進程描述符的task_struct結構體來管理進程,這個結構體包含了一個進程所需的全部信息。它定義在linux-3.18.6/include/linux/sched.h文件中。
這個結構體定義很是龐大,目測有300多行代碼,因此只摘錄了部分關鍵定義:linux

struct task_struct {
    volatile long state;    /* -1 unrunnable, 0 runnable, >0 stopped */
    void *stack;              /*進程堆棧*/
    atomic_t usage;        
    unsigned int flags;  /* per process flags, defined below */
    unsigned int ptrace;

        pid_t pid;
    pid_t tgid;

        struct task_struct __rcu *real_parent; /* real parent process */
    struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
    /*
     * children/sibling forms the list of my natural children
     */
    struct list_head children;  /* list of my children */
    struct list_head sibling;   /* linkage in my parent's children list */
}

用一張比較形象的圖表能夠說明進程描述符大致結構和其功能:
git

1.2分析sys_clone如何建立進程和修改task_struct

系統調用服務例程sys_clone, sys_fork, sys_vfork三者最終都是調用do_fork函數完成。這三者的區別詳細見——Linux中fork,vfork和clone詳解(區別與聯繫)。do_fork函數原型位於linux-3.18.6/kernel/fork.c。
單從do_fork這個函數的參數來看,建立一個新的進程須要傳入的參數有:clone_flags,從字面意思這個參數是克隆的父進程的狀態;stack_start,爲要建立進程的堆棧的起始位置,聯合下一個參數stack_size(堆棧大小)共同決定了該進程的堆棧區域;parent_tidptr和child_tidptr傳入的目的是將該進程置於系統進程鏈表。下面從實現角度分析各個部分的功能(右邊爲do_fork流程):
github

1.3使用gdb跟蹤分析fork調用內核函數sys_clone的過程

PS:繼上次做業,我發現一個問題——在實驗樓環境下使用gdb跟蹤MenuOS啓動後輸入命令後會出現死機,而後只能重複以前步驟從新來一遍操做。本實驗開始時有些頭疼,由於要想完成對fork命令的追蹤也必須在Qemu虛擬機中輸入命令,果真在最開始時仍是出現了一樣的問題。不得已我決定將3.18.6的內核下載到本身的虛擬機,結果出現了尷尬的現象,就是個人Ubuntu64位虛擬機能開啓,但倒是黑屏,上網查資料後於事無補,不少方法試了都沒用,因此一怒之下從磁盤中刪去了該虛擬機(我以前的linux全部程序都在該虛擬機上,從linux內核原理與分析課一開始就用的這個虛擬機,可想而知裏面有多少重要的東西)。若是我以前抓了快照恢復一下可能就行了,然而我重來沒有抓取過快照,即便出了問題也直接把虛擬機扔了從新建立一個。因此抓拍快照很重要!抓拍快照很重要!抓拍快照很重要。然而等我新建虛擬機時候發現引導界面也是黑屏,這時我預感到我可能犯了愚蠢的錯誤,等我打開其餘虛擬機,一樣是黑屏!!!馬上重啓實體機,好了,黑屏不存在了!數據恢復不了那個虛擬機,再怎麼說它也是一個系統。因此我白白給本身創造了一個巨大的問題!接着從新建一個Ubuntu,等到我一步步把內核下載好,編譯的時候又出現問題——個人Ubuntu是64位,實驗要求32位!強忍心裏的憤怒查資料下載了32位庫,然而問題並無解決(貌似它並無找見我下載的32位庫在哪,我也不知道在哪。。。)至此我再沒有耐心又回到了實驗樓!值得反思的一個事實是,不少時候在你跋山涉水經歷萬千磨難後最終發現你一開始要找的答案就在原點,然而一開始你殊不知道它就在腳下!我想,明白這個道理比我作這個實驗獲得的理論知識更有意義!原來在進入Qemu虛擬機後必須按Ctrl+Alt後才能再回到桌面環境,這句話就寫在:

解決「死機」問題後,仍舊選擇實驗樓環境:
基本命令以下:編程

cd LinuxKernel
rm menu -rf
git clone https://github.com/mengning/menu.git
cd menu
mv test_fork.c test.c        //在makefile中編譯命令用的是 test.c,這是更名的緣由!
cd ..
qemu -kernel linux3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
gdb linux3.18.6/vmlinux

驗證是否成功將fork添加:

在建立進程的關鍵函數上設置斷點:

起初沒解決PS中的難題時我是直接在內核啓動時就設置了上圖的斷點,得出以下結論:緩存

  • 內核啓動時建立過不少進程!
  • 儘管建立過不少進程,但不會調用ret_from_fork函數!



    從上面的圖中你們能夠看到,這時候MenuOS並無徹底啓動,我一樣追蹤到了do_forkdup_task_structcopy_processcopy_thread。下面的截圖是解決PS中「問題」後追蹤到的ret_from_fork

    數據結構

    1.4實驗總結

    本次實驗最爲關心的問題就是新的進程從哪開始執行?上面兩張圖足以說明這個問題。ret_from_fork中跳轉到syscall_exit後面的代碼雖然追蹤不到,但在它結束時,子進程建立完成。syscall_exit屬於系統調用中的一個環節,從上次實驗的結果來看,接下來的步驟還有syscall_exit_work!這也從側面證明上次實驗結果中的一個問題,那就是在work_pending中有一個判斷,是否發生進程調度!因此在syscall_exit的時候會發生進程調度,最起碼可能會建立一個新的進程!函數

二.課本11、十二章

2.1相對時間與絕對時間

若是某個事件在5s後被調度執行,那麼系統所須要的不是絕對時間,而是相對時間(好比,相對如今起5s後);相反,若是要求管理當前日期和當前時間,則內核不但要計算流逝的時間並且還要計算絕對時間。系統定時器以某種頻率自行觸發(常常被稱爲擊中或射中)時鐘中斷,該頻率能夠經過編程預約,稱做節拍率。當時鍾中斷髮生時,內核就經過一種特殊的中斷處理程序對其進行處理。atom

2.2jiffies

全局變量jiffies用來記錄系統啓動以來產生的節拍總數。啓動時,內核將該變量初始化爲0,此後,每次時鐘中斷處理程序就會增長該變量的值。jiffies的定義:
extern unsigned long volatile jiffiesextern u64 jiffies_64
jiffies迴繞是指當jiffies達到最大值時,它的值變回0從新開始。.net

2.3實時時鐘

實時時鐘是用來持久存放系統時間的設備,即便系統關閉後,它也能夠靠主板上的微型電池供電保持系統的計時。在PC體系結構中,RTC和CMOS集成在一塊兒,並且RTC的運行和BIOS的保存設置都是同一個電池供電。code

2.4延遲執行——schedule_timeout()

最理想的延遲執行方法是使用schedule_timeout()函數,該方法會讓須要延遲執行的任務睡眠到指定的延遲時間耗盡後再從新運行。當指定時間到期後,內核喚醒被延遲的任務並將其從新放回運行隊列,用法:set_current_state(TASK_INTERRUPTIBLE);schedule_timeout(s*HZ)

2.5slab

slab層(slab分配器)把不一樣的對象劃分爲告訴緩存組,其中每一個高速緩存組存放不一樣類型對象(這好像與普通的高速緩存有區別?)。每種對象類型對應一個高速緩存;高速緩存又被劃分爲slab。slab由一個或多個物理連續的頁組成。每一個高速緩存能夠由多個slab組成。slab描述符以下:

struct slab{
    struct list_head     list;            //滿、部分滿或空鏈表
    unsigned long       colouroff;  //slab着色的偏移量
    void                       *s_mem;  //在slab中的第一個對象
    undigned int          inuse;       //slab中已經分配的對象數
    keme_bufctl_t       free;         //第一個空閒對象
}

一個新的告訴緩存經過如下函數建立:
struct kmem_cache *kmem_cache_create(const char *name,size_t size,size_t align,unsigned long flags, woid(*ctor)(void *));。 讀完課本,我以爲slab就是cache的一種實現類型。

相關文章
相關標籤/搜索