2008年11月18日星期二

父进程和子进程

父进程和子进程
一、子进程的创建
进程创建方式有三种:fork,clone,vfork。fork用于普通进程的创建,采用Copy on Write方式;vfork是完全共享的创建;clone界于两者之间,创建方式比较灵活。真正创建进程的是函数int do_fork(unsigned long clone_flags,unsigned long usp,struct pt_regs *regs)。这里只讲fork方式的创建。
#include
pid_t fork(void);
该函数负责创建一个子进程,它将子进程的tsk_struct中exit_signal域的值设为SIGCHLD。
创建子进程的代码模式为:
...
if((chld_pid = fork() < 0)){ /** Create the child process by fork() */
/** Error has occured,no child process is created.For details,see 'errno'. */
}else if(chld_pid == 0){
/** Returned in the child.So it is child process code here. */
}else if(chld_pid > 0){
/** Returned in the parent process.So it is parent process code here. */
}
...
二、子进程的死亡
进程终止的大致过程为:子进程调用exit函数将自身设为僵死状态并退出;父进程调用wait函数处理处于僵死状态的子进程,将其从内存中彻底清除。

1、exit函数
exit函数调用内核函数sys_exit,而sys_exit则直接调用do_exit函数。所以真正完成exit工作的是函数do_exit。
do_exit函数的原型为
NORET_TYPE void do_exit(long code)
code是进程的退出代码。
do_exit所做的工作为:
1)取出当前进程
2)如果当前进程在中断处理程序中,则不可终止
3)如果当前进程为0号进程(init_task)则不可终止
4)设置进程的标志为正在终止
tsk->flags |= PF_EXITING;
5)释放大部分资源(时钟队列、信号灯结构、虚拟内存空间、文件结构、文件系统结构、信号处理结构、退出线程)
6)设置进程的状态为僵死状态:
tsk->state = TASK_ZOMBIE;
7)设置退出代码:
tsk->exit_code = code;
8)向有关进程发送信号,通知它们自己要终止(exit_notify)。
9)调度调度函数schedule,放弃cpu。因为进程的当前状态为僵死状态,所以调度函数将其从运行队列中删除,进程不会再有运行的机会。

僵死进程的特点:进程永远不会再运行;但其task_struct结构还在内存中。
2、wait函数
父进程收到子进程终止信号后,调用wait函数处理僵死进程,真正完成这个工作的是函数sys_wait4。
该函数原型为
int sys_wait4(pid_t pid,unsigned int * stat_addr,int options,struct rusage * ru)
sys_wait4的工作为:
1)如果能够找到満足条件的僵死子进程,则将其释放,然后返回进程的pid。
2)如果能够找到満足要求的但并没有僵死,则或者立刻返回(options中设有标志WNOHANG或者有等待处理的其它信号);或者等待。
3)如果无法找到满足要求的则返回出错代码 -ECHLD。
task_struct结构的回收由函数release(struct task_struct *p)完成。

没有评论: