Linux中关于进程创建的主要函数有fork,vfork,clone,他们的实现都是有do_fork来完成的,只是传入的参数有差别,do_fork中调用函数copy_process从父进程中复制相关内容到子进程,其中这个复制量的确定是根据传入参数flag来确定是否需要重新申请内存还是共享父进程的资源,下面对具体的代码进行分析。
-
-
-
- int sys_fork(struct pt_regs *regs)
- {
- return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
- }
-
-
-
-
-
-
-
-
-
-
-
- int sys_vfork(struct pt_regs *regs)
- {
- return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0,
- NULL, NULL);
- }
-
- int sys_clone(struct pt_regs *regs)
- {
- unsigned long clone_flags;
- unsigned long newsp;
- int __user *parent_tidptr, *child_tidptr;
-
- clone_flags = regs->bx;
- newsp = regs->cx;
- parent_tidptr = (int __user *)regs->dx;
- child_tidptr = (int __user *)regs->di;
- if (!newsp)
- newsp = regs->sp;
- return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr);
- }
下面是具体的do_fork函数
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 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;
- long nr;
-
-
-
-
-
-
- if (clone_flags & CLONE_NEWUSER) {
- if (clone_flags & CLONE_THREAD)
- return -EINVAL;
-
-
-
- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SETUID) ||
- !capable(CAP_SETGID))
- return -EPERM;
- }
-
-
-
-
-
-
- if (unlikely(clone_flags & CLONE_STOPPED)) {
- static int __read_mostly count = 100;
-
- if (count > 0 && printk_ratelimit()) {
- char comm[TASK_COMM_LEN];
-
- count--;
- printk(KERN_INFO "fork(): process `%s' used deprecated "
- "clone flags 0x%lx\n",
- get_task_comm(comm, current),
- clone_flags & CLONE_STOPPED);
- }
- }
-
-
-
-
-
- if (likely(user_mode(regs)))
- trace = tracehook_prepare_clone(clone_flags);
-
-
- p = copy_process(clone_flags, stack_start, regs, stack_size,
- child_tidptr, NULL, trace);
-
-
-
-
- if (!IS_ERR(p)) {
- struct completion vfork;
-
- trace_sched_process_fork(current, p);
-
- nr = task_pid_vnr(p);
-
- if (clone_flags & CLONE_PARENT_SETTID)
- put_user(nr, parent_tidptr);
-
-
-
- if (clone_flags & CLONE_VFORK) {
- p->vfork_done = &vfork;
- init_completion(&vfork);
- }
-
- audit_finish_fork(p);
-
-
-
- tracehook_report_clone(regs, clone_flags, nr, p);
-
-
-
-
-
-
-
- p->flags &= ~PF_STARTING;
-
-
-
- if (unlikely(clone_flags & CLONE_STOPPED)) {
-
-
-
- sigaddset(&p->pending.signal, SIGSTOP);
- set_tsk_thread_flag(p, TIF_SIGPENDING);
- __set_task_state(p, TASK_STOPPED);
- } else {
- wake_up_new_task(p, clone_flags);
- }
-
- tracehook_report_clone_complete(trace, regs,
- clone_flags, nr, p);
-
- if (clone_flags & CLONE_VFORK) {
- freezer_do_not_count();
- wait_for_completion(&vfork);
- freezer_count();
- tracehook_report_vfork_done(p, nr);
- }
- } else {
- nr = PTR_ERR(p);
- }
- return nr;
- }
对于设置了CLONE_VFORK标志的,调用下面函数
-
-
-
-
-
-
-
- static inline void init_completion(struct completion *x)
- {
- x->done = 0;
-
- init_waitqueue_head(&x->wait);
- }
和下面的代码呼应
-
- if (clone_flags & CLONE_VFORK) {
- freezer_do_not_count();
- wait_for_completion(&vfork);
- freezer_count();
- tracehook_report_vfork_done(p, nr);
- }
唤醒函数,将进程入运行队列
-
-
-
-
-
-
-
- void wake_up_new_task(struct task_struct *p, unsigned long clone_flags)
- {
- unsigned long flags;
- struct rq *rq;
-
- rq = task_rq_lock(p, &flags);
- BUG_ON(p->state != TASK_RUNNING);
- update_rq_clock(rq);
-
- if (!p->sched_class->task_new || !current->se.on_rq) {
- activate_task(rq, p, 0);
- } else {
-
-
-
-
- p->sched_class->task_new(rq, p);
- inc_nr_running(rq);
- }
- trace_sched_wakeup_new(rq, p, 1);
-
-
- check_preempt_curr(rq, p, WF_FORK);
- #ifdef CONFIG_SMP
- if (p->sched_class->task_wake_up)
- p->sched_class->task_wake_up(rq, p);
- #endif
- task_rq_unlock(rq, &flags);
- }
对于copy_process函数比较繁琐,也是do_fork主要执行函数,完成进程资源的复制,根据相关的标志位,有的资源需要和父进程共享,具体下一篇我们会看到。
阅读(676) | 评论(0) | 转发(0) |