# Linux system call呼叫 & `fork()`
###### tags: `learning`
## `fork` System Call如何呼叫
- 早期(v3.7及之前): `sys_fork()`呼叫`do_fork()`
```c
asmlinkage long sys_fork(struct pt_regs regs)
{
return do_fork(SIGCHLD, regs.rsp, ®s, 0);
}
```
- 後期(~v5.9): `SYS_DEFINEx()`(x代表參數個數)呼叫`do_fork()`
```c
#ifdef __ARCH_WANT_SYS_FORK
SYSCALL_DEFINE0(fork)
{
#ifdef CONFIG_MMU
return _do_fork(SIGCHLD, 0, 0, NULL, NULL, 0);
#else
/* can not support in nommu mode */
return -EINVAL;
#endif
}
#endif
```
- 最新版(v5.10之後): `SYS_DEFINEx()`呼叫`kernel_clone()`
```c
#ifdef __ARCH_WANT_SYS_FORK
SYSCALL_DEFINE0(fork)
{
#ifdef CONFIG_MMU
struct kernel_clone_args args = {
.exit_signal = SIGCHLD,
};
return kernel_clone(&args);
#else
/* can not support in nommu mode */
return -EINVAL;
#endif
}
#endif
```
- [ref](https://blog.csdn.net/boyemachao/article/details/112983228)
## fork/vfork/clone
- `fork()`將parent的<font color='red'>全部`task_struct`資源</font>copy給child
- 使用Copy On Write技術,parent與child共享資源,如果有寫入才分配新的空間給child
- `vfork()`將parent<font color='blue'>除了`mm_stuct`</font>的全部資源copy給child
- 即parent及child共享data section,但有各自的記憶體空間
- `vfork`創建的child process會先於parent執行
- `clone()`<font color='green'>利用`CLONE_xxx` flag指定parent的哪些資源</font>copy給child
- v5.10之前`fork/vfork/clone`底層皆呼叫`_do_fork()`,並利用第一個參數的flag區別
- `fork`: `SIGCHLD`
- child終止後會發送SIGCHLD信號給parent
- `vfork`: `CLONE_VFORK | CLONE_VM | SIGCHLD`
- `clone`: 由User自定義flag
- v5.10-rc1之後將原本的`_do_fork`替換成`kernel_clone`,`fork/vfork/clone`底層全部呼叫`kernel_clone`
## `kernel_clone`流程(與`_do_fork`基本一致)
1. `copy_process()` :複製parent的`task_struct`給child,return值為`task_struct` Pointer
2. `get_task_pid()`取得child pid
2. 如果是`vfork`,初始化vfork處理資訊
3. `wake_up_new_task()`將child加入scheduler,至此完成fork,child準備執行
4. 啟動`ptrace`,如果child開始執行就告訴parent
4. 如果是`vfork`,執行`wait_for_vfork_done()`,parent等待child完成,當child調用`exec`或`exit`之後,parent才可以繼續執行
- [ref1](https://blog.csdn.net/jasonactions/article/details/115316642)
- [ref2](https://blog.csdn.net/jasonactions/article/details/115316642)
- [ref3](https://cloud.tencent.com/developer/article/1891524)