关闭。这个问题不满足Stack Overflow guidelines .它目前不接受答案。
想改善这个问题吗?更新问题,使其成为 on-topic对于堆栈溢出。
5年前关闭。
Improve this question
我花了很多时间试图找到 fork()
的源代码。功能。我知道大部分工作都是由 fork()
完成的由 do_fork()
完成可以在 kernel/fork.c
中找到.但是我想看到的是 fork()
的源代码功能。
任何可以找到它的想法?我一直在浏览 GCC 和 Linux 源代码,但仍然没有找到它。
编辑:我试图找到我的系统正在使用的确切实现。正如评论和此 Link 中所述它显然在 glibc 中的一些包装器中。任何想法我可以在 glibc 中找到包装器。我已经彻底搜索过,但找不到它的定义。
最佳答案
以x86平台和2.6.23 Linux内核为引用:
test-fork.c
文件:#include <unistd.h>
int main (void)
{
fork();
return 0;
}
gcc -O0 -static -Wall test-fork.c -o test-fork
objdump -D -S test-fork > test-fork.dis
test-fork.dis
文件并搜索 fork
: fork();
80481f4: e8 63 55 00 00 call 804d75c <__libc_fork>
return 0;
80481f9: b8 00 00 00 00 mov $0x0,%eax
}
80481fe: c9 leave
80481ff: c3 ret
__libc_fork
: 0804d75c <__libc_fork>:
804d75c: 55 push %ebp
804d75d: b8 00 00 00 00 mov $0x0,%eax
804d762: 89 e5 mov %esp,%ebp
804d764: 53 push %ebx
804d765: 83 ec 04 sub $0x4,%esp
804d768: 85 c0 test %eax,%eax
804d76a: 74 12 je 804d77e <__libc_fork+0x22>
804d76c: c7 04 24 80 e0 0a 08 movl $0x80ae080,(%esp)
804d773: e8 88 28 fb f7 call 0 <_init-0x80480d4>
804d778: 83 c4 04 add $0x4,%esp
804d77b: 5b pop %ebx
804d77c: 5d pop %ebp
804d77d: c3 ret
804d77e: b8 02 00 00 00 mov $0x2,%eax
804d783: cd 80 int $0x80
804d785: 3d 00 f0 ff ff cmp $0xfffff000,%eax
804d78a: 89 c3 mov %eax,%ebx
804d78c: 77 08 ja 804d796 <__libc_fork+0x3a>
804d78e: 89 d8 mov %ebx,%eax
804d790: 83 c4 04 add $0x4,%esp
804d793: 5b pop %ebx
804d794: 5d pop %ebp
804d795: c3 ret
请注意,在此特定硬件/内核上
fork
与 相关联系统调用号 2 wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2
linux-2.6.23/arch/x86/kernel/syscall_table_32.S
文件 sys_fork:
.long sys\_fork /* 2 */
linux-2.6.23/arch/x86/kernel/process.c
文件 sys_fork
: asmlinkage int sys_fork(struct pt_regs regs)
{
return do_fork(SIGCHLD, regs.esp, ®s, 0, NULL, NULL);
}
请注意
do_fork()
仅使用 SIGCHLD
调用参数linux-2.6.23/kernel/fork.c
文件。这里是do_fork()
被定义为! do_fork()
然后拨打 copy_process()
: /*
* Ok, this is the main fork-routine.
*
* It copies the process, and if successful kick-starts
* it and waits for it to finish using the VM if required.
*/
long do_fork(unsigned long clone_flags,
unsigned long stack_start,
struct pt_regs *regs,
unsigned long stack_size,
int __user *parent_tidptr,
int __user *child_tidptr)
{
struct task_struct *p;
int trace = 0;
struct pid *pid = alloc_pid();
long nr;
if (!pid)
return -EAGAIN;
nr = pid->nr;
if (unlikely(current->ptrace)) {
trace = fork_traceflag (clone_flags);
if (trace)
clone_flags |= CLONE_PTRACE;
}
p = copy_process(clone_flags, stack_start, regs, stack_size, \
parent_tidptr, child_tidptr, pid);
/*
* Do this prior waking up the new thread - the thread
* pointer might get invalid after that point,
* if the thread exits quickly.
*/
if (!IS_ERR(p)) {
struct completion vfork;
if (clone_flags & CLONE_VFORK) {
p->vfork_done = &vfork;
init_completion(&vfork);
}
if ((p->ptrace & PT_PTRACED) || \
(clone_flags & CLONE_STOPPED)) {
/*
* We'll start up with an immediate SIGSTOP.
*/
sigaddset(&p->pending.signal, SIGSTOP);
set_tsk_thread_flag(p, TIF_SIGPENDING);
}
if (!(clone_flags & CLONE_STOPPED))
wake_up_new_task(p, clone_flags);
else
p->state = TASK_STOPPED;
if (unlikely (trace)) {
current->ptrace_message = nr;
ptrace_notify ((trace << 8) | SIGTRAP);
}
if (clone_flags & CLONE_VFORK) {
freezer_do_not_count();
wait_for_completion(&vfork);
freezer_count();
if (unlikely (current->ptrace & \
PT_TRACE_VFORK_DONE)) {
current->ptrace_message = nr;
ptrace_notify \
((PTRACE_EVENT_VFORK_DONE << 8) | \
SIGTRAP);
}
}
} else {
free_pid(pid);
nr = PTR_ERR(p);
}
return nr;
}
do_fork()
处理。 ,定义于
kernel/fork.c
.由 执行的操作do_fork()
:alloc_pid()
为子进程分配一个新的 PID。 ptrace
父字段(即 current->ptrace
)copy_process()
,它设置进程描述符和子进程执行所需的任何其他内核数据结构do_fork()
加上 child 的PID clone_flags
参数兼容 security_task_create()
执行额外的安全检查。和 security_task_alloc()
dup_task_struct()
创建新的内核堆栈,thread_info
和 task_struct
新流程的结构。alloc_task_struct()
宏获取 task_struct
新进程的结构,并将其地址存储在 tsk
局部变量。 alloc_thread_info
宏来获得一个空闲内存区域来存储 thread_info
结构和新进程的内核模式堆栈,并将其地址保存在ti
局部变量task_struct
tsk
指向的结构,然后设置 tsk->thread_info
至 ti
thread_info
的内容描述符到 ti
指向的结构中,然后设置 ti->task
至 tsk
tsk->usage
)的使用计数器设置为 2 以指定进程描述符正在使用中并且相应的进程处于事件状态(其状态不是 EXIT_ZOMBIE
或 EXIT_DEAD
)tsk
)copy_process()
然后检查是否没有超过当前用户的最大进程数(即大于`max_threads)task_struct
的各个字段来区分子进程和父进程。 copy_flags()
更新 flags
领域task_struct
PF_SUPERPRIV
(表示任务是否使用 super 用户权限)和 PF_NOFREEZE
标志被清除 PF_FORKNOEXEC
设置标志(表示任务是否未调用 `exec()) do_fork(),
的参数copy_process()` 然后复制或共享资源 sched_fork()
它在父子之间分割剩余的时间片 do_fork()
添加待处理 SIGSTOP
信号以防万一CLONE_STOPPED
设置标志或必须跟踪子进程(即 PT_PTRACED
标志设置在 p->ptrace
中)CLONE_STOPPED
标志未设置,它调用 wake_up_new_task()
函数,执行以下操作:CLONE_VM
标志已清除),则它会通过将子进程插入父进程来强制子进程在父进程之前运行在父级之前运行队列。如果子进程在 fork 后立即刷新其地址空间并执行新程序,则此简单步骤会产生更好的性能。如果我们让父进程先运行,Copy On Write 机制会导致一系列不必要的页面重复。 CLONE_VM
标志设置),它将子进程插入到父进程运行队列的最后位置 CLONE_STOPPED
标志被设置,它把 child 放在 TASK_STOPPED
状态ptrace_message
领域current
并调用ptrace_notify()
,它基本上停止当前进程并发送 SIGCHLD
向其 parent 发出信号。 child 的“祖 parent ”是跟踪 parent 的调试器; SIGCHLD
信号通知调试器当前已经 fork 了一个 child ,其PID可以通过查看current->ptrace_message
来检索。 field 。 CLONE_VFORK
指定标志,它将父进程插入等待队列并挂起它,直到子进程释放其内存地址空间(即,直到子进程终止或执行新程序)关于c - Linux 中 fork() 调用的来源在哪里?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34871103/