首页 > 运维 > linux运维 > 正文

fork系统调用分析

看不見的法師
发布: 2025-06-26 12:46:01
原创
866人浏览过

linux中,新的进程主要通过fork函数来创建。我们知道,每个进程在内核中对应一个pcb块,内核通过对pcb块的操作来管理进程。在linux内核中,pcb对应的结构体是task_struct,即所谓的进程描述符(process descriptor)。这个数据结构包含了与进程相关的所有信息,包括描述进程属性的多个字段以及指向其他与进程相关的结构体的指针。因此,进程描述符内部结构相当复杂。该结构体的声明位于include/linux/sched.h文件中。

在linux中,新的进程主要通过fork函数来创建。我们知道,每个进程在内核中对应一个pcb块,内核通过对pcb块的操作来管理进程。在linux内核中,pcb对应的结构体是task_struct,即所谓的进程描述符(process descriptor)。这个数据结构包含了与进程相关的所有信息,包括描述进程属性的多个字段以及指向其他与进程相关的结构体的指针。因此,进程描述符内部结构相当复杂。该结构体的声明位于include/linux/sched.h文件中。

task_struct结构体中包含指向mm_struct结构体的指针mm,用于描述进程的内存管理信息;指向fs_struct结构体的指针fs,用于描述进程当前所在的目录;以及指向files_struct结构体的指针files,用于描述该进程已打开的所有文件。我们需要注意的是,进程在运行期间可能处于不同的状态,如TASK_RUNNING、TASK_STOPPED、TASK_TRACED等。

在用户态下,可以通过fork()函数创建进程。此外,还可以通过vfork()和clone()函数来创建新进程。fork、vfork和clone这三个API函数均由glibc库提供,它们分别封装了同名的系统调用fork()。这些函数适用于不同的场景。例如,子进程可能需要复制父进程的整个地址空间,但在创建后立即执行exec族函数会导致效率低下。写时拷贝技术满足了这种需求,减少了地址空间复制的开销。vfork创建的子进程完全共享父进程的地址空间,甚至是父进程的页表项,父子进程对数据的任何修改都会相互影响。clone函数在创建子进程时提供了更大的灵活性,通过传递不同的参数可以选择性地复制父进程的资源。内核中对应的服务例程分别为sys_fork()、sys_vfork()和sys_clone()。例如,sys_fork()的声明如下(位于arch/x86/kernel/process.c):

int sys_fork(struct pt_regs *regs) {
    return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
}
<p>int sys_vfork(struct pt_regs *regs) {
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, NULL, NULL);
}</p><p>sys_clone(unsigned long clone_flags, unsigned long newsp, void <strong>user <em>parent_tid, void __user </em>child_tid, struct pt_regs <em>regs) {
if (!newsp)
newsp = regs->sp;
return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
}
登录后复制

可以看到,do_fork()函数被上述三个服务函数调用。do_fork()是内核创建进程的核心函数。通过分析调用过程如下,其中分析的是最新版4.X Linux源码,在i386体系结构中,通过0x80中断调用syscall:

fork系统调用分析

从图中可以看到,do_fork()和copy_process()是本文的主要分析对象。

do_fork函数的主要任务是复制原来的进程成为一个新的进程。在函数开始时,定义了一个task_struct类型的指针p,用于接收即将为新进程(子进程)分配的进程描述符。此时需要检查clone_flags是否被跟踪,即ptrace。ptrace用于标记一个进程是否被另一个进程所跟踪。跟踪最常见的例子是处于调试状态下的进程被debugger进程所跟踪。如果ptrace字段非零,说明debugger程序正在跟踪父进程,接下来通过fork_traceflag函数检测子进程是否也需要被跟踪。如果trace为1,则将跟踪标志CLONE_PTRACE加入标志变量clone_flags中。否则,可以进行进程创建,即调用copy_process()。

long _do_fork(unsigned long clone_flags, unsigned long stack_start, unsigned long stack_size, int __user </em>parent_tidptr, int </strong>user <em>child_tidptr, unsigned long tls) {
struct task_struct </em>p;
int trace = 0;
long nr;
if (!(clone_flags & CLONE_UNTRACED)) {
if (clone_flags & CLONE_VFORK)
trace = PTRACE_EVENT_VFORK;
else if ((clone_flags & CSIGNAL) != SIGCHLD)
trace = PTRACE_EVENT_CLONE;
else
trace = PTRACE_EVENT_FORK;
if (likely(!ptrace_event_enabled(current, trace)))
trace = 0;
}
}
登录后复制

这条语句执行的是创建过程中最核心的工作:通过copy_process()创建子进程的描述符,并创建子进程执行时所需的其他数据结构,最终返回这个创建好的进程描述符。由于copy_process()函数非常庞大,单独开辟一篇文章来讲解其实现。

p = copy_process(clone_flags, stack_start, stack_size, child_tidptr, NULL, trace, tls);
登录后复制

如果copy_process函数执行成功,将继续执行下面的代码。定义了一个完成量vfork,并对其进行初始化。如果使用vfork系统调用来创建子进程,那么必然是子进程先执行。这是因为vfork完成量在此处的作用:当子进程调用exec函数或退出时,向父进程发出信号。此时,父进程才会被唤醒;否则一直等待。

if (!IS_ERR(p)) {
struct completion vfork;
struct pid *pid;</p><pre class="brush:php;toolbar:false">trace_sched_process_fork(current, p);
pid = get_task_pid(p, PIDTYPE_PID);
nr = pid_vnr(pid);
if (clone_flags & CLONE_PARENT_SETTID)
    put_user(nr, parent_tidptr);
if (clone_flags & CLONE_VFORK) {
    p->vfork_done = &vfork;
    init_completion(&vfork);
    get_task_struct(p);
}
登录后复制

}

接下来,通过wake_up_new_task函数使得父子进程之一优先运行;如果设置了ptrace,则需要通知跟踪器。如果CLONE_VFORK标志被设置,则通过wait操作将父进程阻塞,直到子进程调用exec函数或退出。

wake_up_new_task(p); /<em> forking complete and child started to run, tell ptracer </em>/
if (unlikely(trace))
ptrace_event_pid(trace, pid);
if (clone_flags & CLONE_VFORK) {
if (!wait_for_vfork_done(p, &vfork))
ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid);
}
put_pid(pid);
如果copy_process()在执行时发生错误,则先释放已分配的pid;再根据PTR_ERR()的返回值得到错误代码,保存于pid中。返回pid。这也就是为什么使用fork系统调用时父进程会返回子进程pid的原因。
} else {
nr = PTR_ERR(p);
}
return nr;
}
登录后复制

参考:linuxsyscallsabids

以上就是fork系统调用分析的详细内容,更多请关注php中文网其它相关文章!

最佳 Windows 性能的顶级免费优化软件
最佳 Windows 性能的顶级免费优化软件

每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号