Where is the source of the fork () call in Linux?

I spent quite a bit of time trying to find the source code for the function fork(). I know that most of the work being done is fork()being done do_fork()and can be found in kernel/fork.c. However, I want to see the source code for the function fork().

Any ideas where you could find it? I went through the source code of GCC and Linux, but still could not find it.

Edit: I am trying to find the exact implementation used by my system. As mentioned in the commentary and in this link , it appears to be in some wrapper in glibc. Any idea where in glibc I can find a wrapper. I searched for him, but could not find his definition.

+4
source share
3 answers

Assuming the x86 platform and Linux kernel 2.6.23 as a reference:

  • Create a file test-fork.c:

    #include <unistd.h>
    
    int main (void)
    {
        fork();
        return 0;
    }
    
  • Compile it with static binding: gcc -O0 -static -Wall test-fork.c -o test-fork

  • Disassemble it: objdump -D -S test-fork > test-fork.dis

  • Open the file test-fork.disand search 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    
    
  • Then do a search __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    
    

    Please note that on this particular hardware / core forkis associated with syscall number 2

  • Download a copy of the Linux kernel: wget http://www.kernel.org/pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2

  • Open file linux-2.6.23/arch/x86/kernel/syscall_table_32.S

  • Please note that syscall 2 is associated with

    sys_fork:
         .long sys\_fork   /* 2 */
    
  • Open file linux-2.6.23/arch/x86/kernel/process.c

  • Find sys_fork:

      asmlinkage int sys_fork(struct pt_regs regs)
      {
              return do_fork(SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
      }
    

    Note that it do_fork()is called only with the parameterSIGCHLD

  • Open the file linux-2.6.23/kernel/fork.c. It is determined here do_fork()!

  • do_fork()then calls 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;
      }
    
  • forking do_fork(), kernel/fork.c. , do_fork():

    • PID , alloc_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
        • 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 ( , ) PF_NOFREEZE
      • PF_FORKNOEXEC ( , `exec()) โ€‹โ€‹
      • `init_sigpending(),
      • , do_fork(), copy_process() `,
      • sched_fork(),
      • ,
    • do_fork() SIGSTOP , CLONE_STOPPED (.. PT_PTRACED p->ptrace)

    • CLONE_STOPPED , wake_up_new_task(), :

      • ,
      • , , (.. CLONE_VM ), , runqueue . , . , .
      • , , , (. CLONE_VM), runqueue
    • , CLONE_STOPPED, TASK_STOPPED
    • , PID ptrace_message current ptrace_notify(), SIGCHLD . "" - , ; SIGCHLD , , PID , current->ptrace_message.

    • CLONE_VFORK, , ( , )

  • PID .
+15

http://lxr.free-electrons.com/source/kernel/fork.c#L1787, Linux 4.4:

1787 #ifdef __ARCH_WANT_SYS_FORK
1788 SYSCALL_DEFINE0(fork)
1789 {
1790 #ifdef CONFIG_MMU
1791         return _do_fork(SIGCHLD, 0, 0, NULL, NULL, 0);
1792 #else
1793         /* can not support in nommu mode */
1794         return -EINVAL;
1795 #endif
1796 }
1797 #endif

, fork. Linux , glibc fork() syscall , .

+4

glibc fork.c

+1

Source: https://habr.com/ru/post/1624918/


All Articles