黄色网页视频 I 影音先锋日日狠狠久久 I 秋霞午夜毛片 I 秋霞一二三区 I 国产成人片无码视频 I 国产 精品 自在自线 I av免费观看网站 I 日本精品久久久久中文字幕5 I 91看视频 I 看全色黄大色黄女片18 I 精品不卡一区 I 亚洲最新精品 I 欧美 激情 在线 I 人妻少妇精品久久 I 国产99视频精品免费专区 I 欧美影院 I 欧美精品在欧美一区二区少妇 I av大片网站 I 国产精品黄色片 I 888久久 I 狠狠干最新 I 看看黄色一级片 I 黄色精品久久 I 三级av在线 I 69色综合 I 国产日韩欧美91 I 亚洲精品偷拍 I 激情小说亚洲图片 I 久久国产视频精品 I 国产综合精品一区二区三区 I 色婷婷国产 I 最新成人av在线 I 国产私拍精品 I 日韩成人影音 I 日日夜夜天天综合

進程、輕量級進程(LWP)、線程

系統(tǒng) 2268 0

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

?

進程、輕量級進程(LWP)、線程

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

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

進程、輕量級進程(LWP)、線程


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

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

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

【本文對您有幫助就好】

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

發(fā)表我的評論
最新評論 總共0條評論