用户进程的退出和等待
退出
在进程执行完工作后,需要退出,释放资源,正我们在do_execve
函数末尾看到的一样,退出进程是调用do_exit
函数来实现的。
如果是内核线程则不需要回收空间
如果是用户进程,就开始回收,首先执行
lcr3(boot_cr3);
切换到内核的页表上,这样用户进程就只能在内核的虚拟地址空间上执行,因为内核权限高。如果当前进程的被调用数减一后等于0,那么就没有其他进程在使用了,就可以进行回收,先回收内存资源,调用exit_mmap
函数释放mm
中的vma
描述的进程合法空间中实际分配的内存,然后把对应的页表项内容清空,最后把页表项和页目录表清空。然后调用put_pgdir
函数释放页目录表所占用的内存。最后调用mm_destroy
释放vma
与mm
的内存。把mm
置为NULL,表示与当前进程相关的用户虚拟内存空间和对应的内存管 理成员变量所占的内核虚拟内存空间已经回收完毕;设置进程的状态为
PROC_ZOMBIE
表示该进程要死了,等待父进程来回收资源,回收内核栈和进程控制块。当前进程的退出码为error_code
表示该进程已经不能被调度。如果当前进程的父进程处于等待子进程的状态,则唤醒父进程让父进程回收资源。
如果该进程还有子进程,那么就指向第一个孩子,把后面的孩子全部置为空,然后把孩子过继给内核线程
initproc
,把子进程插入到initproc
的孩子链表中,如果某个子进程的状态时要死的状态,并且initproc
的状态时等待孩子的状态,则唤醒initproc
来回收子进程的资源。然后开启中断,执行
schedule
函数,选择新的进程执行
等待
那么父进程如何完成对子进程的最后回收工作呢?这要求父进程要执行wait
用户函数或wait_pid
用户函数,这两个函数的区别是,wait
函数等待任意子进程的结束通知,而wait_pid
函数等待进程id号为pid的子进程结束通知。这两个函数最终访问sys_wait
系统调用接口让ucore来完成对子进程的最后回收工作,即回收子进程的内核栈和进程控制块所占内存空间,具体流程如下:
首先进行检查
若
pid
等于0,就去找对应的孩子进程,否则就任意的一个快死的孩子进程。如果此子进程的执行状态不为PROC_ZOMBIE
,表明此子进程还没有退出,则当前进程只 好设置自己的执行状态为PROC_SLEEPING
,睡眠原因为WT_CHILD
(即等待子进程退 出),调用schedule()
函数选择新的进程执行,自己睡眠等待,如果被唤醒,则重复该步骤执行;如果此子进程的执行状态为
PROC_ZOMBIE
,表明此子进程处于退出状态,需要当前进程 (即子进程的父进程)完成对子进程的最终回收工作,即首先把子进程控制块从两个进程队列proc_list
和hash_list
中删除,并释放子进程的内核堆栈和进程控制块。自此,子进程才彻底 地结束了它的执行过程,消除了它所占用的所有资源。
最后更新于