系统调用 fork()

太好了你问这个!“系统调用怎么实现 fork(),到底为啥一会用户态一会内核态”——这确实是面试、操作系统必问的核心问题,很多人都只背概念,但你想明白原理,这是最关键的。


我来用通俗 + 底层思维,一步步帮你理解整个 fork() 从用户态 → 内核态 → 再回用户态的完整流程。


🧠 先回答:为啥“一会用户态一会内核态”?

系统调用(如 fork())就是用户程序请求内核做事的“陷入”机制。

举个例子:

你写的用户代码:

pid_t pid = fork();

表面上是一个普通函数,其实:

  • fork() 并不是直接干复制进程;
  • 而是通过系统调用陷入内核,由操作系统来干活;
  • 所以:fork() 会从 用户态切换到内核态,再从 内核态回到用户态

🔍 1. 用户态:发起系统调用(比如 int 0x80

操作系统会在用户态提供一个 fork() 的“封装函数”,内部其实会执行汇编指令,比如:

mov eax, 2      ; syscall号,2表示fork
int 0x80        ; 触发中断,切换到内核态
  • int 0x80 是一种“陷入指令”,会跳转到内核态的中断处理函数;
  • 然后CPU做保护模式切换,加载内核堆栈,开始执行内核代码(进入 syscall handler)。

🔧 2. 内核态:执行 sys_fork() 系统调用逻辑

这时候你进入了内核,执行 sys_fork()(你贴的那段代码):

它大概会做以下事情(面试顺序很重要):

💡【系统调用fork的执行流程】:

  1. 获取当前进程(父进程)信息task_current()
  2. 分配子进程 task 结构alloc_task(),为子进程创建 PCB。
  3. 复制父进程内存空间memory_copy_uvm()(通常是写时复制 COW)
  4. 复制文件描述符copy_opened_files(),子进程也能打开文件。
  5. 设置子进程寄存器状态(重点):让子进程一恢复时能从用户态继续执行!
  6. 设置返回值
    • 父进程返回 子进程 pid
    • 子进程返回 0
  7. 启动子进程调度入口task_start(),加入调度器。

🚪 3. 回到用户态(继续执行 fork 之后的代码)

fork 之后,进程有两个!

pid_t pid = fork();

if (pid == 0) {
    // 子进程执行这段
} else {
    // 父进程执行这段
}

为什么父进程返回的是子 pid?子进程返回 0?

👉 因为内核设置了两个进程的 eax 寄存器值:

// 父进程
return child_task->pid;

// 子进程
tss->eax = 0;

当两个进程从 iret 回到用户态时,就会在 eax 寄存器中拿到不同的返回值,于是行为就能区分开了!


🖼 整体流程图总结

用户态:
--------------------------------------------------
| 用户程序调用 fork()                             |
|    ↓                                            |
| 封装后执行 int 0x80 触发中断                    |
--------------------------------------------------

内核态:
--------------------------------------------------
| 中断处理器进入 sys_call                         |
|    ↓                                            |
| 找到 syscall table 中 fork 对应函数 sys_fork() |
|    ↓                                            |
| 执行:复制PCB、内存、文件、寄存器等             |
|    ↓                                            |
| 设置返回值 eax=0 / eax=child_pid               |
|    ↓                                            |
| 用 iret 恢复到用户态                            |
--------------------------------------------------

用户态:
--------------------------------------------------
| 两个进程继续执行,父子分流                      |
--------------------------------------------------

✅ 面试重点回答模板(背下来加上理解)

问:fork 的底层流程是怎样的?为什么一会儿是用户态一会儿是内核态?

你可以答:

fork 是一个系统调用,由用户态发起,通过陷入指令(如 int 0x80)进入内核态处理。在内核中,fork 会创建子进程结构、复制父进程的内存空间(通常是写时复制 COW)、文件描述符等资源,然后设置两个进程的返回值不同(父进程返回子pid,子进程返回0),最后通过 iret 返回用户态,实现父子进程继续运行的分流。


要不要也讲一下 execve() 的流程?它和 fork() 常一起考,组合拳「fork + exec + wait」~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值