4

当我用 fork 编写一个小脚本时,系统调用返回两个进程(每个进程一次):

#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    int pid = fork();

    if (pid == 0) {
        // child
    } else if (pid > 0) {
        // parent
    }
}

如果我使用 systemtap 进行检测,我只会找到一个返回值:

// fork() in libc calls clone on Linux
probe syscall.clone.return {
    printf("Return from clone\n")
}

SystemTap 安装探针_do_fork而不是克隆,但这不应该改变任何东西。)

这让我很困惑。几个相关的问题:

  • 为什么系统调用只返回一次?
  • 如果我正确理解了_do_fork代码,该过程将被克隆到函数的中间。(copy_processwake_up_new_task)。后续代码不应该在两个进程中运行吗?
  • 系统调用之后的内核代码是否与系统调用之前的用户代码在同一线程/进程中运行?
4

1 回答 1

5
  1. 孩子的创建可能会失败,因此必须检测和处理错误
  2. 孩子有不同的返回值,这也必须处理
  3. 可能是父母有清理/额外的行动要做

因此,代码必须区分作为父级和子级执行。但是没有这种检查,这已经强烈暗示孩子一开始就没有执行此代码。因此,人们应该寻找一个专门的新孩子返回的地方。

由于代码相当大而且多毛,因此可以尝试作弊并在特定于架构的代码中查找“fork”,这很快就会显示 ret_from_fork。

通过 -> do_fork -> copy_process -> copy_thread_tls http://lxr.free-electrons.com/source/arch/x86/kernel/process_64.c#L158设置起点

因此

为什么系统调用只返回一次?

它不会返回一次。有 2 个返回线程,除了另一个使用不同的代码路径。由于探头仅安装在第一个上,因此您看不到另一个。另见下文。

如果我正确理解了 _do_fork 代码,则该过程将被克隆到函数的中间。(copy_process 和 wake_up_new_task)。后续代码不应该在两个进程中运行吗?

我之前注意到这是错误的。真正的问题是让孩子和父母回到同一个地方有什么好处。我没有看到任何东西,它会很麻烦(如上所述,额外的特殊外壳)。重新声明:让孩子返回elsehwere让调用者不必处理返回的孩子。他们只需要检查错误。

系统调用之后的内核代码是否与系统调用之前的用户代码在同一线程/进程中运行?

什么是“系统调用后的内核代码”?如果你是线程 X 并进入内核,你仍然是线程 X。

于 2017-04-09T10:52:22.800 回答