应用层调用fork来创建进程的时候,内核层通过do_fork实现,相对来说应用层太容易了。而内核层创建fork做了很多工作。系统调用进入do_fork,这篇主要分析do_fork的实现。
fork、vfork都调用了clone系统调用,clone在内核中调用了 do_fork()函数实现,因此重点在于do_fork的分析。
代码如下,do_fork主要工作:
clone系统调用:
- SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
- int __user *, parent_tidptr,
- int, tls_val,
- int __user *, child_tidptr)
- {
- return do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr);
- }
do_fork内核层实现:
- /*
- * 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,
- unsigned long stack_size,
- int __user *parent_tidptr,
- int __user *child_tidptr)
- {
- struct task_struct *p;
- int trace = 0;
- long nr;
-
- /*
- * Determine whether and which event to report to ptracer. When
- * called from kernel_thread or CLONE_UNTRACED is explicitly
- * requested, no event is reported; otherwise, report if the event
- * for the type of forking is enabled.
- */
- //标志解析
- 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
- p = copy_process(clone_flags, stack_start, stack_size,
- child_tidptr, NULL, trace);
- /*
- * 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;
- struct pid *pid;
-
- trace_sched_process_fork(current, p);
-
- //产生分配给子进程的pid
- 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(p);
-
- /* forking complete and child started to run, tell ptracer */
- if (unlikely(trace))
- ptrace_event_pid(trace, pid);
-
- if (clone_flags & CLONE_VFORK) {
- //如果有CLONE_VFORK 需要子进程先运行
- if (!wait_for_vfork_done(p, &vfork))
- ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid);
- }
-
- put_pid(pid);
- } else {
- nr = PTR_ERR(p);
- }
- return nr;
- }
复制父进程资源,得出子进程task_struct。
p = copy_process(clone_flags, stack_start, stack_size, child_tidptr, NULL, trace);
基于父进程资源,产生一个子进程task_struct
- dup_task_struct
- tsk = alloc_task_struct_node
- kmem_cache_alloc_node(task_struct_cachep, GFP_KERNEL, node)
- ti = alloc_thread_info_node(tsk, node)
- alloc_kmem_pages_node(node, THREADINFO_GFP, THREAD_SIZE_ORDER);
- arch_dup_task_struct(tsk, orig)
- *dst = *src; //父进程资源给子进程
-
- tsk->stack = ti
- setup_thread_stack(tsk, orig) //父进程栈给子进程
- clear_user_return_notifier(tsk);//清除一些标志
- clear_tsk_need_resched(tsk);//清除一些标志
- set_task_stack_end_magic(tsk)//设置栈底标志
- atomic_set(&tsk->usage, 2);
拷贝父进程证书
- /* Perform scheduler related setup. Assign this task to a CPU. */
- retval = sched_fork(clone_flags, p);
- if (retval)
- goto bad_fork_cleanup_policy;
-
- retval = perf_event_init_task(p);
- if (retval)
- goto bad_fork_cleanup_policy;
- retval = audit_alloc(p);
- if (retval)
- goto bad_fork_cleanup_perf;
- /* copy all the process information */
- shm_init_task(p);
- retval = copy_semundo(clone_flags, p);
- if (retval)
- goto bad_fork_cleanup_audit;
- retval = copy_files(clone_flags, p);
- if (retval)
- goto bad_fork_cleanup_semundo;
- retval = copy_fs(clone_flags, p);
- if (retval)
- goto bad_fork_cleanup_files;
- retval = copy_sighand(clone_flags, p);
- if (retval)
- goto bad_fork_cleanup_fs;
- retval = copy_signal(clone_flags, p);
- if (retval)
- goto bad_fork_cleanup_sighand;
- retval = copy_mm(clone_flags, p);
- if (retval)
- goto bad_fork_cleanup_signal;
- retval = copy_namespaces(clone_flags, p);
- if (retval)
- goto bad_fork_cleanup_mm;
- retval = copy_io(clone_flags, p);
- if (retval)
- goto bad_fork_cleanup_namespaces;
- retval = copy_thread(clone_flags, stack_start, stack_size, p);
- if (retval)
- goto bad_fork_cleanup_io;
-
- if (pid != &init_struct_pid) {
- pid = alloc_pid(p->nsproxy->pid_ns_for_children);
- if (IS_ERR(pid)) {
- retval = PTR_ERR(pid);
- goto bad_fork_cleanup_io;
- }
- }