do_fork函数

18 篇文章 1 订阅
8 篇文章 0 订阅

do_fork函数

在内核中创建并执行新的程序的各种系统调用最终都是调用了do_fork来实现进程的创建。

asmlinkage int sys_fork(unsigned long r4, unsigned long r5,
            unsigned long r6, unsigned long r7,
            struct pt_regs __regs)
{
#ifdef CONFIG_MMU
    struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
    return do_fork(SIGCHLD, regs->regs[15], regs, 0, NULL, NULL);
#else
    /* fork almost works, enough to trick you into looking elsewhere :-( */
    return -EINVAL;
#endif
}
asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp,
             unsigned long parent_tidptr,
             unsigned long child_tidptr,
             struct pt_regs __regs)
{
    struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
    if (!newsp)
        newsp = regs->regs[15];
    return do_fork(clone_flags, newsp, regs, 0,
            (int __user *)parent_tidptr,
            (int __user *)child_tidptr);
}
asmlinkage int sys_vfork(unsigned long r4, unsigned long r5,
             unsigned long r6, unsigned long r7,
             struct pt_regs __regs)
{
    struct pt_regs *regs = RELOC_HIDE(&__regs, 0);
    return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->regs[15], regs,
               0, NULL, NULL);
}

以上几个创建进程的系统调用最终都调用 do_fork 来实现; do_fork函数的具体代码如下:

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;
	}

	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 = 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) {
			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;
}

do_fork() 函数生成一个新的进程,大致分为三个步骤。

1、建立进程控制结构并赋初值,使其成为进程映像。
2、为新进程的执行设置跟踪进程执行情况的相关内核数据结构。包括 任务数组、自由时间列表 tarray_freelist 以及 pidhash[] 数组。
3、启动调度程序,使子进程获得运行的机会。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值