轉載-linux 2.6 進程總結

轉載-linux 2.6 進程總結
 
 
進程、輕量級進程(LWP)、線程
  • 進程:程序執行體,有生命期,用來分配資源的實體
  • 線程:分配CPU的實體。
    •   用戶空間實現,一個線程阻塞,所有都阻塞。
    •   內核實現,不會所用相關線程都阻塞。用LWP實現,用線程組表示這些線程邏輯上所屬的進程。

進程描述符
  • 進程描述符(簡稱pd, process descriptors),結構體是:task_struct
    •   數據較多,存放在kenerl的動態內存空間。
    •   pd的引用放在thread_info中,
      •    thread_info與內核棧,放在一個8K空間(它的地址8K對齊)。內核程序使用的棧空間很小。
      •    thread_info在底部,內核棧在頂部向下增長。
        •     好處:多CPU時方便,每個CPU根據自己的棧指針就可以找到當前的pd (以後用current表示當前CPU運行的進程描述符)。
          •      esp(內核棧指針)低8位置零,就是thread_info地址。
      •    每進程有自己的thread_info, (分配釋放函數: alloc_thread_info, free_thread_info)

  • 描述符的內容
    •   相關的ID (一個4元素數組)
      •    進程ID (PID)
        •     PID按創建順序連續增長,到最大值後從最小值開始。
        •     0號進程:交換進程(swapper)
        •     有PID可用位圖,表示那一個PID可用,至少佔一個頁。
      •    線程組ID(tgid),用LWP實現多線程支持
        •     多進程時,進程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數據結構——哈希表管理 (利用id找到所用相關的pd,方便)。
        •     一個哈希表數組(pid_hash),存放四個哈希表, 每一個表代表一類id (pid, tgid, pgrp, session)
        •     每個哈希表的由數組(索引爲哈希值)和二維鏈表(嵌入到進程描述符內的pids中)實現
          •      第一維鏈表:哈希衝突鏈表。
          •      第二維鏈表:要查找的值相同的鏈表, 叫per-PID list(同一組的所有線程,同一組的所有進程,同一會話的所有進程);
      •    進程組ID(pgrp), 回話ID(session)在共享信號的數據結構裏。因爲同一進程內的所有LWP,這兩個ID都是一樣的


  •  
    •   家族關係:由pd裏的鏈表(下級)和pd指針(上級)實現
      •    關係:
        •     親生父親:創建自己的進程,或是託孤進程(創建自己的進程死了)。
        •     父親:自己死時要發信號告知的。一般是親生父親,有時是監控自己的進程 (調用ptrace)
        •     孩子:
        •     兄弟:
      •    監控(自己起的名字,類似於監護。由於管理方式相同,也歸爲家族關係)
        •     監控的進程列表:ptrace_children
        •     被監控的其他進程:ptrace_list (類似於被監控的兄弟)
      •    在鏈表裏爲了管理方便:
        •     最大兒子的兄弟是父親
        •     最小兒子的弟弟也是父親
        •     父親保管最大兒子,和最小兒子

  •  
    •   進程資源及資源限制:
      •    CPU相關:
        •     佔用CPU總時間
        •     用戶的最大進程數
      •    內存相關:
        •     進程地址空間
        •     鎖住內存大小
        •     進程頁數 (只有記錄,沒有限制)
        •     堆大小,棧大小
      •    資源相關:
        •     文件:
          •      core dump大小
          •      最大文件大小
          •      打開文件個數
        •     進程同步與通信
          •      鎖數目,
          •      懸掛信號數據
          •      在消息列隊中佔的大小
      •    相關數據結構 和 處理流程
        •     pd->sigal->rlim 是一個表示進程資源使用情況以及限制的結構的數組。
        •     表示進程資源使用情況以及限制的結構:包含當前值,最大值兩個數值。
      •    只有超級用戶才能增大資源限制。
      •    一般用戶登陸時:
        •     kernel創建root進程,減少limit,
        •     建一個 shell子進程,繼承limit.
        •     把shell進程的用戶,改成登陸的那個用戶

  •  
    •   進程狀態(state)
      •    運行,TASK_RUNNING
        •     組織pd的結構:就緒進程鏈:
          •      一個CPU一組鏈表,每個鏈表表示一種優先級。
      •    阻塞
        •     可中斷阻塞,TASK_INTERRUPTIBLE
          •      可被硬件中斷,“釋放資源”事件,信號喚醒。
        •     不可中斷阻塞,TASK_UNINTERRUPTIBLE
          •      可被硬件中斷,“釋放資源”事件,喚醒。
          •      但不能被信號喚醒。可用於驅動程序中。
        •     組織pb的結構:等待列隊: 每一類事件一個列隊,用內嵌鏈表實現(雖然沒列出內嵌鏈表節點)
          •      列隊頭:
            •       自旋鎖:防止有一個主函數和中斷函數同時操作列隊。
          •      列隊節點:
            •       獨佔標誌:表示該進程是否要獨佔資源 (不再喚醒別的進程)
            •       指向pd的指針
            •       用於喚醒進程的回調函數。(提供進程的執行機會,是否操作等待列隊由用戶決定)
      •    停止
        •     停止TASK_STOPPED
          •      被信號停止
        •     追蹤TASK_TRACED
          •      該進程被一個調試進程監控以後,收到任何一個信號就進入該狀態
        •     組織pb的結構:FIXME: 信號的等待列隊?
      •    退出
        •     退出_殭屍EXIT_ZOMBIE
          •      進程終止,資源沒有被回收(父進程要用,沒有調wait系列函數)
        •     退出_死亡EXIT_DEAD
          •      進程終止,資源正在被回收(父進程要用,沒有調wait系列函數)。
          •      一旦資源回收完成,進程描述符也就被回收了。
          •      它防止該進程再次被wait.
        •     組織pb的結構:不掛到隊列上,只在家族關係中,等待父進程收回資源


程控制
  • 阻塞(current阻塞到某個列隊上):
    •   基本流程
      •    臨時生成一個列隊節點,初始化。
      •    改變current的狀態,放入節點,掛到列隊上。
      •    調度 (=====》至此,阻塞完成。 一旦被別的進程喚醒====》從調度函數中返回)
      •    從等待列隊上摘除節點。
    •   變化:
      •    將掛列隊、調度、從列隊刪除三步拆開,便於靈活處理。
      •    可中斷的、限時、獨佔的函數類似。只不過進程狀態、調度函數、獨佔標誌不同。
      •    非獨佔的從列隊開始添加,獨佔的從末尾添加。(但一個列隊內既有獨佔的,又有非獨佔的等待進程,很少見)

  • 喚醒:
    •   基本流程
      •    喚醒一個進程:調用節點裏的回調函數
      •    喚醒的時候從列隊開頭依次喚醒,直到喚醒一個獨佔的後停止。
    •   變化
      •    是否只喚醒可中斷的進程. (_interruptible後綴)
      •    喚醒的獨佔進程的數目(1個,多個(_nr後綴),所有(_all後綴))
      •    喚醒後是否不檢查優先級,馬上給予CPU (有_sync的不檢查優先級)。


  • 進程切換
    •   切換pgd (全局頁目錄),此章不討論。
    •   切換內核棧,硬件上下文
      •    硬件上下文,就是CPU的寄存器。
        •     一部分(大多數CPU寄存器(除了通用寄存器))在pd中保存(task_struct->thread, 類型是thread_struct),
        •     一部分(通用寄存器)保存在內核棧中.
      •    原來用硬件指令()保存CPU信息。後來改成軟件(一個個MOV指令)
        •     容易控制,可以挑選信息保存,便於優化。不保存的做其他用(如:進程間傳遞)
          •           far jmp:跳至目標進程的TSSD。而linux是每個CPU一個TSS,不是每進程一個
        •     對於一些寄存器(ds、es)可以檢查值。
        •     與用硬件指令保存時間差不多。
    •   switch_to 宏
      •    三個參數:
        •     prev: 要換走的進程,一般是當前進程
        •     next: 要換到的進程。
        •     last: 傳出參數。當前進程再次被換到時,最後一個佔用CPU的進程。(prev指向的進程 就是 next指向的進程 的last)
      •    步驟:
        •     棧切換, 完成後就是在新進程的上執行了:
          •      保存prev(放在eax)
          •      eflags,ebp入內核棧;
          •      保存並裝載新的esp (舊的esp放到prev->thread.esp,新的esp是next->thread.esp)
            •       此時current就是新的esp所指的thread_info內的task指針
        •     設置返回地址:
          •      prev進程以後得到執行時的__switch_to的返回地址: __switch_to後的第一條指令, 放入prev->thread.eip,
          •      準備next進程的從__switch_to返回的地址: next->thread.eip入棧.
        •     調用__switch_to ()函數,該函數動作如下:
          •      更新CPU的相關信息(tss和gdt):
            •       存next->thread.esp0(內核棧低)到本地TSS.esp0中。
            •       所在CPU的全局段表裏的TLS段, 設成next進程的.
            •       更新tss的I/O位圖.
          •      更新CPU的寄存器(pd->thread (tss) 與 CPU寄存器交換數據):
            •       保存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)

  • 任務狀態段(一個存CPU狀態的數組,tss_struct init_tss[])
    •     每個CPU用段上的一個元素。(FIXME: 用於:用戶模式要進入內核模式時,設置相應寄存器)
      •       TSS上存內核棧地址。CPU上的程序從用戶模式轉到內核模式,設置esp。
      •       TSS存I/O端口許可位圖。用戶模式程序用到I/O時,檢查有無權限
      •       所以,進程切換時,要保存的寄存器在pd->thread中。
        •         thread_struct不是thread_info。thread_info中只有少量的數據或指針, 用於通過esp快速定位數據
    •     進程切換時,更新TSS上的信息。
      •       CPU控制單元再從TSS上取需要的信息。
      •       即反應了CPU的當前進程情況,又不需要維護所有進程的狀態數據。
    •     TSS的描述符在GDT裏。
      •       TSSD:任務狀態段描述符 (其實應該叫任務狀態描述符,每個TSSD,表示一個CPU的狀態, FIXME: :具體以源碼爲準)
      •       CPU原始設計,每個進程一個TSS元素。
      •       linux設計,每個CPU一個TSS元素。
      •       cpu裏的tr寄存器,保存着自己的TSSD(即init_ttss[cpu_id]),不用總上gdt裏去取。

 

進程創建: clone, fork, vfork系統調用
  •   clone系統調用
    •    參數:
      •     執行函數(fn), 參數(arg)
      •     flags|死亡時給父進程發的信號 (clone_flags): 以下介紹clone_flags
        •      資源共享
          •       段,頁,打開文件共享:
            •        頁表(不是頁, CLONE_VM),
            •        打開文件(clone_files),
            •        建一個新tls段(clone_settls)
          •       路徑和權限設置:
            •        clone_fs: 共享根目錄, 當前目錄, 創建文件初始權限.
            •        clone_newns: 新的根路徑, 自己的視野看文件系統
          •       線程通信
            •        clone_sighand: 信號處理action, 阻塞和懸掛的信號
            •        clone_sysvsem: 共享undoable信號量操作
        •      進程關係
          •       同父: clone_parent 創建進程與新進程是兄弟 (同父), 新進程不是創建進程的子進程
            •        爲了方便期間, 以下討論暫時不考慮這一因素(它很容易實現), 認爲創建進程就是父進程
          •       同一個線程組: clone_thread. 屬於同一個進程(線程組)
          •       都被trace: clone_ptrace
          •       子進程不被trace: clone_untrace (內核設置, 覆蓋clone_ptrace)
        •      返回tid
          •       向父進程返回tid: clone_parent_settid
          •       向子進程返回tid: clone_child_settid
        •      子進程的狀態:
          •       子進程開始就stop: clone_stopped
        •      進程死亡或exec通知:
          •       啓動內核機制: 如果子進程死亡或exec, 它自己空間內的tid(*ctid)清零, 並喚醒等待子進程死亡的進程.
      •     賦給子進程的資源
        •      子進程的棧(父進程alloc的內存地址)
        •      線程局部倉庫段(tls)
      •     返回子進程tid的地址
        •      父進程用戶空間內的地址
        •      子進程用戶空間的地址

  •   clone, fork, vfork實現方式
    •   大致相同:
      •     系統調用服務例程sys_clone, sys_fork, sys_vfork三者最終都是調用do_fork函數完成.
        •     do_fork的參數與clone系統調用的參數類似, 不過多了一個regs(內核棧保存的用戶模式寄存器). 實際上其他的參數也都是用regs取的
    •    區別在於:
      •     clone:
        •      clone的API外衣, 把fn, arg壓入用戶棧中, 然後引發系統調用. 返回用戶模式後下一條指令就是fn.
        •      sysclone: parent_tidptr, child_tidptr都傳到了 do_fork的參數中
        •      sysclone: 檢查是否有新的棧, 如果沒有就用父進程的棧 (開始地址就是regs.esp)
      •     fork, vfork:
        •      服務例程就是直接調用do_fork, 不過參數稍加修改
        •      clone_flags:
          •       sys_fork: SIGCHLD|0;
          •       sys_vfork: SIGCHLD| (clone_vfork | clone_vm)
        •      用戶棧: 都是父進程的棧.
        •      parent_tidptr, child_ctidptr都是NULL.

  • 具體實現函數do_fork() (內核函數)的工作流程:
    •   分配PID, 確定子進程到底是否traced.
      •    分配空閒的PID
      •    確定clone_ptrace位. (確定子進程到底要不要被trace, 而不是參數所說的希望被trace)
        •     設置該位: 參數已設該位, 且創建線程被trace中
        •     清除該位: 父進程沒有被trace, 或 clone_untrace已經設置.
    •   複製進程描述符(copy_process)
      •    檢查clone_flags是否兼容, 是否安全
        •     clone_newns 與 clone_fs 互斥
        •     clone_sighand 是 clone_thread 的必要條件: 線程必須共享信號處理
        •     clone_vm 是 clone_sighand 的必要條件 : 共享信號處理, 首先要共享信號處理的代碼(在進程頁面裏)
        •     附加的安全檢查: security_task_create(clone_flags)
      •    複製進程描述符
        •     在父進程的thread_info裏保存浮點寄存器: __unlazy_fpu()
        •     分配新的進程pd(alloc_task_struct), 並拷貝父進程pd
        •     分配新的thread_info(alloc_thread_info), 並拷貝父進程的thread_info.
        •     新的thread_info和新分配的pd 相互引, 新pd的引用計數設爲2 (表示:新pd有用, 且不是殭屍進程)
      •    相關計數加1: (此處先相關計數檢查, 都通過後再都加1)
        •     檢查並增加: 用戶擁有進程數, 系統總共進程數.
          •      一般來說, 所有進程的thread_info總和, 不超過物理內存的1/8
        •     新進程的可執行格式的引用計數(FIXME: pd裏標有可執行個數嗎)
        •     系統執行fork總數.
      •    進程pd的關鍵域的設置(順序與源碼可能不一致):
        •     進程關係
          •      設置父子關係 (parent, real_parent, 考慮被trace的情況)
          •      設置新pd的PID
          •      設置tgid, 線程組長的pd(pd->group_leader). (根據是不是線程組長, 即clone_thread位是否爲0)
          •      加入PID哈希表(pid, tgid, 如果是進程組長加入pgid和sid表),(調attach_pid())
          •      拷貝tid到父進程的用戶空間(parent_tidptr)
        •     拷貝資源(如果clone_flags沒標明共享):
          •      文件,目錄,內存:copy_files, copy_mm, copy_namespace,
          •      進程通信: copy_signal, copy_sighand, copy_semundo
        •     設置子進程的內核棧(thread_info), 內核態相關寄存器(thread_struct, 不知道這個結構的具體用處): copy_thread()
          •      子進程的thread_struct:
            •       esp, esp0 - 內核棧頂, 內核棧底
            •       eip - ret_from_fork()的地址 (用戶態切到內核態的第一條指令)
            •       I/O許可位圖 - 如果父進程有, 就拷貝一份過來
            •       TLS - 如果用戶空間提供了TLS段, 拷貝過來
          •      設置子進程的內核棧:
            •       child_regs.esp = 傳入的棧地址參數;
            •       child_regs.eax = 0, 給用戶態的返回值是0
            •       清除thread_info中的, TIF_SYSCALL_TRACE位, 防止運行ret_from_fork時, 系統通知調試進程
            •       設置子進程的thread_info的cpuid
        •     設置調度信息(sched_fork())
          •      設置task_running狀態,
          •      初始化調度參數(時間片),
          •      子進程禁止內核搶佔(thread_info.preempt_cout = 1)
        •     其他:
          •      如果沒有被trace,pd->ptrace = 0;
          •      設置pd->exit_signal:
            •       有clone_thread位: 設爲參數clone_flags中的退出信號
            •       沒有clone_thread位: 設爲-1 (表示進程終止時, 該LWP不給父進程發信號)
          •      pd->flags: 清除PF_SUPERPRIV , 設置PF_FORKNOEXEC
          •      大內核鎖 pd->lock_depth = -1
          •      exec次數: pd->did_exec = 0
          •      拷貝child_tidptr到pd->set_child_tid. 以備子進程開始執行時, 把tid放到自己內存空間的child_tidptr
      •    返回pd
    •   設置父子進程的運行狀態, 調度信息
      •    設置子進程的狀態.
        •     掛信號: 如果創建出來的是停止(clone_stopped)或被trace(pd->ptrace裏有PT_PTRACE位)的進程, 懸掛一個SIGSTOP信號.
          •      只有debugger發出SIGCONT信號後, 才能進入運行狀態
        •     設狀態,入列隊:如果有clone_stopped位, 子進程設爲stopped狀態; 否則調用wake_up_new_task(), 把子進程加入就緒列隊:
          •      調整父進程和子進程的調度參數 (主要是時間片)
          •      如果父子在同一CPU上運行, 且頁表不同享, 子進程在插在父進程前
            •       子進程很可能exec, 不與父進程共享頁. 這樣防止父進程無用的copy on write.
          •      如果不同CPU上運行, 或者共享頁表, 子進程放在列隊最後
      •    如果父進程處於被調試狀態, 程通知調試器
        •     當前進程給debugger進程發信號, 告知自己創建了子進程; 並停止自己(進入traced狀態), 使debugger運行.
          •      子進程的pid保存在current->ptrace_message中, 供debugger用
          •      調試器發信號, 使父進程繼續後, 再進行下一步; 否則父進程一直處於traced狀態
      •    設置父進程狀態
        •     如果有clone_vfork, 把自己放到一個等待列隊.
          •      內核處理完系統調用後, 會執行調度, 這樣就阻塞父進程了.
          •      直到子進程釋放了它的內存地址空間, 即子進程終止或exec新程序, 用信號喚醒父進程.
    •   返回子進程的pid.
    •   子進程被調度後,執行pd.thread.eip(ret_from_fork). 調用關係(=>): ret_from_fork=>schedule_tail=>finish_task_switch.
      •    schedule_tail的另一件事就是: 把pid保存到地址pd->set_child_tid (創建進程使的parent_tidptr)
      •    finish_task_switch的動作是: 裝載內核棧保存的寄存器(regs->eax爲0),返回到用戶態。系統調用返回值就是eax(0)

  • 內核線程:
    •   只運行於kernel模式,只能訪問大於3G的空間。而普通進程在內核模式時,能訪問整個4G空間
    •   創建方法, 類似於clone
      •    準備返回地址fn: 構造一個regs. 裏面有fn, args, __KERNEL_CS等. regs->eip是彙編函數kernel_thread_helper
      •    do_fork (flags|CLONE_VM|clone_untraced, 0, &regs, 0, NULL, NULL)
        •     創建線程, 與父進程共享頁. 用上步構造的regs初始化新程的內核棧
      •    新線程被調度後. 由ret_from_fork, 用regs恢復寄存器, 開始執行kernel_thread_helper
      •    kernel_thread_helper: 把args壓入棧, call fn(args, fn都寄存器中)
    •   典型的內核線程:
      •    進程0: 所有進程的祖先
        •     編譯時存在.
          •      pd, 內核棧: init_task, init_thread_union
          •      資源: init_mm, init_files, init_fs.  信號: init_signals, init_sighand
          •      頁表: swapper_gd_dir
        •     功能
          •      初始化系統數據,
            •       多CPU系統中, 開始時BIOS禁用其他CPU.
            •       初始化系統數據後, 進程0拷貝自己到其他CPU的調度列隊上, 啓動其他CPU, 所有的PID都是0.
          •      使能中斷
          •      創建內核線程1, (函數是init)
          •      進入idle
      •    進程1:
        •     init函數 exec可執行文件init, 使內核線程變成了普通進程.
        •     管理其他進程, 稱爲託孤進程
      •    其他內核線程:
        •     執行工作列隊:
          •      ksoftirqd: 執行 softlets
          •      kblockd: 執行工作列隊 kblockd_workqueue, 定期激活塊設備驅動
          •      keventd (又叫events): 處理工作列隊 keventd_wq
        •     管理資源:
          •      kapmd: 電源管理
          •      kswapd: 交換進程, 用於回收內存資源
          •      pdflush: flush髒的磁盤緩存

進程銷燬
  • 進程終止
    •   系統調用
      •    整個進程終止: exit_group(), 由do_group_exit處理系統調用. c函數 exit()也是用的這系統調用
      •    某個線程終止: _exit(), 由do_exit處理. C函數中用到此係統調用的API: pthread_exit
    •   do_group_exit流程: (整個組內至少有一個線程調用它, 用於整組協調)
      •    檢查線程組的退出過程是否啓動: 檢查signal_group_exit(線程組內的公共數據)是否非零. 如果沒有啓動, 執行一下操作來啓動退出過程:
        •     設置啓動標誌signal_group_exit.
        •     存儲終止碼(exit_group的參數), 在current->signal->group_exit_cold
        •     向其他線程發SIG_KILL信號, (它們收到信號後, 調do_exit())
      •    調用do_exit, 使本線程退出
    •   do_exit流程:
      •    設置線程的終止標誌, 退出碼
        •     設置PF_EXITING, 標明要被終止
        •     設置pd->exit_code
          •      系統調用參數
          •      或是內核提供的錯誤碼, 表示異常終止
      •    釋放資源:
        •     刪除該進程的定時器
        •     去除對資源的引用:
          •      exit_mm, __exit_files;
          •      __exit_fs(root路徑,工作路徑, 創建文件權限), exit_namespace(掛載的文件系統的視野);
          •      exit_thread(thread_struct), exit_sem,
      •    如果這個線程的函數實現了一種可執行格式, 可執行格式數的引用計數--; FIXME: 還沒看到這塊兒, 湊合翻譯的不一定對
      •    改變父子關係, 並向父進程發信號, 改變自己的狀態(exit_notify)
        •     託付終止線程創建的子進程:
          •      如果終止線程還有同組線程: 終止線程創建的子進程, 作爲與同組線程的子進程.
          •      否則: 終止線程創建的子進程, 作爲孤兒進程, 由init進程託管
        •     向父進程發信號
          •      exit_signal有意義 && 最後線程 :  發exit_signal
          •      否則:
            •       被trace : 發SIGCHLD
            •       沒被trace : 不發信號
        •     殭屍自己或直接死亡,  並設置PF_DEAD位
          •      exit_signal沒意義 && 沒被trace : 直接死亡 (這種情況沒有發信號)
            •       變成EXIT_DEAD狀態,
            •       release_task() (後面介紹). pd引用計數變爲1, 不會馬上釋放
          •      否則: 殭屍
            •       exit_signal有意義 || 被trace : 殭屍
          •      整理"殭屍"與"發臨殭屍信號"的關係:
            •       將發信號的條件中"最後線程"去掉, 可簡化爲(exit_signal有意義)||(被trace) == (發信號)
            •       可得出後: (發信號) == (殭屍)
            •       又可推出: (沒有trace && exit_signal有意義 && 不是最後進程) == (殭屍了,但沒法信號) , 這種情況在移除死進程時, 會給其父進程發信號 (FIXME: 待驗證)
      •    調度. 調度函數會忽略殭屍進程, 但會減少殭屍進程的pd的使用計數; 會檢查PF_DEAD位, 把它變成exit_dead狀態

  • 進程移除 TODO:

 

 原文地址 http://linux.chinaunix.net/bbs/thread-1034959-1-1.html
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章