【问题标题】:Why does the kretprobe of the _do_fork() only return once?为什么 _do_fork() 的 kretprobe 只返回一次?
【发布时间】:2017-09-02 19:29:10
【问题描述】:

当我用 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 installes probes on _do_fork 而不是克隆,但这不应该改变任何东西。)

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

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

【问题讨论】:

    标签: c linux kernel systemtap kprobe


    【解决方案1】:
    1. 子项的创建可能会失败,因此必须检测和处理错误
    2. 孩子有不同的返回值,这也必须处理
    3. 可能是父母有清理/额外的操作要做

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

    由于代码又大又多,所以可以尝试作弊,在特定于 Arch 的代码中寻找“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。

    【讨论】:

    • 非常感谢!这让我明白了一切。 :-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多