1. 程式人生 > >linux核心程式設計讀書筆記【第三章程序管理】

linux核心程式設計讀書筆記【第三章程序管理】

第三章程序管理

應專業選修Linux程式設計老師的要求,記錄讀書筆記

3.1程序

1)程序:處於執行期的程式(目標碼存放在某種介質上),包含程式碼段還包含其他資源(開啟的檔案、核心內部資料、存放全域性變數的資料段),是正在執行的程式程式碼的實時結果,Linux通常叫程序也叫任務。

2)執行緒:擁有獨立的程式計數器、程序棧和一組程序暫存器。核心排程的是執行緒不是程序,對於 linux執行緒是一種特殊程序。

3)實際上,許多程序分享一個處理器,但是虛擬處理器為每個程序提供自己獨享的處理器。虛擬記憶體為每個程序提供獨享整個系統的記憶體資源

4)linux通過父程序呼叫fork()進行復制一個現有程序來建立一個全新程序——子程序。fork()函式實際上是由clone()系統呼叫實現的,exec()建立新的地址空間。fork()系統呼叫從核心返回兩次:一次回到父程序,另一次回到新產生的子程序。

3.2程序描述符及任務結構

1)程序的列表存放在任務佇列(雙向迴圈連結串列)中,連結串列的每一項都是型別為task_struct稱為程序描述符的結構,其包含一個具體程序的所有資訊(程序的地址空間,掛起的訊號,程序的狀態,還有其他更多的資訊)。

2)分配程序描述符。linux通過slab分配器分配task_struct結構(動態生成),task_struct存放在棧底或棧頂。每個任務的thread_info結構在它的核心棧的尾端分配,結構中的task域中存放的指向該任務實際task_struct的指標

3)程序描述符的存放。pid或者唯一的程序標識值來標識每個程序。核心把每個程序的pid存放在他們各自的程序描述符中。 4)程序狀態:系統中的每個程序都必然處於五種程序狀態中的一種。該域的值也比為:TASK_RUNNUNG(執行)、TASK_INTERRUPTIBLE(可中斷)、TASK_UNINTERRUPTIBLE(不可中斷)、_TASK_TRACED(被跟蹤)_TASK_STOPPED(停止)

5)設定當前程序狀態:set_task_state(task,state)函式將任務task的狀態設定為state

6)程序上下文:current巨集在程序上下文中使有效的,除非在此間隙有更高優先順序的程序需要執行並由排程器做出了相應調整,否則退出核心進入使用者態後會繼續執行

7)程序家族樹,程序之間存在明顯的繼承關係,都是PID為1的init程序的後代。任務佇列是雙向迴圈連結串列。獲取前一個程序的方法list_entry(task->tasks.prev,struct task_struct,tasks)獲取後一個程序的方法list_entry(task->tasks.prev,struct task_struct,tasks)依次訪問整個任務佇列for_each_process(task)

3.3程序建立

1)先用fork()拷貝當前程序建立子程序,exec()函式負責讀取可執行檔案並將其載入地址空間開始執行。

2)寫時拷貝:fork()拷貝程序的時候使用寫時拷貝頁實現,讓父程序和子程序共享同一個拷貝,不復制整個程序地址空間,使地址空間上的頁(資料)的拷貝推遲到實際發生寫入的時候才進行。

3)fork()呼叫clone(),clone()呼叫do_fork(),do_fork()完成建立中的大部分工作。

4)vfork()除了不拷貝父程序的頁表項外,功能與fork()相同

3.4執行緒在linux中的實現

1)把所有執行緒都當做程序來實現,被視為一個與其他程序共享某些資源的程序。耗時更少,資源消耗更少,執行更快

2)建立執行緒:與建立程序不同的是在呼叫clone()函式的時候需要傳遞一些引數標誌來指明需要共享的資源

3)核心執行緒:後臺執行的一些操作,獨立執行在核心空間的標準程序,沒有獨立的地址空間(指向地址空間mm指標被設定為NULL)。只在核心空間執行,可以被排程,可以被搶佔。ps -ef檢視核心執行緒,核心執行緒只能由其他核心執行緒建立(kthreadd核心程序)

3.5程序終結

1)do_exit()定義於kernel/exit.c:程序終結的大部分任務靠do_exit()。

2)do_exit()做的工作: a.將tast_struct中的標誌成員設定為PF_EXITING b.呼叫del_timer_sync()刪除任一核心定時器根據返回的結果判斷定時器處理程式是否在執行 c.若BSD程序的記賬功能是開啟的,do_exit()呼叫acct_uodate_integrals()來輸出記賬資訊 d.呼叫exit_mm()函式釋放程序呼叫的mm_struct,如果沒有別的程序使用它們(地址空間沒有被共享)就徹底釋放 e.呼叫sem_exit()函式,如果程序排隊等候IPC訊號,它則離開佇列 f.呼叫exit_files()和exit_fs(),以分別遞減檔案描述符、檔案系統資料的引用計數,如果引用計數為零則釋放 g.把存放在task_struct的exit_code成員中的退出程式碼置為由exit()提供的退出程式碼,退出程式碼放在這裡供父程序隨時檢索 h.呼叫exit_notify()向父程序傳送訊號,給子程序重新找養父,並把程序狀態設定為EXIT_ZOMBLE i.do_exit()呼叫schedule()切換到新的程序,處於EXIT_ZOMBLE狀態的程序不會在被排程,所以這是程序所執行的最後一段程式碼,do_exit()永不返回。

3)刪除程序描述符:呼叫do_exit()之後,執行緒僵死,但為了讓系統有辦法在程序終結後還能獲得他的資訊,程序描述符還保留,所以刪除程序描述符在程序終結之後。 a.wait()這一族函式唯一的系統呼叫wait4()來實現呼叫它的程序,知道其中的一個子程序退出 b.釋放程序描述符是,release_task()會被呼叫: c.他呼叫_exit_signal(),該函式呼叫_unhash_process(),後者又呼叫detach_pid()從pidhash上刪除該程序,同時從任務列表刪除該程序 d._exit_signal()釋放目前釋放僵死程序所使用的所有剩餘資源,並進行最終統計和記錄 e.若果這個程序是執行緒組最後一個程序,並且領頭程序已經死掉,那麼release_task()就要通知僵死的領頭程序的父程序 f.release_task()呼叫put_task_struct()釋放程序核心棧和thread_info結構所佔的頁,並釋放task_struct所佔的slab快取記憶體

4)程序描述符和所有程序獨享資源全部被釋放了

5)父程序在子程序之前退出,子程序會變成孤兒,永遠處於僵死狀態:給子程序在當前程序組找一個執行緒作為父親,或者讓init做他們的父程序。