深入理解Linux之do_fork()

本文深入解析了Linux系统中进程复制的核心函数do_fork()的工作原理,包括如何为子进程分配PID、设置跟踪标志、复制进程描述符等关键步骤。同时介绍了do_fork()函数的各个参数的作用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

clone(), fork(), vfork() 最终都是调用 do_fork()来实现的。 do_fork()在Kernel\fork.c文件中。代码如下:

/*
 *  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;
	long pid = alloc_pidmap(); //通过pidmap_array位图,为子进程分配新的PID

	if (pid < 0)
		return -EAGAIN;
	if (unlikely(current->ptrace)) {   //检测父进程是否被跟踪,并设置子进程的跟踪
		trace = fork_traceflag (clone_flags);
		if (trace)
			clone_flags |= CLONE_PTRACE;
	}
                //最关键的一步,复制进程描述符。如果成功,则返回刚刚创建的task_struct描述符地址。下一篇博客会详细介绍
	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)) {   //设置了COLNE_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))    //没有设置COLNE_STOPPED
			wake_up_new_task(p, clone_flags); //把子进程插入父进程的运行队列
		else
			p->state = TASK_STOPPED;  //将子进程的进程描述符中的状态设置为  stopped
		++total_forks;

		if (unlikely (trace)) {          //还是设置子进程是否被跟踪。
			current->ptrace_message = pid;
			ptrace_notify ((trace << 8) | SIGTRAP);
		}

		if (clone_flags & CLONE_VFORK) {    //如果设置了CLONE_VFORK标志,则把父进程插入到等待队列,并挂起父进程,直到子进程释放自己的内存空间
			wait_for_completion(&vfork);           //也就是说,直到子进程结束或执行新的程序。
			if (unlikely (current->ptrace & PT_TRACE_VFORK_DONE))
				ptrace_notify ((PTRACE_EVENT_VFORK_DONE << 8) | SIGTRAP);
		}
	} else {
		free_pidmap(pid);
		pid = PTR_ERR(p);
	}
	return pid;
}


参数:clone   包含了很多的信息,如:是否共享内存描述符和页表,是否共享打开的文件表,是否调用vfork(),是否和父进程一样被跟踪。

参数:stack_start  是

参数:regs  是指向通用寄存器值的指针,通用寄存器的只是从用户态切换到内核态时被保存到内核态堆栈的。 个人感觉,就是TSS。

参数:stack_size   未使用

参数:parent_tidptr  是父进程的用户态变量地址

参数:child_tidptr   是子进程的用户态变量地址

CLONE_PTRACE 是clone_flag中的一个标志位,表示如果父进程被跟踪,那么子进程也被跟踪。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值