fork 是linux创建进程的系统调用,相关的函数(不只是系统调用)还有 vfork,clone,sys_frok等。这些函数会整理不同参数,再调用到 do_fork 中。
本篇文章主要介绍do_fork 函数。(sys_call_table 是 系统调用表, fork -> syscall(number) -> sys_fork -> do_fork)
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, 8 unsigned long stack_start, 9 struct pt_regs *regs, 10 unsigned long stack_size, 11 int __user *parent_tidptr, 12 int __user *child_tidptr) 13 { 14 struct task_struct *p; 15 int trace = 0; 16 long pid; 17 18 if (unlikely(current->ptrace)) { 19 trace = fork_traceflag (clone_flags); 20 if (trace) 21 clone_flags |= CLONE_PTRACE; 22 } 23 24 p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr); 25 /* 26 * Do this prior waking up the new thread - the thread pointer 27 * might get invalid after that point, if the thread exits quickly. 28 */ 29 pid = IS_ERR(p) ? PTR_ERR(p) : p->pid; 30 31 if (!IS_ERR(p)) { 32 struct completion vfork; 33 34 if (clone_flags & CLONE_VFORK) { 35 p->vfork_done = &vfork; 36 init_completion(&vfork); 37 } 38 39 if ((p->ptrace & PT_PTRACED) || (clone_flags & CLONE_STOPPED)) { 40 /* 41 * We'll start up with an immediate SIGSTOP. 42 */ 43 sigaddset(&p->pending.signal, SIGSTOP); 44 set_tsk_thread_flag(p, TIF_SIGPENDING); 45 } 46 47 p->state = TASK_STOPPED; 48 if (!(clone_flags & CLONE_STOPPED)) 49 wake_up_forked_process(p); /* do this last */ 50 ++total_forks; 51 52 if (unlikely (trace)) { 53 current->ptrace_message = pid; 54 ptrace_notify ((trace << 8) | SIGTRAP); 55 } 56 57 if (clone_flags & CLONE_VFORK) { 58 wait_for_completion(&vfork); 59 if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE)) 60 ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP); 61 } else 62 /* 63 * Let the child process run first, to avoid most of the 64 * COW overhead when the child exec()s afterwards. 65 */ 66 set_need_resched(); 67 } 68 return pid; 69 }
18行:likely和unlikely是内核代码中常用的宏,likely实际是希望表达式x==1,即表达式x成立,并且在代码实际执行中,表达式x在绝大多数情况下是成立的,相反,unlikely是希望表达式在绝大多数情况下不成立。
24行: copy_process 复制进程信息。
31行: IS_ERR 是内核判断地址是否合法的常用函数。(具体为什么是(unsigned long)ptr > (unsigned long)-1000L,没太理解,chatgpt说是约定负数为错误,但个人感觉他说的不对。应该和地址空间有关(用户态占用3G内存,内核占用1G内存。))
34行: CLONE_VFORK // set if the parent wants the child to wake it up on mm_release ,英文不好,大概理解是 当子进程调用 mm_release 时,唤醒父进程。查看调用 CLONE_VFORK 的函数,发现都是vfork在使用。vfork 系统调用会要求先运行子进程,再运行父进程。所以猜测,是唤醒父进程使用的。
同时再搜索mm_release函数调用发现 vork_done 标志及注释,可以用来佐证上述猜想。
39行: 如果有人跟踪子进程,或者子进程设置里暂停状态,将子进程设置成暂停状态,设置TIF_SIGPENDING标志。(#define TIF_SIGPENDING 3 /* signal pending */ 不同系统这个值不一样)
47行: state用来记录进程状态。初始化成stop状态
48行:进程初始化是stop状态,如果再fork时没有设置stop状态,则将状态修改成 running。
50行:我理解是total_forks 是进程总数,新增加一个进程,就会+1, 销毁进程,应该是-1,但是没有看到-1操作。全局搜索,只看到显示函数有使用(应该是再/proc/stat下,或者是proc/pid/stat???)
52行:如果子进程被调试,则通知调试进程。
57行:VFORK要求先执行子进程,再执行父进程。
do_fork 函数读完,下一篇读 do_fork -> copy_process, 进程相关的信息都在这个函数里。
技术水平有限,虚心求教,欢迎指正。
标签:fork,do,clone,long,进程,vfork From: https://www.cnblogs.com/atest/p/17647349.html