亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

進(jìn)程、輕量級(jí)進(jìn)程(LWP)、線程

系統(tǒng) 1845 0

轉(zhuǎn)載自:http://blog.chinaunix.net/u2/78225/showart_1761586.html

?

進(jìn)程、輕量級(jí)進(jìn)程(LWP)、線程

進(jìn)程、輕量級(jí)進(jìn)程(LWP)、線程
  • 進(jìn)程:程序執(zhí)行體,有生命期,用來分配資源的實(shí)體
  • 線程:分配CPU的實(shí)體。
    • ??用戶空間實(shí)現(xiàn),一個(gè)線程阻塞,所有都阻塞。
    • ??內(nèi)核實(shí)現(xiàn),不會(huì)所用相關(guān)線程都阻塞。用LWP實(shí)現(xiàn),用線程組表示這些線程邏輯上所屬的進(jìn)程。
進(jìn)程描述符
  • 進(jìn)程描述符(簡稱pd, process descriptors),結(jié)構(gòu)體是:task_struct
    • ??數(shù)據(jù)較多,存放在kenerl的動(dòng)態(tài)內(nèi)存空間。
    • ??pd的引用放在thread_info中,
      • ? ?thread_info與內(nèi)核棧,放在一個(gè)8K空間(它的地址8K對(duì)齊)。內(nèi)核程序使用的棧空間很小。
      • ? ?thread_info在底部,內(nèi)核棧在頂部向下增長。
        • ? ? 好處:多CPU時(shí)方便,每個(gè)CPU根據(jù)自己的棧指針就可以找到當(dāng)前的pd (以后用current表示當(dāng)前CPU運(yùn)行的進(jìn)程描述符)。
          • ? ???esp(內(nèi)核棧指針)低8位置零,就是thread_info地址。
      • ? ?每進(jìn)程有自己的thread_info, (分配釋放函數(shù): alloc_thread_info, free_thread_info)
  • 描述符的內(nèi)容
    • ??相關(guān)的ID (一個(gè)4元素?cái)?shù)組)
      • ? ?進(jìn)程ID (PID)
        • ? ? PID按創(chuàng)建順序連續(xù)增長,到最大值后從最小值開始。
        • ? ? 0號(hào)進(jìn)程:交換進(jìn)程(swapper)
        • ? ? 有PID可用位圖,表示那一個(gè)PID可用,至少占一個(gè)頁。
      • ? ?線程組ID(tgid),用LWP實(shí)現(xiàn)多線程支持
        • ? ? 多進(jìn)程時(shí),進(jìn)程id,就是線程組id, 也就是組長的pid(LWP)。 getpid() 取的是線程組的id(tgid), 也是組長的pid.
        • ? ? 單線程時(shí),pid = gid。所以getpid,也是真正的pid.
      • ? ?進(jìn)程組ID(pgrp)。
      • ? ?回話的ID(session).
        • ? ? 組ID,都是組長的PID。FIXME: 但pb也有各組長的PID
          • ? ???線程組長:tgid
          • ? ???進(jìn)程組長:signal->pgrp ,
          • ? ???會(huì)話長:signal->session
      • ? ?管理ID數(shù)據(jù)結(jié)構(gòu)——哈希表管理 (利用id找到所用相關(guān)的pd,方便)。
        • ? ? 一個(gè)哈希表數(shù)組(pid_hash),存放四個(gè)哈希表, 每一個(gè)表代表一類id (pid, tgid, pgrp, session)
        • ? ? 每個(gè)哈希表的由數(shù)組(索引為哈希值)和二維鏈表(嵌入到進(jìn)程描述符內(nèi)的pids中)實(shí)現(xiàn)
          • ? ???第一維鏈表:哈希沖突鏈表。
          • ? ???第二維鏈表:要查找的值相同的鏈表, 叫per-PID list(同一組的所有線程,同一組的所有進(jìn)程,同一會(huì)話的所有進(jìn)程);
      • ? ?進(jìn)程組ID(pgrp), 回話ID(session)在共享信號(hào)的數(shù)據(jù)結(jié)構(gòu)里。因?yàn)橥贿M(jìn)程內(nèi)的所有LWP,這兩個(gè)ID都是一樣的
  • ?
    • ??家族關(guān)系:由pd里的鏈表(下級(jí))和pd指針(上級(jí))實(shí)現(xiàn)
      • ? ?關(guān)系:
        • ? ? 親生父親:創(chuàng)建自己的進(jìn)程,或是托孤進(jìn)程(創(chuàng)建自己的進(jìn)程死了)。
        • ? ? 父親:自己死時(shí)要發(fā)信號(hào)告知的。一般是親生父親,有時(shí)是監(jiān)控自己的進(jìn)程 (調(diào)用ptrace)
        • ? ? 孩子:
        • ? ? 兄弟:
      • ? ?監(jiān)控(自己起的名字,類似于監(jiān)護(hù)。由于管理方式相同,也歸為家族關(guān)系)
        • ? ? 監(jiān)控的進(jìn)程列表:ptrace_children
        • ? ? 被監(jiān)控的其他進(jìn)程:ptrace_list (類似于被監(jiān)控的兄弟)
      • ? ?在鏈表里為了管理方便:
        • ? ? 最大兒子的兄弟是父親
        • ? ? 最小兒子的弟弟也是父親
        • ? ? 父親保管最大兒子,和最小兒子
  • ?
    • ??進(jìn)程資源及資源限制:
      • ? ?CPU相關(guān):
        • ? ? 占用CPU總時(shí)間
        • ? ? 用戶的最大進(jìn)程數(shù)
      • ? ?內(nèi)存相關(guān):
        • ? ? 進(jìn)程地址空間
        • ? ? 鎖住內(nèi)存大小
        • ? ? 進(jìn)程頁數(shù) (只有記錄,沒有限制)
        • ? ? 堆大小,棧大小
      • ? ?資源相關(guān):
        • ? ? 文件:
          • ? ???core dump大小
          • ? ???最大文件大小
          • ? ???打開文件個(gè)數(shù)
        • ? ? 進(jìn)程同步與通信
          • ? ???鎖數(shù)目,
          • ? ???懸掛信號(hào)數(shù)據(jù)
          • ? ???在消息列隊(duì)中占的大小
      • ? ?相關(guān)數(shù)據(jù)結(jié)構(gòu) 和 處理流程
        • ? ? pd->sigal->rlim 是一個(gè) 表示進(jìn)程資源使用情況以及限制的結(jié)構(gòu) 的數(shù)組。
        • ? ? 表示進(jìn)程資源使用情況以及限制的結(jié)構(gòu):包含當(dāng)前值,最大值兩個(gè)數(shù)值。
      • ? ?只有超級(jí)用戶才能增大資源限制。
      • ? ?一般用戶登陸時(shí):
        • ? ? kernel創(chuàng)建root進(jìn)程,減少limit,
        • ? ? 建一個(gè) shell子進(jìn)程,繼承l(wèi)imit.
        • ? ? 把shell進(jìn)程的用戶,改成登陸的那個(gè)用戶
  • ?
    • ??進(jìn)程狀態(tài)(state)
      • ? ?運(yùn)行,TASK_RUNNING
        • ? ? 組織pd的結(jié)構(gòu):就緒進(jìn)程鏈:
          • ? ???一個(gè)CPU一組鏈表,每個(gè)鏈表表示一種優(yōu)先級(jí)。
      • ? ?阻塞
        • ? ? 可中斷阻塞,TASK_INTERRUPTIBLE
          • ? ???可被硬件中斷,“釋放資源”事件,信號(hào)喚醒。
        • ? ? 不可中斷阻塞,TASK_UNINTERRUPTIBLE
          • ? ???可被硬件中斷,“釋放資源”事件,喚醒。
          • ? ???但不能被信號(hào)喚醒。可用于驅(qū)動(dòng)程序中。
        • ? ? 組織pb的結(jié)構(gòu):等待列隊(duì): 每一類事件一個(gè)列隊(duì),用內(nèi)嵌鏈表實(shí)現(xiàn)(雖然沒列出內(nèi)嵌鏈表節(jié)點(diǎn))
          • ? ???列隊(duì)頭:
            • ? ?? ?自旋鎖:防止有一個(gè)主函數(shù)和中斷函數(shù)同時(shí)操作列隊(duì)。
          • ? ???列隊(duì)節(jié)點(diǎn):
            • ? ?? ?獨(dú)占標(biāo)志:表示該進(jìn)程是否要獨(dú)占資源 (不再喚醒別的進(jìn)程)
            • ? ?? ?指向pd的指針
            • ? ?? ?用于喚醒進(jìn)程的回調(diào)函數(shù)。(提供進(jìn)程的執(zhí)行機(jī)會(huì),是否操作等待列隊(duì)由用戶決定)
      • ? ?停止
        • ? ? 停止TASK_STOPPED
          • ? ???被信號(hào)停止
        • ? ? 追蹤TASK_TRACED
          • ? ???該進(jìn)程被一個(gè)調(diào)試進(jìn)程監(jiān)控以后,收到任何一個(gè)信號(hào)就進(jìn)入該狀態(tài)
        • ? ? 組織pb的結(jié)構(gòu):FIXME: 信號(hào)的等待列隊(duì)?
      • ? ?退出
        • ? ? 退出_僵尸EXIT_ZOMBIE
          • ? ???進(jìn)程終止,資源沒有被回收(父進(jìn)程要用,沒有調(diào)wait系列函數(shù))
        • ? ? 退出_死亡EXIT_DEAD
          • ? ???進(jìn)程終止,資源正在被回收(父進(jìn)程要用,沒有調(diào)wait系列函數(shù))。
          • ? ???一旦資源回收完成,進(jìn)程描述符也就被回收了。
          • ? ???它防止該進(jìn)程再次被wait.
        • ? ? 組織pb的結(jié)構(gòu):不掛到隊(duì)列上,只在家族關(guān)系中,等待父進(jìn)程收回資源
進(jìn) 程控制
  • 阻塞(current阻塞到某個(gè)列隊(duì)上):
    • ??基本流程
      • ? ?臨時(shí)生成一個(gè)列隊(duì)節(jié)點(diǎn),初始化。
      • ? ?改變current的狀態(tài),放入節(jié)點(diǎn),掛到列隊(duì)上。
      • ? ?調(diào)度 (=====》至此,阻塞完成。 一旦被別的進(jìn)程喚醒====》從調(diào)度函數(shù)中返回)
      • ? ?從等待列隊(duì)上摘除節(jié)點(diǎn)。
    • ??變化:
      • ? ?將掛列隊(duì)、調(diào)度、從列隊(duì)刪除三步拆開,便于靈活處理。
      • ? ?可中斷的、限時(shí)、獨(dú)占的函數(shù)類似。只不過進(jìn)程狀態(tài)、調(diào)度函數(shù)、獨(dú)占標(biāo)志不同。
      • ? ?非獨(dú)占的從列隊(duì)開始添加,獨(dú)占的從末尾添加。(但一個(gè)列隊(duì)內(nèi)既有獨(dú)占的,又有非獨(dú)占的等待進(jìn)程,很少見)
  • 喚醒:
    • ??基本流程
      • ? ?喚醒一個(gè)進(jìn)程:調(diào)用節(jié)點(diǎn)里的回調(diào)函數(shù)
      • ? ?喚醒的時(shí)候從列隊(duì)開頭依次喚醒,直到喚醒一個(gè)獨(dú)占的后停止。
    • ??變化
      • ? ?是否只喚醒可中斷的進(jìn)程. (_interruptible后綴)
      • ? ?喚醒的獨(dú)占進(jìn)程的數(shù)目(1個(gè),多個(gè)(_nr后綴),所有(_all后綴))
      • ? ?喚醒后是否不檢查優(yōu)先級(jí),馬上給予CPU (有_sync的不檢查優(yōu)先級(jí))。
  • 進(jìn)程切換
    • ??切換pgd (全局頁目錄),此章不討論。
    • ??切換內(nèi)核棧,硬件上下文
      • ? ?硬件上下文,就是CPU的寄存器。
        • ? ? 一部分(大多數(shù)CPU寄存器(除了通用寄存器))在pd中保存(task_struct->thread, 類型是thread_struct),
        • ? ? 一部分(通用寄存器)保存在內(nèi)核棧中.
      • ? ?原來用硬件指令()保存CPU信息。后來改成軟件(一個(gè)個(gè)MOV指令)
        • ? ? 容易控制,可以挑選信息保存,便于優(yōu)化。不保存的做其他用(如:進(jìn)程間傳遞)
          • ? ?? ?? ? far jmp:跳至目標(biāo)進(jìn)程的TSSD。而linux是每個(gè)CPU一個(gè)TSS,不是每進(jìn)程一個(gè)
        • ? ? 對(duì)于一些寄存器(ds、es)可以檢查值。
        • ? ? 與用硬件指令保存時(shí)間差不多。
    • ??switch_to 宏
      • ? ?三個(gè)參數(shù):
        • ? ? prev: 要換走的進(jìn)程,一般是當(dāng)前進(jìn)程
        • ? ? next: 要換到的進(jìn)程。
        • ? ? last: 傳出參數(shù)。當(dāng)前進(jìn)程再次被換到時(shí),最后一個(gè)占用CPU的進(jìn)程。(prev指向的進(jìn)程 就是 next指向的進(jìn)程 的last)
      • ? ?步驟:
        • ? ? 棧切換, 完成后就是在新進(jìn)程的上執(zhí)行了:
          • ? ???保存prev(放在eax)
          • ? ???eflags,ebp入內(nèi)核棧;
          • ? ???保存并裝載新的esp (舊的esp放到prev->thread.esp,新的esp是next->thread.esp)
            • ? ?? ?此時(shí)current就是新的esp所指的thread_info內(nèi)的task指針
        • ? ? 設(shè)置返回地址:
          • ? ???prev進(jìn)程以后得到執(zhí)行時(shí)的__switch_to的返回地址: __switch_to后的第一條指令, 放入prev->thread.eip,
          • ? ???準(zhǔn)備next進(jìn)程的從__switch_to返回的地址: next->thread.eip入棧.
        • ? ? 調(diào)用__switch_to ()函數(shù),該函數(shù)動(dòng)作如下:
          • ? ???更新CPU的相關(guān)信息(tss和gdt):
            • ? ?? ?存next->thread.esp0(內(nèi)核棧低)到本地TSS.esp0中。
            • ? ?? ?所在CPU的全局段表里的TLS段, 設(shè)成next進(jìn)程的.
            • ? ?? ?更新tss的I/O位圖.
          • ? ???更新CPU的寄存器(pd->thread (tss) 與 CPU寄存器交換數(shù)據(jù)):
            • ? ?? ?保存FPU, MMX, XMM寄存器, 先不裝載以后需要時(shí)通過中斷裝載(TODO: )
            • ? ?? ?保存prev的fs, gs寄存器. 裝載next的
            • ? ?? ?裝載next的debug寄存器(debug寄存器一個(gè)8個(gè), 進(jìn)程切換時(shí)只需6個(gè))
          • ? ???返回
            • ? ?? ?prev放入eax (prev就是新進(jìn)程的last)
            • ? ?? ?ret
        • ? ? ret返回的地址: (__switch_to之前被存入棧中, __switch_to ret時(shí)進(jìn)入eip)
          • ? ???如果是next新進(jìn)程, next->thread.eip是iret_from_fork.
          • ? ???如果next不是新進(jìn)程:
            • ? ?? ?彈出ebp, elfags
            • ? ?? ?把eax放入last變量 (prev就是next進(jìn)程的last)
  • 任務(wù)狀態(tài)段(一個(gè)存CPU狀態(tài)的數(shù)組,tss_struct init_tss[])
    • ? ? 每個(gè)CPU用段上的一個(gè)元素。(FIXME: 用于:用戶模式要進(jìn)入內(nèi)核模式時(shí),設(shè)置相應(yīng)寄存器)
      • ? ?? ?TSS上存內(nèi)核棧地址。CPU上的程序從用戶模式轉(zhuǎn)到內(nèi)核模式,設(shè)置esp。
      • ? ?? ?TSS存I/O端口許可位圖。用戶模式程序用到I/O時(shí),檢查有無權(quán)限
      • ? ?? ?所以,進(jìn)程切換時(shí),要保存的寄存器在pd->thread中。
        • ? ?? ???thread_struct不是thread_info。thread_info中只有少量的數(shù)據(jù)或指針, 用于通過esp快速定位數(shù)據(jù)
    • ? ? 進(jìn)程切換時(shí),更新TSS上的信息。
      • ? ?? ?CPU控制單元再從TSS上取需要的信息。
      • ? ?? ?即反應(yīng)了CPU的當(dāng)前進(jìn)程情況,又不需要維護(hù)所有進(jìn)程的狀態(tài)數(shù)據(jù)。
    • ? ? TSS的描述符在GDT里。
      • ? ?? ?TSSD:任務(wù)狀態(tài)段描述符 (其實(shí)應(yīng)該叫任務(wù)狀態(tài)描述符,每個(gè)TSSD,表示一個(gè)CPU的狀態(tài), FIXME: :具體以源碼為準(zhǔn))
      • ? ?? ?CPU原始設(shè)計(jì),每個(gè)進(jìn)程一個(gè)TSS元素。
      • ? ?? ?linux設(shè)計(jì),每個(gè)CPU一個(gè)TSS元素。
      • ? ?? ?cpu里的tr寄存器,保存著自己的TSSD(即init_ttss[cpu_id]),不用總上gdt里去取。

您對(duì)本貼的看法: 鮮花[0] 臭蛋[0]
積分兌換專區(qū) | IT節(jié)能和TPC-E活動(dòng)獲獎(jiǎng)名單 | 致電800-858-2903,了解DELL如何為你量身訂制筆記本 | 送2G U盤 | 站長如何獲得資金?
ninesunqian ?? 帥哥
俠客 UID:698749 注冊(cè):2008-4-29 最后登錄: 2008-12-09 帖子: 49 精華:0 可用積分:85 (白手起家) 信譽(yù)積分:100 專家積分:0 (本版:0) 空間積分:1 推廣積分:0 狀態(tài): ...離線...
[ 資料 ] [ 站內(nèi)短信 ] [ Blog ]
2樓 發(fā)表于 2008-9-28 09:05?
進(jìn)程創(chuàng)建: clone, fork, vfork系統(tǒng)調(diào)用
  • ??clone系統(tǒng)調(diào)用
    • ? ?參數(shù):
      • ? ? 執(zhí)行函數(shù)(fn), 參數(shù)(arg)
      • ? ? flags|死亡時(shí)給父進(jìn)程發(fā)的信號(hào) (clone_flags): 以下介紹clone_flags
        • ? ???資源共享
          • ? ?? ?段,頁,打開文件共享:
            • ? ?? ? 頁表(不是頁, CLONE_VM),
            • ? ?? ? 打開文件(clone_files),
            • ? ?? ? 建一個(gè)新tls段(clone_settls)
          • ? ?? ?路徑和權(quán)限設(shè)置:
            • ? ?? ? clone_fs: 共享根目錄, 當(dāng)前目錄, 創(chuàng)建文件初始權(quán)限.
            • ? ?? ? clone_newns: 新的根路徑, 自己的視野看文件系統(tǒng)
          • ? ?? ?線程通信
            • ? ?? ? clone_sighand: 信號(hào)處理action, 阻塞和懸掛的信號(hào)
            • ? ?? ? clone_sysvsem: 共享undoable信號(hào)量操作
        • ? ???進(jìn)程關(guān)系
          • ? ?? ?同父: clone_parent 創(chuàng)建進(jìn)程與新進(jìn)程是兄弟 (同父), 新進(jìn)程不是創(chuàng)建進(jìn)程的子進(jìn)程
            • ? ?? ? 為了方便期間, 以下討論暫時(shí)不考慮這一因素(它很容易實(shí)現(xiàn)), 認(rèn)為創(chuàng)建進(jìn)程就是父進(jìn)程
          • ? ?? ?同一個(gè)線程組: clone_thread. 屬于同一個(gè)進(jìn)程(線程組)
          • ? ?? ?都被trace: clone_ptrace
          • ? ?? ?子進(jìn)程不被trace: clone_untrace (內(nèi)核設(shè)置, 覆蓋clone_ptrace)
        • ? ???返回tid
          • ? ?? ?向父進(jìn)程返回tid: clone_parent_settid
          • ? ?? ?向子進(jìn)程返回tid: clone_child_settid
        • ? ???子進(jìn)程的狀態(tài):
          • ? ?? ?子進(jìn)程開始就stop: clone_stopped
        • ? ???進(jìn)程死亡或exec通知:
          • ? ?? ?啟動(dòng)內(nèi)核機(jī)制: 如果子進(jìn)程死亡或exec, 它自己空間內(nèi)的tid(*ctid)清零, 并喚醒等待子進(jìn)程死亡的進(jìn)程.
      • ? ? 賦給子進(jìn)程的資源
        • ? ???子進(jìn)程的棧(父進(jìn)程alloc的內(nèi)存地址)
        • ? ???線程局部倉庫段(tls)
      • ? ? 返回子進(jìn)程tid的地址
        • ? ???父進(jìn)程用戶空間內(nèi)的地址
        • ? ???子進(jìn)程用戶空間的地址
  • ??clone, fork, vfork實(shí)現(xiàn)方式
    • ??大致相同:
      • ? ? 系統(tǒng)調(diào)用服務(wù)例程sys_clone, sys_fork, sys_vfork三者最終都是調(diào)用do_fork函數(shù)完成.
        • ? ? do_fork的參數(shù)與clone系統(tǒng)調(diào)用的參數(shù)類似, 不過多了一個(gè)regs(內(nèi)核棧保存的用戶模式寄存器). 實(shí)際上其他的參數(shù)也都是用regs取的
    • ? ?區(qū)別在于:
      • ? ? clone:
        • ? ???clone的API外衣, 把fn, arg壓入用戶棧中, 然后引發(fā)系統(tǒng)調(diào)用. 返回用戶模式后下一條指令就是fn.
        • ? ???sysclone: parent_tidptr, child_tidptr都傳到了 do_fork的參數(shù)中
        • ? ???sysclone: 檢查是否有新的棧, 如果沒有就用父進(jìn)程的棧 (開始地址就是regs.esp)
      • ? ? fork, vfork:
        • ? ???服務(wù)例程就是直接調(diào)用do_fork, 不過參數(shù)稍加修改
        • ? ???clone_flags:
          • ? ?? ?sys_fork: SIGCHLD|0;
          • ? ?? ?sys_vfork: SIGCHLD| (clone_vfork | clone_vm)
        • ? ???用戶棧: 都是父進(jìn)程的棧.
        • ? ???parent_tidptr, child_ctidptr都是NULL.
  • 具體實(shí)現(xiàn)函數(shù)do_fork() (內(nèi)核函數(shù))的工作流程:
    • ??分配PID, 確定子進(jìn)程到底是否traced.
      • ? ?分配空閑的PID
      • ? ?確定clone_ptrace位. (確定子進(jìn)程到底要不要被trace, 而不是參數(shù)所說的希望被trace)
        • ? ? 設(shè)置該位: 參數(shù)已設(shè)該位, 且創(chuàng)建線程被trace中
        • ? ? 清除該位: 父進(jìn)程沒有被trace, 或 clone_untrace已經(jīng)設(shè)置.
    • ??復(fù)制進(jìn)程描述符(copy_process)
      • ? ?檢查clone_flags是否兼容, 是否安全
        • ? ? clone_newns 與 clone_fs 互斥
        • ? ? clone_sighand 是 clone_thread 的必要條件: 線程必須共享信號(hào)處理
        • ? ? clone_vm 是 clone_sighand 的必要條件 : 共享信號(hào)處理, 首先要共享信號(hào)處理的代碼(在進(jìn)程頁面里)
        • ? ? 附加的安全檢查: security_task_create(clone_flags)
      • ? ?復(fù)制進(jìn)程描述符
        • ? ? 在父進(jìn)程的thread_info里保存浮點(diǎn)寄存器: __unlazy_fpu()
        • ? ? 分配新的進(jìn)程pd(alloc_task_struct), 并拷貝父進(jìn)程pd
        • ? ? 分配新的thread_info(alloc_thread_info), 并拷貝父進(jìn)程的thread_info.
        • ? ? 新的thread_info和新分配的pd 相互引, 新pd的引用計(jì)數(shù)設(shè)為2 (表示:新pd有用, 且不是僵尸進(jìn)程)
      • ? ?相關(guān)計(jì)數(shù)加1: (此處先相關(guān)計(jì)數(shù)檢查, 都通過后再都加1)
        • ? ? 檢查并增加: 用戶擁有進(jìn)程數(shù), 系統(tǒng)總共進(jìn)程數(shù).
          • ? ???一般來說, 所有進(jìn)程的thread_info總和, 不超過物理內(nèi)存的1/8
        • ? ? 新進(jìn)程的可執(zhí)行格式的引用計(jì)數(shù)(FIXME: pd里標(biāo)有可執(zhí)行個(gè)數(shù)嗎)
        • ? ? 系統(tǒng)執(zhí)行fork總數(shù).
      • ? ?進(jìn)程pd的關(guān)鍵域的設(shè)置(順序與源碼可能不一致):
        • ? ? 進(jìn)程關(guān)系
          • ? ???設(shè)置父子關(guān)系 (parent, real_parent, 考慮被trace的情況)
          • ? ???設(shè)置新pd的PID
          • ? ???設(shè)置tgid, 線程組長的pd(pd->group_leader). (根據(jù)是不是線程組長, 即clone_thread位是否為0)
          • ? ???加入PID哈希表(pid, tgid, 如果是進(jìn)程組長加入pgid和sid表),(調(diào)attach_pid())
          • ? ???拷貝tid到父進(jìn)程的用戶空間(parent_tidptr)
        • ? ? 拷貝資源(如果clone_flags沒標(biāo)明共享):
          • ? ???文件,目錄,內(nèi)存:copy_files, copy_mm, copy_namespace,
          • ? ???進(jìn)程通信: copy_signal, copy_sighand, copy_semundo
        • ? ? 設(shè)置子進(jìn)程的內(nèi)核棧(thread_info), 內(nèi)核態(tài)相關(guān)寄存器(thread_struct, 不知道這個(gè)結(jié)構(gòu)的具體用處): copy_thread()
          • ? ???子進(jìn)程的thread_struct:
            • ? ?? ?esp, esp0 - 內(nèi)核棧頂, 內(nèi)核棧底
            • ? ?? ?eip - ret_from_fork()的地址 (用戶態(tài)切到內(nèi)核態(tài)的第一條指令)
            • ? ?? ?I/O許可位圖 - 如果父進(jìn)程有, 就拷貝一份過來
            • ? ?? ?TLS - 如果用戶空間提供了TLS段, 拷貝過來
          • ? ???設(shè)置子進(jìn)程的內(nèi)核棧:
            • ? ?? ?child_regs.esp = 傳入的棧地址參數(shù);
            • ? ?? ?child_regs.eax = 0, 給用戶態(tài)的返回值是0
            • ? ?? ?清除thread_info中的, TIF_SYSCALL_TRACE位, 防止運(yùn)行ret_from_fork時(shí), 系統(tǒng)通知調(diào)試進(jìn)程
            • ? ?? ?設(shè)置子進(jìn)程的thread_info的cpuid
        • ? ? 設(shè)置調(diào)度信息(sched_fork())
          • ? ???設(shè)置task_running狀態(tài),
          • ? ???初始化調(diào)度參數(shù)(時(shí)間片),
          • ? ???子進(jìn)程禁止內(nèi)核搶占(thread_info.preempt_cout = 1)
        • ? ? 其他:
          • ? ???如果沒有被trace,pd->ptrace = 0;
          • ? ???設(shè)置pd->exit_signal:
            • ? ?? ?有clone_thread位: 設(shè)為參數(shù)clone_flags中的退出信號(hào)
            • ? ?? ?沒有clone_thread位: 設(shè)為-1 (表示進(jìn)程終止時(shí), 該LWP不給父進(jìn)程發(fā)信號(hào))
          • ? ???pd->flags: 清除PF_SUPERPRIV , 設(shè)置PF_FORKNOEXEC
          • ? ???大內(nèi)核鎖 pd->lock_depth = -1
          • ? ???exec次數(shù): pd->did_exec = 0
          • ? ???拷貝child_tidptr到pd->set_child_tid. 以備子進(jìn)程開始執(zhí)行時(shí), 把tid放到自己內(nèi)存空間的child_tidptr
      • ? ?返回pd
    • ??設(shè)置父子進(jìn)程的運(yùn)行狀態(tài), 調(diào)度信息
      • ? ?設(shè)置子進(jìn)程的狀態(tài).
        • ? ? 掛信號(hào): 如果創(chuàng)建出來的是停止(clone_stopped)或被trace(pd->ptrace里有PT_PTRACE位)的進(jìn)程, 懸掛一個(gè)SIGSTOP信號(hào).
          • ? ???只有debugger發(fā)出SIGCONT信號(hào)后, 才能進(jìn)入運(yùn)行狀態(tài)
        • ? ? 設(shè)狀態(tài),入列隊(duì):如果有clone_stopped位, 子進(jìn)程設(shè)為stopped狀態(tài); 否則調(diào)用wake_up_new_task(), 把子進(jìn)程加入就緒列隊(duì):
          • ? ???調(diào)整父進(jìn)程和子進(jìn)程的調(diào)度參數(shù) (主要是時(shí)間片)
          • ? ???如果父子在同一CPU上運(yùn)行, 且頁表不同享, 子進(jìn)程在插在父進(jìn)程前
            • ? ?? ?子進(jìn)程很可能exec, 不與父進(jìn)程共享頁. 這樣防止父進(jìn)程無用的copy on write.
          • ? ???如果不同CPU上運(yùn)行, 或者共享頁表, 子進(jìn)程放在列隊(duì)最后
      • ? ?如果父進(jìn)程處于被調(diào)試狀態(tài), 程通知調(diào)試器
        • ? ? 當(dāng)前進(jìn)程給debugger進(jìn)程發(fā)信號(hào), 告知自己創(chuàng)建了子進(jìn)程; 并停止自己(進(jìn)入traced狀態(tài)), 使debugger運(yùn)行.
          • ? ???子進(jìn)程的pid保存在current->ptrace_message中, 供debugger用
          • ? ???調(diào)試器發(fā)信號(hào), 使父進(jìn)程繼續(xù)后, 再進(jìn)行下一步; 否則父進(jìn)程一直處于traced狀態(tài)
      • ? ?設(shè)置父進(jìn)程狀態(tài)
        • ? ? 如果有clone_vfork, 把自己放到一個(gè)等待列隊(duì).
          • ? ???內(nèi)核處理完系統(tǒng)調(diào)用后, 會(huì)執(zhí)行調(diào)度, 這樣就阻塞父進(jìn)程了.
          • ? ???直到子進(jìn)程釋放了它的內(nèi)存地址空間, 即子進(jìn)程終止或exec新程序, 用信號(hào)喚醒父進(jìn)程.
    • ??返回子進(jìn)程的pid.
    • ??子進(jìn)程被調(diào)度后,執(zhí)行pd.thread.eip(ret_from_fork). 調(diào)用關(guān)系(=>): ret_from_fork=>schedule_tail=>finish_task_switch.
      • ? ?schedule_tail的另一件事就是: 把pid保存到地址pd->set_child_tid (創(chuàng)建進(jìn)程使的parent_tidptr)
      • ? ?finish_task_switch的動(dòng)作是: 裝載內(nèi)核棧保存的寄存器(regs->eax為0),返回到用戶態(tài)。系統(tǒng)調(diào)用返回值就是eax(0)
  • 內(nèi)核線程:
    • ??只運(yùn)行于kernel模式,只能訪問大于3G的空間。而普通進(jìn)程在內(nèi)核模式時(shí),能訪問整個(gè)4G空間
    • ??創(chuàng)建方法, 類似于clone
      • ? ?準(zhǔn)備返回地址fn: 構(gòu)造一個(gè)regs. 里面有fn, args, __KERNEL_CS等. regs->eip是匯編函數(shù)kernel_thread_helper
      • ? ?do_fork (flags|CLONE_VM|clone_untraced, 0, &regs, 0, NULL, NULL)
        • ? ? 創(chuàng)建線程, 與父進(jìn)程共享頁. 用上步構(gòu)造的regs初始化新程的內(nèi)核棧
      • ? ?新線程被調(diào)度后. 由ret_from_fork, 用regs恢復(fù)寄存器, 開始執(zhí)行kernel_thread_helper
      • ? ?kernel_thread_helper: 把a(bǔ)rgs壓入棧, call fn(args, fn都寄存器中)
    • ??典型的內(nèi)核線程:
      • ? ?進(jìn)程0: 所有進(jìn)程的祖先
        • ? ? 編譯時(shí)存在.
          • ? ???pd, 內(nèi)核棧: init_task, init_thread_union
          • ? ???資源: init_mm, init_files, init_fs.??信號(hào): init_signals, init_sighand
          • ? ???頁表: swapper_gd_dir
        • ? ? 功能
          • ? ???初始化系統(tǒng)數(shù)據(jù),
            • ? ?? ?多CPU系統(tǒng)中, 開始時(shí)BIOS禁用其他CPU.
            • ? ?? ?初始化系統(tǒng)數(shù)據(jù)后, 進(jìn)程0拷貝自己到其他CPU的調(diào)度列隊(duì)上, 啟動(dòng)其他CPU, 所有的PID都是0.
          • ? ???使能中斷
          • ? ???創(chuàng)建內(nèi)核線程1, (函數(shù)是init)
          • ? ???進(jìn)入idle
      • ? ?進(jìn)程1:
        • ? ? init函數(shù) exec可執(zhí)行文件init, 使內(nèi)核線程變成了普通進(jìn)程.
        • ? ? 管理其他進(jìn)程, 稱為托孤進(jìn)程
      • ? ?其他內(nèi)核線程:
        • ? ? 執(zhí)行工作列隊(duì):
          • ? ???ksoftirqd: 執(zhí)行 softlets
          • ? ???kblockd: 執(zhí)行工作列隊(duì) kblockd_workqueue, 定期激活塊設(shè)備驅(qū)動(dòng)
          • ? ???keventd (又叫events): 處理工作列隊(duì) keventd_wq
        • ? ? 管理資源:
          • ? ???kapmd: 電源管理
          • ? ???kswapd: 交換進(jìn)程, 用于回收內(nèi)存資源
          • ? ???pdflush: flush臟的磁盤緩存
進(jìn)程銷毀
  • 進(jìn)程終止
    • ??系統(tǒng)調(diào)用
      • ? ?整個(gè)進(jìn)程終止: exit_group(), 由do_group_exit處理系統(tǒng)調(diào)用. c函數(shù) exit()也是用的這系統(tǒng)調(diào)用
      • ? ?某個(gè)線程終止: _exit(), 由do_exit處理. C函數(shù)中用到此系統(tǒng)調(diào)用的API: pthread_exit
    • ??do_group_exit流程: (整個(gè)組內(nèi)至少有一個(gè)線程調(diào)用它, 用于整組協(xié)調(diào))
      • ? ?檢查線程組的退出過程是否啟動(dòng): 檢查signal_group_exit(線程組內(nèi)的公共數(shù)據(jù))是否非零. 如果沒有啟動(dòng), 執(zhí)行一下操作來啟動(dòng)退出過程:
        • ? ? 設(shè)置啟動(dòng)標(biāo)志signal_group_exit.
        • ? ? 存儲(chǔ)終止碼(exit_group的參數(shù)), 在current->signal->group_exit_cold
        • ? ? 向其他線程發(fā)SIG_KILL信號(hào), (它們收到信號(hào)后, 調(diào)do_exit())
      • ? ?調(diào)用do_exit, 使本線程退出
    • ??do_exit流程:
      • ? ?設(shè)置線程的終止標(biāo)志, 退出碼
        • ? ? 設(shè)置PF_EXITING, 標(biāo)明要被終止
        • ? ? 設(shè)置pd->exit_code
          • ? ???系統(tǒng)調(diào)用參數(shù)
          • ? ???或是內(nèi)核提供的錯(cuò)誤碼, 表示異常終止
      • ? ?釋放資源:
        • ? ? 刪除該進(jìn)程的定時(shí)器
        • ? ? 去除對(duì)資源的引用:
          • ? ???exit_mm, __exit_files;
          • ? ???__exit_fs(root路徑,工作路徑, 創(chuàng)建文件權(quán)限), exit_namespace(掛載的文件系統(tǒng)的視野);
          • ? ???exit_thread(thread_struct), exit_sem,
      • ? ?如果這個(gè)線程的函數(shù)實(shí)現(xiàn)了一種可執(zhí)行格式, 可執(zhí)行格式數(shù)的引用計(jì)數(shù)--; FIXME: 還沒看到這塊兒, 湊合翻譯的不一定對(duì)
      • ? ?改變父子關(guān)系, 并向父進(jìn)程發(fā)信號(hào), 改變自己的狀態(tài)(exit_notify)
        • ? ? 托付終止線程創(chuàng)建的子進(jìn)程:
          • ? ???如果終止線程還有同組線程: 終止線程創(chuàng)建的子進(jìn)程, 作為與同組線程的子進(jìn)程.
          • ? ???否則: 終止線程創(chuàng)建的子進(jìn)程, 作為孤兒進(jìn)程, 由init進(jìn)程托管
        • ? ? 向父進(jìn)程發(fā)信號(hào)
          • ? ???exit_signal有意義 && 最后線程 :??發(fā)exit_signal
          • ? ???否則:
            • ? ?? ?被trace : 發(fā)SIGCHLD
            • ? ?? ?沒被trace : 不發(fā)信號(hào)
        • ? ? 僵尸自己或直接死亡,??并設(shè)置PF_DEAD位
          • ? ???exit_signal沒意義 && 沒被trace : 直接死亡 (這種情況沒有發(fā)信號(hào))
            • ? ?? ?變成EXIT_DEAD狀態(tài),
            • ? ?? ?release_task() (后面介紹). pd引用計(jì)數(shù)變?yōu)?, 不會(huì)馬上釋放
          • ? ???否則: 僵尸
            • ? ?? ?exit_signal有意義 || 被trace : 僵尸
          • ? ???整理"僵尸"與"發(fā)臨僵尸信號(hào)"的關(guān)系:
            • ? ?? ?將發(fā)信號(hào)的條件中"最后線程"去掉, 可簡化為(exit_signal有意義)||(被trace) == (發(fā)信號(hào))
            • ? ?? ?可得出后: (發(fā)信號(hào)) == (僵尸)
            • ? ?? ?又可推出: (沒有trace && exit_signal有意義 && 不是最后進(jìn)程) == (僵尸了,但沒法信號(hào)) , 這種情況在移除死進(jìn)程時(shí), 會(huì)給其父進(jìn)程發(fā)信號(hào) (FIXME: 待驗(yàn)證)
      • ? ?調(diào)度. 調(diào)度函數(shù)會(huì)忽略僵尸進(jìn)程, 但會(huì)減少僵尸進(jìn)程的pd的使用計(jì)數(shù); 會(huì)檢查PF_DEAD位, 把它變成exit_dead狀態(tài)
  • 進(jìn)程移除 TODO:

進(jìn)程、輕量級(jí)進(jìn)程(LWP)、線程


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 国产3区| 奇米影视四色中文字幕 | 九九re| 欧美性色生活片天天看99 | 69国产成人综合久久精品91 | 色综合网亚洲精品久久 | 四虎永久免费观看 | 天天做爽夜夜做爽 | 日本精品久久久一区二区三区 | 久久在线资源 | 九九九热在线精品免费全部 | 国产精品久久久尹人香蕉 | 91热爆在线 | 一级毛片特级毛片免费的 | 一级aa毛片 | 老师在办公室被躁到白浆 | 午夜一区二区在线观看 | 97se在线观看 | 成人美女黄网站色大色费 | 久草在线视频免费 | 国语高清精品一区二区三区 | 精品久久久久久亚洲精品 | 中文精品久久久久国产网址 | 国产尤物精品视频 | 自拍第二页| 国产女人水多毛片18 | 九九热精彩视频 | 中文字幕一区精品 | 福利姬在线精品观看 | 一本一道| 成熟热自由日本语亚洲人 | 伊人国产视频 | 99热久久免费精品首页 | 日韩毛片在线免费观看 | 欧美日韩亚洲国产无线码 | 午夜国产精品久久影院 | 国产精品免费观在线 | 国产欧美在线观看不卡 | 大片国产片日本观看免费视频 | 日韩免费在线 | 国产成人一区二区三区精品久久 |