# Process management process control block (PCB) ![](https://i.imgur.com/DUUEQAY.png) # process descriptor & Task_Struct kernel把process稱作task,用doubly linked list存放,type name **task_struct**就是linux的PCB,裡面紀錄的process的一切資訊,size有1.7KB,滿大的 ![](https://i.imgur.com/l4T3MYF.png) linux 2.6之前task_struct是存在stack最底端(stack往下長),linux 2.6之後的版本用thread_info把task_struct包起來,也放在stack最底端 ![](https://i.imgur.com/8LD1OKd.png) ![](https://i.imgur.com/sw3ikMM.png) # 存取當下在cpu執行的process > it is useful to be able to quickly look up the process descriptor of the currently executing task, which is done via the **current** macro. > current_thread_info() > Finally, current dereferences the task member of thread_info to return the task_struct: > current_thread_info()->task; > # process state ![](https://i.imgur.com/InlYwk7.png) ![](https://i.imgur.com/DmDdqTc.png) ![](https://i.imgur.com/MAQ22g8.png) Kernel code often needs to change a process’s state.The preferred mechanism is using > set_task_state(task, state); /* set task ‘task’ to state ‘state’ */ # process termination * process自己call exit() system call * main() return時 c compiler就會call exit() * 中途process自己達成明確目的call exit() * 別人send signal kill him * 發生exception 被kernel kill掉 exit()被wrapper成do_exit() > `code flow細節定義在kernel/exit.c` 做完之後process的所有資源都被free掉,也沒有address space了,然後被丟到EXIT_ZOMBIE state,唯一留下thread_info structure & task_struct structure,目的是寫遺書給他的parent,等parent確認過child沒有利用價值後,就叫kernel把他幹掉。 parent的作法是call wait() system call,等他的child寫遺書說他想死,wait會收到child的pid,然後可以去call release_task()才把child的資源完全釋放掉 > 1. It calls __exit_signal(), which calls __unhash_process(), which in turns calls detach_pid() to remove the process from the pidhash and remove the process from the task list. > 2. __exit_signal() releases any remaining resources used by the now dead process and finalizes statistics and bookkeeping. > 3. If the task was the last member of a thread group, and the leader is a zombie, then release_task() notifies the zombie leader’s parent. > 4. release_task() calls put_task_struct() to free the pages containing the process’s kernel stack and thread_info structure and deallocate the slab cache containing the task_struct > # Process and thread(in linux) Linux實作thread的方式跟大多數OS不一樣 其他os的process and thread是用完全不一樣的struct process call fork()最後會call到 clone() thread call clone()參數帶一些自訂的flag process就是無帶參數的thread > clone(SIGCHLD, 0); thread就是有帶參數條件的process > `clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND, 0);` > vfork() vfork()跟fork()的差別只有child不複製page table,直接使用parent的address space,parent直接被block住直到child call exec() or exit(),child只能讀不能寫parent的address space,這個技術是在COW還沒發展前的技術(COW更好),所以新版的linux漸漸淘汰掉這個機制。 > `clone(CLONE_VFORK | CLONE_VM | SIGCHLD, 0);` <linux/sched.h> 定義clone flags如下 ![](https://i.imgur.com/FnnvJBi.png) **fork()**+**copy on wright(COW)** 疑問: linux fork 子行程的時候,子行程直接複製parent大多數的內容,大多數子行程被生出來後又執行exec()跑去做別的事,這樣的設計不是很浪費記憶體而且複製資料也花時間不是嗎? A:加上copy on wright技術,完全沒問題,只有在child有寫到shared的東西的時候,才會真正複製給child,如果child一出生就執行exec,那整個life cycle更不會有複製大量資料的時間 > In Linux, fork() utilizes copy-on-write pages to delay or altogether avoid copying the data that can be shared between the parent and child processes. Thus, the only overhead that is incurred during a normal fork() is the **copying of the parent's page tables** and **the assignment of a unique process descriptor struct, task_struct, for the child**. 來看這個 https://unix.stackexchange.com/questions/87551/which-file-in-kernel-specifies-fork-vfork-to-use-sys-clone-system-call **Kernel thread & normal process的差別** > kernel threads do not have an address space. (Their mm pointer, which points at their address space, is NULL.) They operate only in kernel-space and do not context switch into user-space. Kernel threads, however, are schedulable and preemptable, the same as normal processes. > ![](https://i.imgur.com/il7c5To.png) Q: Can a thread of one process A share data with the thread of another process B? A: yes, through IPC, A's thread 跟 B's thread沒有共用address space,但可透過IPC溝通