Linux中fork()调用的源代码在哪里?

前端之家收集整理的这篇文章主要介绍了Linux中fork()调用的源代码在哪里?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

我花了很多时间试图找到fork()函数的源代码.我知道fork()完成的大部分工作都是由do_fork()完成的,可以在kernel / fork.c中找到.但是我想看到的是fork()函数的源代码.

有什么想法可以找到吗?我一直在浏览GCC和Linux代码,但仍未设法找到它.

编辑:我正在尝试找到我的系统正在使用的确切实现.正如评论中所提及的,在Link中它显然在glibc的一些包装中.任何想法在glibc我可以找到包装器.我经常搜索但找不到它的定义.

最佳答案
以x86平台和2.6.23 Linux内核为参考:

>创建test-fork.c文件

  1. #include

>使用静态链接编译它:gcc -O0 -static -Wall test-fork.c -o test-fork
>拆卸它:objdump -D -S test-fork>测试fork.dis
>打开test-fork.dis文件搜索fork:

  1. fork();
  2. 80481f4: e8 63 55 00 00 call 804d75c <__libc_fork>
  3. return 0;
  4. 80481f9: b8 00 00 00 00 mov $0x0,%eax
  5. }
  6. 80481fe: c9 leave
  7. 80481ff: c3 ret

>然后搜索__libc_fork:

  1. 0804d75c <__libc_fork>:
  2. 804d75c: 55 push %ebp
  3. 804d75d: b8 00 00 00 00 mov $0x0,%eax
  4. 804d762: 89 e5 mov %esp,%ebp
  5. 804d764: 53 push %ebx
  6. 804d765: 83 ec 04 sub $0x4,%esp
  7. 804d768: 85 c0 test %eax,%eax
  8. 804d76a: 74 12 je 804d77e <__libc_fork+0x22>
  9. 804d76c: c7 04 24 80 e0 0a 08 movl $0x80ae080,(%esp)
  10. 804d773: e8 88 28 fb f7 call 0 <_init-0x80480d4>
  11. 804d778: 83 c4 04 add $0x4,%esp
  12. 804d77b: 5b pop %ebx
  13. 804d77c: 5d pop %ebp
  14. 804d77d: c3 ret
  15. 804d77e: b8 02 00 00 00 mov $0x2,%eax
  16. 804d783: cd 80 int $0x80
  17. 804d785: 3d 00 f0 ff ff cmp $0xfffff000,%eax
  18. 804d78a: 89 c3 mov %eax,%ebx
  19. 804d78c: 77 08 ja 804d796 <__libc_fork+0x3a>
  20. 804d78e: 89 d8 mov %ebx,%eax
  21. 804d790: 83 c4 04 add $0x4,%esp
  22. 804d793: 5b pop %ebx
  23. 804d794: 5d pop %ebp
  24. 804d795: c3 ret

请注意,在此特定硬件/内核上,fork与syscall number 2相关联
>下载Linux内核的副本: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文件
>请注意,系统调用号2与之关联

  1. sys_fork:
  2. .long sys\_fork /* 2 */

>打开linux-2.6.23 / arch / x86 / kernel / process.c文件
>搜索sys_fork:

  1. asmlinkage int sys_fork(struct pt_regs regs)
  2. {
  3. return do_fork(SIGCHLD,regs.esp,&regs,NULL,NULL);
  4. }

请注意,仅使用SIGCHLD参数调用do_fork()
>打开linux-2.6.23 / kernel / fork.c文件.这是do_fork()定义的地方!
> do_fork()然后调用copy_process():

  1. /*
  2. * Ok,this is the main fork-routine.
  3. *
  4. * It copies the process,and if successful kick-starts
  5. * it and waits for it to finish using the VM if required.
  6. */
  7. 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)
  8. {
  9. struct task_struct *p;
  10. int trace = 0;
  11. struct pid *pid = alloc_pid();
  12. long nr;
  13. if (!pid)
  14. return -EAGAIN;
  15. nr = pid->nr;
  16. if (unlikely(current->ptrace)) {
  17. trace = fork_traceflag (clone_flags);
  18. if (trace)
  19. clone_flags |= CLONE_PTRACE;
  20. }
  21. p = copy_process(clone_flags,stack_start,regs,stack_size,\
  22. parent_tidptr,child_tidptr,pid);
  23. /*
  24. * Do this prior waking up the new thread - the thread
  25. * pointer might get invalid after that point,* if the thread exits quickly.
  26. */
  27. if (!IS_ERR(p)) {
  28. struct completion vfork;
  29. if (clone_flags & CLONE_VFORK) {
  30. p->vfork_done = &vfork;
  31. init_completion(&vfork);
  32. }
  33. if ((p->ptrace & PT_PTRACED) || \
  34. (clone_flags & CLONE_STOPPED)) {
  35. /*
  36. * We'll start up with an immediate SIGSTOP.
  37. */
  38. sigaddset(&p->pending.signal,SIGSTOP);
  39. set_tsk_thread_flag(p,TIF_SIGPENDING);
  40. }
  41. if (!(clone_flags & CLONE_STOPPED))
  42. wake_up_new_task(p,clone_flags);
  43. else
  44. p->state = TASK_STOPPED;
  45. if (unlikely (trace)) {
  46. current->ptrace_message = nr;
  47. ptrace_notify ((trace << 8) | SIGTRAP);
  48. }
  49. if (clone_flags & CLONE_VFORK) {
  50. freezer_do_not_count();
  51. wait_for_completion(&vfork);
  52. freezer_count();
  53. if (unlikely (current->ptrace & \
  54. PT_TRACE_VFORK_DONE)) {
  55. current->ptrace_message = nr;
  56. ptrace_notify \
  57. ((PTRACE_EVENT_VFORK_DONE << 8) | \
  58. SIGTRAP);
  59. }
  60. }
  61. } else {
  62. free_pid(pid);
  63. nr = PTR_ERR(p);
  64. }
  65. return nr;
  66. }

>分叉的大部分工作由do_fork()处理,
在kernel / fork.c中定义. do_fork()执行的操作:

>它通过调用alloc_pid()为子节点分配一个新的PID
>它检查父项的ptrace字段(即current-> ptrace)

>如果它不为零,则父进程将被另一个进程跟踪

>它调用copy_process(),它设置进程描述符和子进程执行所需的任何其他内核数据结构

>其参数与do_fork()加上子项的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局部变量中
>它将当前进程描述符的内容复制到tsk指向的task_struct结构中,然后将tsk-> thread_info设置为ti
>它将当前thread_info描述符的内容复制到ti指向的结构中,然后将ti->任务设置为tsk
>它将新进程描述符的使用计数器(即tsk->用法)设置为2,以指定进程描述符正在使用中,并且相应的进程处于活动状态(其状态不是EXIT_ZOMBIE或EXIT_DEAD)
>它返回新进程的进程描述符指针(即tsk)

> copy_process()然后检查是否未超过当前用户的最大进程数(即大于’max_threads)

>它通过清除或初始化task_struct的各个字段来区分子项与父项
>它调用copy_flags()来更新task_struct的flags字段

> PF_SUPERPRIV(表示任务是否使用超级用户权限)和PF_NOFREEZE标志被清除
>设置PF_FORKNOEXEC标志(表示任务是否未调用`exec())
>它调用`init_sigpending()来清除挂起的信号
>根据传递给do_fork()的参数,copy_process()`然后复制或共享资源
>打开文件
>文件系统信息
>信号处理程序
>地址空间
>它调用sched_fork(),它将父级和子级之间的剩余时间片分开
>最后,它返回一个指向新子节点的指针

>然后,do_fork()在设置了CLONE_STOPPED标志或者必须跟踪子进程的情况下添加一个待处理的SIGSTOP信号(即,在p-> ptrace中设置了PT_PTRACED标志)
>如果未设置CLONE_STOPPED标志,则调用wake_up_new_task()函数,该函数执行以下操作:

>它调整父项和子项的调度参数
>如果子进程与父进程在同一cpu上运行,并且父进程和子进程没有共享同一组页表(即CLONE_VM标志已清除),则会强制子进程在父进程之前运行,方法是将其插入到父进程的运行队列中在父母之前.如果子项刷新其地址空间并在分叉后立即执行新程序,则此简单步骤可以获得更好的性能.如果我们让父进程先运行,则Copy On Write机制会引起一系列不必要的页面重复.
>否则,如果子节点不与父节点在同一cpu上运行,或者父节点和子节点共享同一组页面表(即
CLONE_VM标志设置),它将子项插入父项运行队列的最后位置

>否则,如果设置了CLONE_STOPPED标志,则将子项置于TASK_STOPPED状态
>如果正在跟踪父进程,它将存储子进程的PID
当前的ptrace_message字段并调用
ptrace_notify(),它基本上停止当前进程并向其父进程发送SIGCHLD信号.孩子的“祖父母”是跟踪父母的调试者; SIGCHLD信号通知调试器当前已经分叉了一个子节点,可以通过查看current-> ptrace_message字段来检索其PID.
>如果指定了CLONE_VFORK标志,它会将父进程插入等待队列并暂停它,直到子进程释放其内存地址空间(即,直到子进程终止或执行新程序)

>它通过返回子的PID来终止.

猜你在找的Linux相关文章