伪代码说明Linux进程创建过程
以前单知道linux创建进程用的fork函数,深一点点知道是调用sys_fork系统调用来完成,前阵子看了 安全焦点process写得文章对这个过程的框架有了点点认识,记下来,以后再学到时把它更深入一成的研究。:)
Fork --> sys_fork() --> do_fork();这里倒是有点想exec族的系统调用,execve() -> sys_exec() -> do_exec().
下面我们开始吧。
sys_fork()
{
Sys_fork系统调用通过do_fork()函数实现,
do_fork()
{
通过对do_fork()函数传递不同的clone_flags来实现fork,clone,vfork
copy_process()
{
copy_process()函数完成了进程创建的绝大部分工作
dup_task_struct()
{
dup_task_struct()为进程创建一个新的内核堆栈,
完整复制task_struct和
thread_info结构这里只是完整的复制,进程描述符process
descriptor (struct task_struct)进程描述符与父进程的一样
(task_struct与父进程的一样)
创建内核堆栈和和task_struct结构空间
tsk = alloc_task_struct();
复制整个进程描述符(复制整个task_struct结构)
*tsk = *orig;
复制thread_info结构
setup_thread_struct(tsk, org);
}//end dup_task_struct()
rlim[rLIMIT_NPROC]限制用户可以拥有的进程数
capble()对权限进行检查
更新task_struct结构的flags成员
...
对子进程的task_struct进行初始化
...
获得新的pid
...
复制其他资源
if ((retval = security_task_alloc(p)))
goto bad_fork_cleanup_policy;
if ((retval = audit_alloc(p)))
goto bad_fork_cleanup_security;
/* copy all the process information */
if ((retval = copy_semundo(clone_flags, p)))
goto bad_fork_cleanup_audit;
if ((retval = copy_files(clone_flags, p)))
goto bad_fork_cleanup_semundo;
//pr0cess大侠把copy_files()举例出来了
copy_files()
{
...
newf = dup_fd(oldf, &error){
newf = alloc_files(){
//调用kmem_cache_alloc()来为子进程分配file_struct
...
接着设置file_struct结构的count成员
alloc_files()中把oldf的内容copy到newf中
}//end alloc_files
}//end dup_fd()
}//end copy_files()
if ((retval = copy_fs(clone_flags, p)))
goto bad_fork_cleanup_files;
if ((retval = copy_sighand(clone_flags, p)))
goto bad_fork_cleanup_fs;
if ((retval = copy_signal(clone_flags, p)))
goto bad_fork_cleanup_sighand;
if ((retval = copy_mm(clone_flags, p)))
goto bad_fork_cleanup_signal;
if ((retval = copy_keys(clone_flags, p)))
goto bad_fork_cleanup_mm;
if ((retval = copy_namespaces(clone_flags, p)))
goto bad_fork_cleanup_keys;
retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
if (retval)
goto bad_fork_cleanup_namespaces;
copy_thread(){
...
复制父进程系统空间堆栈,堆栈中有完整的路线指明父进程通过
//系统调用进入内核空间的过程
//子进程推出时需要按照完整的路线返回
}//end copy_thread()
//now return copy_process()
设置子进程退出时要像父进程发送信号
将子进程联入进程队列等待被唤醒
}//end copy_process()
唤醒子进程并开始运行,所以为什么说fork是调用一次返回两次
一次是父进程,一次是子进程
}//end do_fork()
}//end sys_fork()
这是我的读书笔记,主要是读安全焦点的这篇文章:
Referrence”
《Linux Kernl Development》
2.6.22 的源码
《Linux2.6内核进程创建过程分析》安全焦点