现在的位置: 首页 > 综合 > 正文

Hello World 6

2013年08月02日 ⁄ 综合 ⁄ 共 3469字 ⁄ 字号 评论关闭

本文装载自:http://www.cnblogs.com/xuqiang/archive/2010/03/29/1953689.html

微笑

卸载hello程序

现在再来看看我们的Hello World程序:

#include <stdio.h>

int main ()
{

printf ("hello world\n");

return 0;

在进程运行结束后,我们会显示的调用exit()或者return退出正在运行的进程,如果调用return的话,编译器会自己加上exit().此时,保存子进程的一

部份信息是很有必要的,因为父进程可以读取这些消息而取得子进程的退出状态.如果子进程退出.但父进程没有用wait(),这就成为了我们常说的僵

尸进程,exit()系统调用在内核中的相应接口为sys_exit(),我们来跟踪一下,看下内核是如何处理这个过程的.

 

fastcall NORET_TYPE void do_exit(long code)

{

...

//不可以在中断上下文或者是0号进程使用该函数

         if (unlikely(in_interrupt()))

                   panic("Aiee, killing interrupt handler!");

         if (unlikely(!tsk->pid))

                   panic("Attempted to kill the idle task!");

  ...

 //设置PF_EXITING:表示进程正在退出

         tsk->flags |= PF_EXITING;

 

...

 

 //退出状态码

         tsk->exit_code = code;

         taskstats_exit(tsk, group_dead);

 

         //退出进程所占用的空间

         exit_mm(tsk);

 

         if (group_dead)

                   acct_process();

         //从进程的信号从IPC队列中删除

         exit_sem(tsk);

         //

         __exit_files(tsk);

         //关闭打开的文件

         __exit_fs(tsk);

         check_stack_usage();

         exit_thread();

         cgroup_exit(tsk, 1);

         exit_keys(tsk);

 

         //进程组全部退出且当前进程是进程组的组长

         if (group_dead && tsk->signal->leader)

                   //脱离当前的tty 并向进程显示终端的组发送SIGHUP 和SIGCONT

                   disassociate_ctty(1);

 

 

         //减少模块的引用计数

         module_put(task_thread_info(tsk)->exec_domain->module);

         if (tsk->binfmt)

                   module_put(tsk->binfmt->module);

 

         proc_exit_connector(tsk);

         //更新进程的亲属关系.并给父进程发送相应的信号

         exit_notify(tsk);

 

...

 //进程退出已经完成了,设置PF_EXITPIDONE

         tsk->flags |= PF_EXITPIDONE;

 

...

//设置进程的状态为TASK_DEAD

         tsk->state = TASK_DEAD;

 

         //调度另一个进程运行

         schedule();

 

...

}

 

显然上面的函数首先做的是检查进程退出条件是否满足,然后结束和进程相关的资源,最后标记当前进程为TASK_DEAD,注意此时还没有将

task_struct删除。那么进程描述符什么时候被删除?

 

由于在linux中允许进程查询其父进程的状态,或者是任何子进程的状态,所以在某个进程执行完毕之后,不能马上将task_struct删除。只有当

父进程发出了wait系统调用之后才允许将task_struct结构从内存中删除。但是如果子进程在父进程之前结束那该怎么办?在linux中,将这样的子进程的父进程自动的设置成init进程。这时,在init进程中使用wait系统调用来结束这样的子进程。

 

 

下面参见《linux内核编程》

当子进程终止时,父进程收到内核发出的信号“SIGCHLD”,父进程可以在任何的事件地点来调用wait系统调用。可以采用:

pid_t wait(int* status)

pid_t waitpid (pid_t pid, int* status, int options)

pid_t wait3(int* status, int options, struct rusage* rusage)

pid_t wait4(pid_t pid, int* status, int options, struct rusage* rusage)

这些函数又调用sys_wait4。

asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru){
	...
	/* 参数有效? */
	if (options & ~(WNOHANG|WUNTRACED|__WCLONE))	    return -EINVAL;	/* 将进程加入到等待进程中 */	add_wait_queue(&current->wait_chldexit,&wait);repeat:	flag=0;	/* 首先初始化flag为0,在下面如果查找到参数pid和某个子进程的pid相同,更改pid */
	/* p_cptr是进程的子进程,p_osptr是进程的子进程兄弟进程 */ 	for (p = current->p_cptr ; p ; p = p->p_osptr) {		...		flag = 1;		switch (p->state) {		/* 找到这样的进程pid等于函数参数pid */			case TASK_STOPPED:	/* TASK_STOPPED进程进入睡眠状态,此时进程是可以被唤醒的 */				if (!p->exit_code)					continue;				if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED))					continue;				if (ru != NULL)					getrusage(p, RUSAGE_BOTH, ru);				if (stat_addr)					put_user((p->exit_code << 8) | 0x7f,						stat_addr);				p->exit_code = 0;				retval = p->pid;				goto end_wait4;			case TASK_ZOMBIE:		/* 进程处于TASK_ZOMBIE,此时需要收回task_struct */				current->cutime += p->utime + p->cutime;				current->cstime += p->stime + p->cstime;				if (ru != NULL)					getrusage(p, RUSAGE_BOTH, ru);				if (stat_addr)					put_user(p->exit_code, stat_addr);				retval = p->pid;				if (p->p_opptr != p->p_pptr) {					REMOVE_LINKS(p);					p->p_pptr = p->p_opptr;					SET_LINKS(p);					notify_parent(p);				} else					release(p);	/* 释放进程的内存中的结构 */			...		}	}	...end_wait4:	/* 结束函数sys_wait4 */	remove_wait_queue(&current->wait_chldexit,&wait);	return retval;}

显然在sys_wait4函数中实现了将进程的内存结构消除。

到现在为止,hello world程序最终完成了一个简单的printf ("hello world\\n");的使命,挂掉了。那么linux中程序(或者说是进程)的完整生命周期就是这样的。

终于hello world完了。。。

抱歉!评论已关闭.