冬天OS(三十四):内存管理 - exit & wait

--------------------------------------------------------

exit & wait

--------------------------------------------------------

 

·fs_exit 函数
PRIVATE int fs_exit()
{
	int i;
	struct proc *p = &proc_table[fs_msg.PID]; /* 请求退出的那个进程 */
	for (i = 0; i < NR_FILES; i++)
	{
		if (p->filp[i])
		{
			/* release the inode */
			p->filp[i]->fd_inode->i_cnt--;
			/* release the file desc slot */
			if (--p->filp[i]->fd_cnt == 0) /* 说明此进程是最后一个引用此文件的进程了 */
				p->filp[i]->fd_inode = 0;
			p->filp[i] = 0;
		}
	}
	return 0;
}

——fs_exit 做的工作和 fs_open 相同!

 

·do_exit 函数
PUBLIC void do_exit(int status)
{
	int i;
	int pid = mm_msg.source;				   /* PID of caller */
	int parent_pid = proc_table[pid].p_parent; /* 获得发 exit 消息进程的 parent */
	struct proc *p = &proc_table[pid];

	/* tell FS, see fs_exit() */
	MESSAGE msg2fs;
	msg2fs.type = EXIT;
	msg2fs.PID = pid;
	send_recv(BOTH, TASK_FS, &msg2fs);

	// 进程表对应的就是这段内存,如果进程表设置为了空闲
	// 那么这段内存就可以被覆盖
	free_mem(pid);

	p->exit_status = status;

	if (proc_table[parent_pid].p_flags & WAITING) /* 父进程在等 */
	{
		proc_table[parent_pid].p_flags &= ~WAITING;
		cleanup(&proc_table[pid]);
	}
	else
		proc_table[pid].p_flags |= HANGING; /* 父进程没有 wait ,就将自己设置为 hanging */

	/* 要退出的进程还有子进程 */
	for (i = 0; i < NR_TASKS + NR_PROCS; i++)
	{
		if (proc_table[i].p_parent == pid)
		{ /* is a child */
			proc_table[i].p_parent = INIT;
			if ((proc_table[INIT].p_flags & WAITING) &&
				(proc_table[i].p_flags & HANGING))
			{
				proc_table[INIT].p_flags &= ~WAITING;
				cleanup(&proc_table[i]); /* 这里是唤醒 INIT 进程 */
			}
		}
	}
}

——函数流程:
首先判断父进程是否在等自己,如果父进程在等自己,那么唤醒父进程,清除自己,很到位 ... 如果父进程没有在等,那么将自己设置为 hanging ,此时父进程的子进程中多了一个 hanging 的进程,当下次父进程调用 wait 的时候,会直接清除此 hanging 的进程并对那次 wait 直接返回!如果父进程不再调用 wait,那么会在父进程调用 exit 的时候将此 hanging 进程过继给 init 进程,init 在循环等待,所以遇见 hanging 进程直接清除并 init 进程继续循环 wait!
这是关于有没有父进程在等自己的问题,接着来看看如果要退出的此进程有孩子进程的情况,如果此进程有孩子,并且孩子在 hanging(这就是我们上面刚刚分析的因为这个孩子在 exit 的时候此进程并没有在 wait,所以孩子就将自己设置为了 hanging),那么就会将该孩子交给 INIT 进程,并且立即展开一次 【INIT 返回 & 清除此 hanging 进程】 的工作(因为在 INIT wait 的时候,遇见自己的孩子是 hanging,INIT 也会执行这一步)!如果此进程的孩子没有 hanging,那么将此孩子过继给 INIT 就行了,因为孩子没有 hanging,所以孩子是能够将来退出的,在孩子退出的时候,它唤醒的将是 INIT 父进程!
 

·do_wait 函数
PUBLIC void do_wait()
{
	int pid = mm_msg.source;

	int i;
	int children = 0;
	struct proc *p_proc = proc_table;
	/* 要进入等待的进程有 Hanging 的孩子 */
	for (i = 0; i < NR_TASKS + NR_PROCS; i++, p_proc++)
	{
		if (p_proc->p_parent == pid)
		{
			children++;
			if (p_proc->p_flags & HANGING) /* 调用 wait 的进程有孩子正在 hanging */
			{							   /* 则直接唤醒它并将它的孩子清除掉 */
				cleanup(p_proc);
				return;
			}
		}
	}

	if (children) /* 有孩子但是孩子没有 hanging,进入wait */
		proc_table[pid].p_flags |= WAITING;
	else
	{
		/* 没有孩子,直接返回· */
		MESSAGE msg;
		msg.type = SYSCALL_RET;
		msg.PID = NO_TASK;
		send_recv(SEND, pid, &msg);
	}
}

wait 函数就是分为三种情况:
1)如果有孩子在 hanging ,那么清除孩子并且此次 wait 返回
2)如果有孩子但是孩子正常运行,那么进入 wait 状态
3)如果没有孩子,直接返回!

 

·clean_up 函数
PRIVATE void cleanup(struct proc *proc)
{
	MESSAGE msg2parent;
	msg2parent.type = SYSCALL_RET;
	msg2parent.PID = proc2pid(proc);	   /* 子进程的 ID 号 */
	msg2parent.STATUS = proc->exit_status; /* 子进程的状态 */
	send_recv(SEND, proc->p_parent, &msg2parent);

	proc->p_flags = FREE_SLOT; /* ** */
}

cleanup 函数唤醒父进程并清除自己!

 

init 进程创建第一个进程之后就进入循环 wait 的状态:
 

while (1)
{
	int s;
	int child = wait(&s);
	printf("child (%d) exited with status: %d.\n", child, s);
}

运行

OK,关于 wait 和 exit 的问题我们就分析到这里!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柔弱胜刚强.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值