分类: LINUX
2008-05-02 11:55:55
今天完成了我Linux进程学习计划中的最后一个内容:进程的终止。
先了解一下当我们或者系统终止一个进程的时候,Linux0.11内核是怎么处理的。当我们在程序中要退出这个程序的时候,会直接或者间接的调用exit()这个C库函数,这个库函数实际上执行linux中sys_exit()的系统调用,这个系统调用会调用内核的do_exit()函数完成大部分资源的释放、与此进程相关进程的处理,将此进程置成僵死状态,最后向父进程发送进程终止信号,并执行进程的调度;当这个父进程在某个时候系统调用返回的时候,会发现自己收到了进程终止的信号,就会释放这个子进程的进程数据结构,完成进程的完全释放。当然,父进程如果调用了waitpid()函数,也会完成子进程的完全释放。下面我就具体说一下do_exit()的具体工作过程:
1) 释放代码段和数据段所占的内存。
2) 处理其子进程:将子进程的父进程改为init进程,并判断如果子进程已经处于僵死状态,则向init进程(这些进程的新父进程)发送子进程终止信号。也就是说。
3) 释放pwd、root、i节点。
4) 如果当前进程是会话头:释放终端;挂起该会话中的进程。
5) 将当前进程置为僵死状态。
6) 向父进程发送子进程终止信号。
7) 执行schedule()
在这里涉及到了两个函数,一个是6)中向父进程发送子进程终止信号的函数:tell_father();另一个是4)中挂起会话中进程的函数:kill_session()。Tell_father()函数做的就是将当前进程的父进程的信号中的sigchld(子进程终止信号)位置位。Kill_session()做的就是,扫描系统的所有任务,如果哪个任务的session与当前进程的session相同,就将这个进程的的sighup信号位置位。
在这里我还要介绍一下也是与进程释放相关的系统调用:waitpid()。这个函数的主要功能是挂起当前进程,直到它所等待的进程终止或者僵死了,或者它需要调用某个信号句柄。它的参数pid指明了它等待的进程号,这个进程号不但可以指定哪个进程,还可以指定某些进程。大体工作过程是这样的:
1) 扫描系统的任务数组,当发现与传入的pid与扫描到的进程相符(不一定相同)的时候,就会做一下处理:
判断这进程的状态,如果是停止转状态,再根据传入的另一个参数option判断是立即返回还是继续扫描;如果是僵死状态,就释放该进程的任务数据结构task_struct;
2)如果扫描结束后,发现等待的进程没有处在停止或者僵死状态的,就根据option判断是返回还是继续等待。如果是继续等待则做一下工作:将此进程置位可中断的睡眠状态,并执行进程调度程序shedule(),在schedulue之后是当此进程被重新执行的时候的处理:如果自己除了sigchld这外没收到其它信号(是否需要调度信号处理句柄),就转向开头进行再一次的扫描,如果发现此时收到了信号,就返回系统调用中断出错码,用户针对这个出错号应该再继续调用本函数。
以上就是我对今晨终止的理解。至此,我对Linux0.11核进程部分的学习告一段落了,下面我打算开始内存管理的学习。