find_new_reaper

如果父进程在子进程之前退出,必须有机制来保证子进程能找到一个新的父亲,否则这些成为孤儿的进程就会在退出时永远处于僵死状态,白白地耗费内存。对于这个问题,解决方法是给子进程在当前线程组内找一个线程作为父亲,如果不行,就让init做它们的父进程。在do_exit()中会调用exit_notify(),该函数会调用forget_original_parent(),而后者会调用find_new_reaper()来执行寻父过程:

/*
 * When we die, we re-parent all our children.
 * Try to give them to another thread in our thread
 * group, and if no such member exists, give it to
 * the child reaper process (ie "init") in our pid
 * space.
 */
static struct task_struct *find_new_reaper(struct task_struct *father)
{
	struct pid_namespace *pid_ns = task_active_pid_ns(father);
	struct task_struct *thread;

	thread = father;
	while_each_thread(father, thread) {
		//遍历该结束的进程所在线程组的下一个进程
		if (thread->flags & PF_EXITING)//如果得到的下一个进程被标记了 PF_EXITING ,就不符合要求,需要继续遍历
			continue;
		if (unlikely(pid_ns->child_reaper == father))
			/*
			child_reaper 表示进程结束后,需要这个child_reaper指向的进程对这个结束的进程进行托管,
			其中的一个目的是对孤儿进程进行回收。
			若该托管进程是该结束进程本身,就需要重新设置托管进程,
			设置为该结束进程所在线程组的下一个符合要求的进程即可。
			*/
			pid_ns->child_reaper = thread;
		return thread;//在该结束进程所在的线程组中找到符合要求的进程,返回即可
	}

	/*
	如果该结束进程所在的线程组中没有其他的进程,
	函数就返回该结束进程所在命名空间的 child_reaper 指向的托管进程
	(前提是该托管进程不是该结束进程本身)
	*/
	if (unlikely(pid_ns->child_reaper == father)) {
		/*
		如果该结束进程所在命名空间的 child_reaper 指向的托管进程就是该结束进程本身,
		而程序运行至此,说明在该线程组中已经找不到符合要求的进程,
		此时,需要将托管进程设置为 init 进程,供函数返回
		*/
		write_unlock_irq(&tasklist_lock);
		if (unlikely(pid_ns == &init_pid_ns))
			panic("Attempted to kill init!");

		zap_pid_ns_processes(pid_ns);
		write_lock_irq(&tasklist_lock);
		/*
		 * We can not clear ->child_reaper or leave it alone.
		 * There may by stealth EXIT_DEAD tasks on ->children,
		 * forget_original_parent() must move them somewhere.
		 */
		pid_ns->child_reaper = init_pid_ns.child_reaper;
	}

	return pid_ns->child_reaper;
}

总结一下,在 find_new_reaper 中有可能返回以下3种进程作为新父进程:

1、原结束进程所在线程组中的一个符合要求的进程

2、原结束进程所在进程命名空间中 child_reaper指向的托管进程

3、init进程


现在,给子进程找到合适的新父进程了,只需要遍历所有的子进程并为他们设置新的父进程

reaper = find_new_reaper(father);

	list_for_each_entry_safe(p, n, &father->children, sibling) {
		p->real_parent = reaper;
		if (p->parent == father) {
			BUG_ON(task_ptrace(p));
			p->parent = p->real_parent;
		}
		reparent_thread(father, p, &dead_children);
	}


你可能感兴趣的:(find_new_reaper)