10/09/2006

进程的一生

[进程的一生]
一.fork
之后将讲述的线程也完全一样使用do_fork函数生成。只是在于调用这个函数时传递的参数不同。

do_fork(flag,进程上下文)
分配一个空的task_struct(alloc_task_struct函数)
分配一个进程ID(get_pid函数)
初始化task_struct结构体的各个成员
复制文件描述符表(copy_files函数)
当前目录,umask等的复制(copy_fs函数)
复制信号情报(copy_sighand函数)
父进程上下文的复制(copy_thread函数)
使用Copy-On-Write复制虚拟内存空间(copy_mm函数)
将生成的子进程链接入RUNQ(wake_up_process函数)

二.exec
进程可使用exec系统调用执行新的命令。exec系统调用将一次性释放全部虚拟内存空间,之后生成新的空间并将新的命令映射入内。

do_execve(文件路径,参数。环境)
打开文件(open_namei函数)
计算exec后的UID/GID,读入文件头(prepare_binprm函数)
读入命令名,环境变量,启动参数(copy_strings函数)
调用各种不同二进制文件的操作函数(search_binary_handler函数)

ELF格式的话,经由search_binary_handler函数调用load_elf_binary函数。如果是动态链接,同时映射动态链接器(ld*.so)

load_elf_binary(linux_binprm* bprm,pt_regs* regs)

分析ELF文件头
读入程序的头部分(kernel_read函数)
if(存在解释器头部)
{
读入解释器名(ld*.so)(kernel_read函数) |(zalem note:可用
打开解释器文件(open_exec函数) | objdump -s -j .interp xxx
读入解释器文件的头部(kernel_read函数) | 命令查看,
| linux下是/lib/ld-linux.so.x)
}

释放空间,清除信号,关闭指定了close-on-exec标识的文件(flush_old_exec函数)
生成堆栈空间,塞入环境变量/参数部分(setup_arg_pages函数)
for(可引导的所有的程序头)
{
将文件映射入内存空间(elf_map,do_mmap 函数)
}

if(为动态链接)
{
映射动态链接器(load_elf_interp函数)
}

释放文件(sys_close函数)
确定执行中的UID,GID(compute_creds函数)
生成bss领域(set_brk函数)
bss领域清零(padzero函数)
设定从exec返回时的IP,SP(start_thread函数)(动态链接时的IP指向解释器的入口)

三.exit

进程的结束由do_exit函数进行。除显式调用exit系统函数外,接受到信号而终止的情况下也被调用。do_exit函数释放除task_struct结构体外的所有资源。do_exit使用exit_notify函数向父进程发送SIGCHLD信号。接受到SIGCHLD函数的父进程找出成为ZOMBIE状态的子进程,释放其task_struct.

do_exit(终止号)
{
停止此进程的计时器(del_timer_sync函数)
释放IPC信号灯(sem_exit函数)
释放虚拟空间(__exit_mm函数)
关闭文件及释放管理空间(__exit_files函数)
释放当前目录,umask情报(__exit_fs函数)
抛弃信号及管理领域的释放(__exit_sighand函数)
将进程状态设为TASK_ZOMBIE
通知父进程(exit_notify函数)
放弃CPU(schedule函数)
}


父进程使用下面的release函数释放成为了ZOMBIE的task_struct结构体。

release(ZOMBIE的子进程)
释放PID(unhash_process函数)
释放task_struct(free_task_struct函数)

没有评论: