# Process management
process control block (PCB)

# process descriptor & Task_Struct
kernel把process稱作task,用doubly linked list存放,type name **task_struct**就是linux的PCB,裡面紀錄的process的一切資訊,size有1.7KB,滿大的

linux 2.6之前task_struct是存在stack最底端(stack往下長),linux 2.6之後的版本用thread_info把task_struct包起來,也放在stack最底端


# 存取當下在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



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如下

**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.
>

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溝通