Hello World 6
来源:互联网 发布:log4j.xml配置显示sql 编辑:程序博客网 时间:2024/05/20 11:47
本文装载自: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(¤t->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);} elserelease(p);/* 释放进程的内存中的结构 */...}}...end_wait4:/* 结束函数sys_wait4 */remove_wait_queue(¤t->wait_chldexit,&wait);return retval;}
显然在sys_wait4函数中实现了将进程的内存结构消除。
到现在为止,hello world程序最终完成了一个简单的printf ("hello world\\n");的使命,挂掉了。那么linux中程序(或者说是进程)的完整生命周期就是这样的。
终于hello world完了。。。
- 深入浅出Hello World 6
- Hello World 6
- Hello World!【Hello World】
- Hello, world!
- Hello World!
- Hello world!
- Hello World!
- Hello World!
- hello world!
- Hello World !
- Hello,World!
- Hello World!
- Hello world!
- Hello World!
- Hello World
- Hello World
- Hello world
- Hello World!
- Hello World 5
- JQ也要面向对象~在JQ中扩展静态方法和实例方法
- Export runnable jar in Eclipse.
- Oracle中的select for update
- 猴子吃桃
- Hello World 6
- C语言二进制文件和文本文件的区别
- Hibernate读书笔记-----HQL查询
- 数学之路(2)-数据分析-R基础(16)
- poj 2096 Collecting Bugs
- 优秀的程序 vs. 糟糕的程序
- Java_集合_Arrays工具类
- Setting property 'source' to 'org.eclipse.jst.jee.server:webProject' did not find a matching propert
- 兔子问题