Linux進(jìn)程基礎(chǔ)行為(一)

1.進(jìn)程組織結(jié)構(gòu)

1. task_struct ,thread_info 和內(nèi)核棧

image.png
image.png

在內(nèi)核中通常current宏獲取當(dāng)前正在運(yùn)行的task_struct可都。對于不同的硬件體系current的實(shí)現(xiàn)方式不一樣导俘,寄存器較多的體系直接用一個寄存器來存儲當(dāng)前進(jìn)程的task_struct的指針秘蛔,X86 current把內(nèi)核棧棧頂指針最后13位(內(nèi)核棧8KB)清零,計算出thread_info的位置勋陪,通過thread_info總task指針指向當(dāng)前進(jìn)程的task_truct

2. 進(jìn)程狀態(tài)

image.png

3. 進(jìn)程樹

進(jìn)程樹的樹根是0號進(jìn)程idle,是所有進(jìn)程的祖先。

  1. 0號進(jìn)程創(chuàng)建1號進(jìn)程(創(chuàng)建時是內(nèi)核線程)着饥,1號進(jìn)程負(fù)責(zé)內(nèi)核部分的初始化工作及系統(tǒng)配置,創(chuàng)建用于高速緩存和虛擬內(nèi)存管理的內(nèi)核線程
  2. 1號進(jìn)程調(diào)用execve()運(yùn)行磁盤上的init可執(zhí)行程序惰赋,并演變?yōu)橛脩魬B(tài)1號進(jìn)程宰掉,init進(jìn)程
  3. init進(jìn)程按照配置文件/etc/initab的要求,完成系統(tǒng)啟動工作赁濒,創(chuàng)建編號為1號轨奄,2號,……的Getty進(jìn)程(初始化終端)
  4. getty進(jìn)程監(jiān)控到終端連接信號時拒炎,通過調(diào)用execve()執(zhí)行l(wèi)ogin登錄程序
  5. 如果登錄成功過挪拟,login程序通過execve()函數(shù)調(diào)用shell
  6. Shell進(jìn)程接收getty進(jìn)程的pid,取代原來的getty進(jìn)程击你。

1. 0號進(jìn)程idle

  1. idle進(jìn)程只能從靜態(tài)地填寫thread_info和task_struct
  2. idle進(jìn)程讓CPU陷入空閑循環(huán)舞丛,空閑運(yùn)行
  3. 多處理器上剛啟動只有一個CPU能運(yùn)行,只有CPU0上的idle進(jìn)程完成初始化后才激活其他CPU果漾,并通過copy_process()創(chuàng)建其他CPU的idle進(jìn)程

3. 進(jìn)程創(chuàng)建與撤銷

在Linux系統(tǒng)中球切,系統(tǒng)通過fork()函數(shù)復(fù)制一個現(xiàn)有的進(jìn)程創(chuàng)建一個新進(jìn)程。
接著绒障,調(diào)用exec()函數(shù)創(chuàng)建新進(jìn)程的地址空間吨凑,并把新程序載入其中。
最終户辱,程序通過調(diào)用exit()系統(tǒng)調(diào)用退出運(yùn)行鸵钝。
進(jìn)程退出后被設(shè)置為僵死狀態(tài),直到父進(jìn)程檢查之后調(diào)用wait()在刪除進(jìn)程描述符資源

1. 進(jìn)程創(chuàng)建

1. fork 庐镐,vfork, clone

fork: 寫時復(fù)制恩商,賦值父進(jìn)程的task_struct,thread_info和內(nèi)核棧必逆,mm_struct怠堪,頁表
vfork: 沒有創(chuàng)建父進(jìn)程的數(shù)據(jù)副本,子進(jìn)程與父進(jìn)程共享數(shù)據(jù)名眉。子進(jìn)程創(chuàng)建之后粟矿,子進(jìn)程立即調(diào)用execve()加載新的進(jìn)程映象,或者與父進(jìn)程共享進(jìn)程映象损拢。在子進(jìn)程退出之前陌粹,父進(jìn)程處于阻塞狀態(tài)。
clone: fork,vfork福压,__clone庫函數(shù)都是通過不同的參數(shù)調(diào)用clone()函數(shù)掏秩,來實(shí)現(xiàn)進(jìn)程的創(chuàng)建的或舞。

clone()-->do_fork()(1. copy_process() 2. wake_up_task() 3. 如果是vfork調(diào)用的,則使用wait_for_vfork_done() 等待子進(jìn)程結(jié)束或調(diào)用execve())
copy_process()
(1)復(fù)制父進(jìn)程的內(nèi)核棧蒙幻,thread_info映凳,task_struct
(2)檢查創(chuàng)建該子進(jìn)程后,沒有超出系統(tǒng)的資源限制
(3)著手將子進(jìn)程和父進(jìn)程區(qū)分開來杆煞,子進(jìn)程一些統(tǒng)計信息清空
(4)將子進(jìn)程的狀態(tài)標(biāo)志設(shè)置為TASK_UNINTERRUPTIBLE,保證子進(jìn)程不會運(yùn)行
(5)更新子進(jìn)程flag,例如設(shè)置子進(jìn)程沒有被exec調(diào)用的標(biāo)志魏宽,超級用戶權(quán)限標(biāo)志清零
(6)根據(jù)傳遞進(jìn)clone的參數(shù)腐泻,子進(jìn)程拷貝或共享父進(jìn)程地址空間决乎,打開的文件,文件系統(tǒng)信息等
(7)返回一個指向子進(jìn)程的指針
wake_up_task()
將子進(jìn)程添加到調(diào)度隊列上等待調(diào)度獲取CPU獲取執(zhí)行派桩。

創(chuàng)建線程:

image.png

線程的用戶態(tài)堆棧构诚,task_struct,內(nèi)核棧和thread_info是私有的

創(chuàng)建進(jìn)程和寫時復(fù)制:


image.png

2. execve()系統(tǒng)調(diào)用

前面進(jìn)程只是創(chuàng)建了一個與父進(jìn)程大體一致的子進(jìn)程(僅僅是資源共享上的區(qū)別)铆惑。execve使用指定可執(zhí)行文件替換現(xiàn)有進(jìn)程上的進(jìn)程印象范嘱。
舉一個例子:在Shell中運(yùn)行一個二進(jìn)制程序。
(1)Shell進(jìn)程將參數(shù) 運(yùn)行時環(huán)境添加到自己的用戶態(tài)堆棧中
(2)Shell使用fork()創(chuàng)建一個子進(jìn)程员魏,放到CPU調(diào)度隊列上丑蛤。
(3)子進(jìn)程執(zhí)行execve()使用二進(jìn)制程序替換原來的Shell映象并將EIP指向新程序的入口開始執(zhí)行。
execve():
(1)execve()--》sys_execve()--》do_execve()——》do_execve_common()
(2)do_execve_common()執(zhí)行:
(1) unshared_files()為新進(jìn)程復(fù)制一份打開的文件表
(2) kazlloc()分配一個可執(zhí)行文件的結(jié)構(gòu)體linux_binprm撕阎,將可執(zhí)行文件運(yùn)行時所要用的參數(shù)受裹,運(yùn)行時環(huán)境等信息添加到linux_binprm。
(3)open_exec() 打開可執(zhí)行文件虏束。具體參考文件系統(tǒng)
(4) 找到負(fù)載最小的CPU棉饶。
(5)填寫linux_binprm實(shí)例,創(chuàng)建進(jìn)程映象镇匀,將參數(shù)傳入新進(jìn)程的用戶態(tài)堆棧照藻。
(6)執(zhí)行新程序,使用過load_elf_binary()執(zhí)行處理ELF的函數(shù)汗侵。
(7)如果該程序是靜態(tài)鏈接的幸缕,則load_elf_binary()直接返回新程序的入口地址,并調(diào)用start_thread()將EIP的值置為新程序的入口地址晰韵。

2.進(jìn)程撤銷

進(jìn)程要終結(jié)的時候會調(diào)用exit()函數(shù)冀值,最終通過調(diào)用do_exit()這個函數(shù)來結(jié)束進(jìn)程的。
(1)簡單的說宫屠,就是將各個引用計數(shù)器減一列疗,若有計數(shù)器歸0,則釋放相應(yīng)的內(nèi)存浪蹂。
(2)然后調(diào)用exit_notify()告知父進(jìn)程為子進(jìn)程找養(yǎng)父抵栈,并把進(jìn)程狀態(tài)設(shè)置為EXIT_ZOMBIE.最后調(diào)用schedule()切換到其他進(jìn)程告材。
(3)自此該進(jìn)程不會被再次調(diào)用。此時該進(jìn)程占用的內(nèi)存僅為內(nèi)存棧古劲,thread_info和task_struct斥赋。
(4)當(dāng)父進(jìn)程調(diào)用wait或waitpid檢測到僵尸進(jìn)程提供的信息之后,將進(jìn)程所持有的剩余內(nèi)存釋放产艾。至此進(jìn)程終結(jié)疤剑。wait掛起當(dāng)前進(jìn)程知道一個子進(jìn)程退出。

1.孤兒進(jìn)程闷堡,僵尸進(jìn)程

孤兒進(jìn)程: 一個父進(jìn)程退出隘膘,而它的一個或多個子進(jìn)程還在運(yùn)行,那么那些子進(jìn)程將成為孤兒進(jìn)程杠览。孤兒進(jìn)程將被init進(jìn)程(進(jìn)程號為1)所收養(yǎng)弯菊,并由init進(jìn)程對它們完成狀態(tài)收集工作。

僵尸進(jìn)程: 一個進(jìn)程使用fork創(chuàng)建子進(jìn)程踱阿,如果子進(jìn)程退出管钳,而父進(jìn)程并沒有調(diào)用wait或waitpid獲取子進(jìn)程的狀態(tài)信息,那么子進(jìn)程的進(jìn)程描述符仍然保存在系統(tǒng)中软舌。這種進(jìn)程稱之為僵死進(jìn)程才漆。如果進(jìn)程不調(diào)用wait / waitpid的話, 那么保留的那段信息就不會釋放佛点,其進(jìn)程號就會一直被占用醇滥,但是系統(tǒng)所能使用的進(jìn)程號是有限的,如果大量的產(chǎn)生僵死進(jìn)程恋脚,將因?yàn)闆]有可用的進(jìn)程號而導(dǎo)致系統(tǒng)不能產(chǎn)生新的進(jìn)程. 此即為僵尸進(jìn)程的危害腺办,應(yīng)當(dāng)避免。

4. 進(jìn)程切換

進(jìn)程切換主要包括:1.當(dāng)前進(jìn)程信息壓入內(nèi)核棧 2. 切換CPU頁表寄存器 3.切入進(jìn)程工作現(xiàn)場恢復(fù)
進(jìn)程切換是通過schedule()函數(shù)完成的糟描。schedule中最核心的就是switch_mm()切換進(jìn)程映象,內(nèi)核堆棧和硬件上下文的切換switch_to()

1. 頁表切換

switch_mm() load_cr3(next->pgd)

image.png

2.內(nèi)核堆棧切換

每個進(jìn)程的內(nèi)核空間都是一樣的怀喉,因此,盡管在switch_mm()中切換了頁表但是對switch_to沒有影響船响,所以說switch_to是平滑的躬拢。

image.png

switch_to(pre,next,last)
pre:當(dāng)前進(jìn)程 next:下一個進(jìn)程 last:上一個進(jìn)程
(a)頁表切換后內(nèi)核空間分布狀況
(b)將當(dāng)前進(jìn)程的內(nèi)核棧棧底和進(jìn)程狀態(tài)信息保存在內(nèi)核棧中。
(c)將當(dāng)前進(jìn)程的棧頂ESP保存在prev->thread.sp中见间,將ESP = next->thread.sp聊闯,此時完成了內(nèi)核切換,同時current宏根據(jù)P1的ESP找到P1的thread_info米诉,進(jìn)而找到task_struct菱蔬。此時,內(nèi)核狀態(tài)為(d)
(e)將P0的EIP保存到pre->thread.ip 此時狀態(tài)為(f)
(g)執(zhí)行__switch_to()完成一些浮點(diǎn)部件現(xiàn)場保留和恢復(fù)
(i)EIP=next->thread.ip,繼續(xù)執(zhí)行P1上次schedule()被打斷的指令拴泌,在通過系統(tǒng)調(diào)用返回返回到用戶空間執(zhí)行代碼魏身。其中,內(nèi)核態(tài)和用戶態(tài)切換是通過任務(wù)狀態(tài)段TSS蚪腐,來獲取內(nèi)核或用戶態(tài)的堆棧地址的箭昵。

5. 進(jìn)程調(diào)度

1. 基本框架

實(shí)時任務(wù)調(diào)度算法:FIFO和RR。普通任務(wù)完全公平調(diào)度算法

image.png

四個調(diào)度類優(yōu)先級:stop_sched_class回季,rt_sched_class, fair_sched_class,idle_sched_class家制,NUll
運(yùn)行隊列:

image.png
image.png

put_prev_task():通知當(dāng)前進(jìn)程準(zhǔn)備調(diào)出
pick_next_task()選擇要調(diào)入的進(jìn)程

2. CFS

CFS為每一個進(jìn)程設(shè)置一個虛擬時間,調(diào)度時總是選擇虛擬時間推進(jìn)緩慢的進(jìn)程先運(yùn)行泡一。優(yōu)先級越高颤殴,虛擬時間推進(jìn)越慢,所占用CPU時間就越高瘾杭。
虛擬時間推進(jìn):

image.png

內(nèi)核中并不直接使用進(jìn)程的優(yōu)先級數(shù)據(jù)值诅病,而是將優(yōu)先級轉(zhuǎn)換為權(quán)重計算虛擬時間的推進(jìn)哪亿。任務(wù)的nice值每降低1粥烁,則多獲得10%的CPU時間。

挑選下一個任務(wù):普通任務(wù)的運(yùn)行隊列的結(jié)構(gòu)是紅黑樹蝇棉。每次挑選紅黑樹最左側(cè)的葉子節(jié)點(diǎn)讨阻,將葉子節(jié)點(diǎn)緩存起來,每次挑選時篡殷,只要從這個緩存區(qū)取出該進(jìn)程就行钝吮,如果該緩存區(qū)為空,則調(diào)用idle進(jìn)程板辽。

調(diào)度延遲:CFS為無線小調(diào)度周期設(shè)置了一個“目標(biāo)延遲”默認(rèn)是20ms奇瘦,即保證每個可運(yùn)行的進(jìn)程都應(yīng)該至少運(yùn)行一次的某個時間間隔.。越小的周期帶來越好的交互性劲弦,同時也接近完美耳标。如果揮動進(jìn)程的數(shù)目超過該上限, 則延遲周期也成比例的線性擴(kuò)展.。周期長度是
__sched_period = sysctl_sched_latency * nr_running / sched_nr_latency

3.實(shí)時策略

FIFO:不適用時間片邑跪,可以一直運(yùn)行下去次坡,除非有更高優(yōu)先級的任務(wù)搶占
RR:是帶有時間片的FIFO,只能在同一優(yōu)先級的任務(wù)中輪詢画畅。

6 其他

1 進(jìn)程和線程區(qū)別

  1. 進(jìn)程是資源分配的基本單位砸琅,線程是調(diào)度的基本單位。
  2. 實(shí)體間(進(jìn)程間轴踱,線程間症脂,進(jìn)線程間)通信方式的不同
    進(jìn)程:A.共享內(nèi)存 B.消息隊列 C.信號量 D.有名管道 E.無名管道 F.信號 G.文件 H.socket
    線程: 線程間的通信方式上述進(jìn)程間的方式都可沿用,且還有自己獨(dú)特的幾種:A.互斥量 B.自旋鎖 C.條件變量 D.讀寫鎖 E.線程信號 G.全局變量
  3. 進(jìn)程有父子關(guān)系,線程只有一個父線程诱篷,其他都為子線程

多線程的優(yōu)勢:

  1. 理由之一是和進(jìn)程相比沸版,它是一種非常"節(jié)儉"的多任務(wù)操作方式。我們知道兴蒸,在Linux系統(tǒng)下视粮,啟動一個新的進(jìn)程必須分配給它獨(dú)立的地址空間,建立眾多的數(shù)據(jù)表來維護(hù)它的代碼段橙凳、堆棧段和數(shù)據(jù)段蕾殴,這是一種"昂貴"的多任務(wù)工作方式。而運(yùn)行于一個進(jìn)程中的多個線程岛啸,它們彼此之間使用相同的地址空間钓觉,共享大部分?jǐn)?shù)據(jù),啟動一個線程所花費(fèi)的空間遠(yuǎn)遠(yuǎn)小于啟動一個進(jìn)程所花費(fèi)的空間坚踩,而且荡灾,線程間彼此切換所需的時間也遠(yuǎn)遠(yuǎn)小于進(jìn)程間切換所需要的時間。
  2. 理由之二是線程間方便的通信機(jī)制瞬铸。對不同進(jìn)程來說批幌,它們具有獨(dú)立的數(shù)據(jù)空間,要進(jìn)行數(shù)據(jù)的傳遞只能通過通信的方式進(jìn)行嗓节,這種方式不僅費(fèi)時荧缘,而且很不方便。線程則不然拦宣,由于同一進(jìn)程下的線程之間共享數(shù)據(jù)空間截粗,所以一個線程的數(shù)據(jù)可以直接為其它線程所用,這不僅快捷鸵隧,而且方便绸罗。
  3. 提高應(yīng)用程序響應(yīng)。這對圖形界面的程序尤其有意義豆瘫,當(dāng)一個操作耗時很長時珊蟀,整個系統(tǒng)都會等待這個操作,此時程序不會響應(yīng)鍵盤靡羡、鼠標(biāo)系洛、菜單的操作,而使用多線程技術(shù)略步,將耗時長的操作(time consuming)置于一個新的線程描扯,可以避免這種尷尬的情況。
  4. 使多CPU系統(tǒng)更加有效趟薄。操作系統(tǒng)會保證當(dāng)線程數(shù)不大于CPU數(shù)目時绽诚,不同的線程運(yùn)行于不同的CPU上。
  5. 改善程序結(jié)構(gòu)。一個既長又復(fù)雜的進(jìn)程可以考慮分為多個線程恩够,成為幾個獨(dú)立或半獨(dú)立的運(yùn)行部分卒落,這樣的程序會利于理解和修改。

2 用戶線程 內(nèi)核線程

兩種類型的內(nèi)核線程:
線程按周期性間隔運(yùn)行蜂桶,檢測特定資源的使用儡毕,在用量超出或者低于預(yù)置的限制時采取行動
在線程啟動后則一直等待,直到內(nèi)核線程請求執(zhí)行某一特定的操作扑媚。
不同之處在于:
內(nèi)核線程只工作在內(nèi)核態(tài)中腰湾;而用戶線程則既可以運(yùn)行在內(nèi)核態(tài)(執(zhí)行系統(tǒng)調(diào)用時),也可以運(yùn)行在用戶態(tài)疆股;
內(nèi)核線程沒有用戶空間费坊,所以對于一個內(nèi)核線程來說,它的0 ~ 3G的內(nèi)存空間是空白的旬痹,它的current->mm是空的附井,與內(nèi)核使用同一張頁表;而用戶線程則可以看到完整的0~4G內(nèi)存空間两残。

3.進(jìn)程狀態(tài)

image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末永毅,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子磕昼,更是在濱河造成了極大的恐慌卷雕,老刑警劉巖节猿,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件票从,死亡現(xiàn)場離奇詭異,居然都是意外死亡滨嘱,警方通過查閱死者的電腦和手機(jī)峰鄙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來太雨,“玉大人吟榴,你說我怎么就攤上這事∧野猓” “怎么了吩翻?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長锥咸。 經(jīng)常有香客問我狭瞎,道長,這世上最難降的妖魔是什么搏予? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任熊锭,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘碗殷。我一直安慰自己精绎,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布锌妻。 她就那樣靜靜地躺著代乃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪仿粹。 梳的紋絲不亂的頭發(fā)上襟己,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天,我揣著相機(jī)與錄音牍陌,去河邊找鬼擎浴。 笑死,一個胖子當(dāng)著我的面吹牛毒涧,可吹牛的內(nèi)容都是我干的贮预。 我是一名探鬼主播,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼契讲,長吁一口氣:“原來是場噩夢啊……” “哼仿吞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起捡偏,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤唤冈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后银伟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體你虹,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年彤避,在試婚紗的時候發(fā)現(xiàn)自己被綠了傅物。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡琉预,死狀恐怖董饰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情圆米,我是刑警寧澤卒暂,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站娄帖,受9級特大地震影響也祠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜块茁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一齿坷、第九天 我趴在偏房一處隱蔽的房頂上張望桂肌。 院中可真熱鬧,春花似錦永淌、人聲如沸崎场。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽谭跨。三九已至,卻和暖如春李滴,著一層夾襖步出監(jiān)牢的瞬間螃宙,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工所坯, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谆扎,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓芹助,卻偏偏與公主長得像堂湖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子状土,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

推薦閱讀更多精彩內(nèi)容