1. 程式人生 > >深入理解linux核心讀書筆記(第三章)

深入理解linux核心讀書筆記(第三章)

1.  程序是程式執行時的一個例項。

2. 從核心的角度看,程序是系統進行資源分配的實體。

3. linux 通過輕量級程序來支援多執行緒應用,每一個輕量級程序對應一個執行緒。

   執行緒之間共享地址空間,開啟的檔案等資源,核心對每一個輕量級程序進行單獨排程。

4. 一個執行緒組包含了一組執行緒用來實現多執行緒應用,對於getpid,kill, _exit等系統呼叫,執行緒組作為一個整體。

5. 核心通過task_struct 結構體來儲存程序的資訊。

6. 程序的狀態 task_struct->state

  (1) TASK_RUNNING, 正在cpu上執行或者等待被執行。

  (2) TASK_INTERRUPTTBLE,程序正在被掛起直到滿足一定條件後被喚醒。喚醒條件包括中斷,傳送訊號,或者等待的條件得到滿足。

  (3) TASK_UNINTERRUPTTBLE, 和(2)類似,但是不能被訊號喚醒。

  (4) TASK_STOPPED, 程序執行暫停。

  (5) TASK_TRACED, 程序被偵錯程式暫停

7. 程序的退出狀態 task_struct->exit_state

   (1)  EXIT_ZOMBIE, 程序執行已經結束,但是父程序還沒有呼叫wait4或者waitpid之類的系統呼叫來獲取該程序的資訊。

 (2)EXIT_DEAD, 程序的最後狀態,程序正在被系統移除,將程序退出狀態從EXIT_ZOMBIE改為EXIT_DEAD可以防止其他的程序對該程序呼叫wait系列的函式。

8.  核心提供了set_task_state 和set_current_state巨集來對程序的狀態進行賦值,並且保證賦值的操作被正確執行(不會與其他操作亂序)。

9. 每個可以被單獨排程的執行實體都有task_struct 結構體,大部分對程序的引用都是通過task_struct  的指標來完成。

10.  執行緒組共有的id是第一個執行緒的pid,儲存在tgid中,getpid返回tgid而不是pid。

11. 程序的thread_info 和 核心棧共同佔有兩個頁面,也可以配置佔有一個頁面,其中,thread_info位於低地址處,核心棧底位於地址頂端。

12. 兩個list增加的操作:

  (1) list_add(n, p), 將n節點新增到p節點之後。

  (2) list_add_tail(n, p), 將n節點新增到p節點之前。

13. 當只有一個孩子程序時,children.prev 和 children.next都指向那個孩子程序; 第一個孩子的sibling.prev指向parent,最後一個孩子的sibling.next也指向parent。

14.  程序狀態為TASK_STOPPED, TASK_ZOMBIE和TASK_DEAD的程序沒有用連結串列連線,因為這些程序只能通過pid或者特定的父程序來訪問; 

       程序狀態為TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE的程序根據等待事件細分為好多種,因此引入了等待佇列。

15. __wait_queue結構體中,flags為1的話,表示是獨佔程序,核心有選擇地喚醒程序; 為0的話是非獨佔程序,核心無條件喚醒。

16. 所有非獨佔程序位於等待佇列的前面,而獨佔程序位於等待佇列的後面,每次特定條件滿足後,喚醒所有的非獨佔程序和一個獨佔程序。

17.  每個程序的資源配額儲存在signal_struct 的rlim陣列中,包括當前的使用量和最大使用量。子程序繼承父程序的配額。

18.  在程序恢復執行之前必須要載入cpu暫存器的資料被稱為硬體上下文,他是程序上下文的一個子集。

19. linux中,一部分硬體上下文儲存在task_struct中,剩下的儲存在核心棧中。

20. linux 2.6使用軟體來進行程序切換,和x86提供的硬體切換相比,速度差不多,但是有更多的優化空間。

21. 程序切換髮生在核心空間。當發生切換時,使用者態的暫存器內容已經被儲存在核心棧中,包括esp,和ss。

22. 儘管linux不使用硬體來切換程序,但是還是要求為每個cpu設定一個TSS段來儲存硬體上下文。

23. 當程序從使用者態切換到核心態時,從TSS中取得核心棧的地址。另外,當用戶程序訪問IO埠時,需要去檢查TSS中的IO點陣圖。通過tr暫存器來訪問tss。

24.  task_struct 中的thread_struct 儲存了除通用暫存器的大部分暫存器,通用暫存器儲存在核心棧中。

25. 每個程序切換包含兩步:

 (1)切換pgd,裝入新的程序地址空間。

  (2) 切換核心棧和硬體上下文。

26. 程序切換的第2步主要是由switch_to 巨集來完成。switch_to的第三個last引數是一個輸出引數,用來指向切換前的程序描述符。

27.  thread_struct 中的esp0用來指向核心棧底(核心棧空), esp指向程序切換時的核心棧地址。(詳見copy_thread)

28.  linux 中,傳統的fork 系統呼叫是通過 clone來實現的,flags(低位元組)只包含SIGCHLD。

29. vfork中,包含的flags有SIGCHLD,CLONE_VM和CLONE_VFORK,child_stack和父程序相同。

30. clone, fork 和 vfork系統呼叫都是經過do_fork來處理。

31. 核心執行緒只執行在核心態,只使用大於PAGE_OFFSET的地址空間。

32.  kernel_thread用來新建一個核心執行緒, 相當於呼叫do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0,  NULL, NULL)。

33.  0程序(又叫idle程序, swapper程序), 是在核心初始化過程中建立的核心執行緒。程序描述符儲存在init_task中。

34. start_kernel函式會建立另外一個核心執行緒,1程序,又叫init程序。該核心執行緒會呼叫init_post去執行使用者的init程序。

35. release_task用來釋放zombie程序的最後一個數據結構。