刘昆
+《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
UNIX及类UNIX体系中,父进程与子进程共享代码段,拥有独立的堆栈和数据段,那么子进程具体是如何由fork()创建及被父进程后又从哪里执行呢?
首先分析创建子进程的系统调用sys_fork
有的平台该系统调用不同,虽然是sys_clone,但最终仍然是通过do_fork()底层实现的,这个是和sys_fork(0一样的:
2#ifdef __ARCH_WANT_SYS_CLONE 1723#ifdef CONFIG_CLONE_BACKWARDS 1724SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp, 1725 int __user *, parent_tidptr, 1726 int, tls_val, 1727 int __user *, child_tidptr) 1728#elif defined(CONFIG_CLONE_BACKWARDS2) 1729SYSCALL_DEFINE5(clone, unsigned long, newsp, unsigned long, clone_flags, 1730 int __user *, parent_tidptr, 1731 int __user *, child_tidptr, 1732 int, tls_val) 1733#elif defined(CONFIG_CLONE_BACKWARDS3) 1734SYSCALL_DEFINE6(clone, unsigned long, clone_flags, unsigned long, newsp, 1735 int, stack_size, 1736 int __user *, parent_tidptr, 1737 int __user *, child_tidptr, 1738 int, tls_val) 1739#else 1740SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp, 1741 int __user *, parent_tidptr, 1742 int __user *, child_tidptr, 1743 int, tls_val) 1744#endif 1745{ 1746 return do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr); 1747} 1748#endif
下面分析do_fork()的实现过程
首先看看源码
do_fork()代码入口
整个父进程执行do_fork()的过程,就是对struct task_struct结构体数据操作的过程。
struct task_struct 是所有进程描述信息的结构体链表中的世界信息载体,系统对进程调度等操作,都是通过维护该链表实现。
创建一个子进程,对于系统,就是创建一个新的进程,一个新的struct task_struct数据信息。
copy_process(clone_flags, stack_start, stack_size,child_tidptr, NULL, trace);完成了子进程相关struct task_struct数据的创建和初始化工作
copy_process代码入口
copy_process的工作除了完成了子进程复制父进程的struxt task_struct数据信息,还会修改每一个进程独一无二的描述信息,如PID.real_start_time等
其中,父进程在这个函数中完成子进程的创建,子进程首次开始执行的入口由该函数中的copy_thread函数知名;
copy_thread代码入口
copy_thread创建了子进程的内核堆栈,并指明了首次执行的的EIP:指令的跳转入口
p->thread.ip = (unsigned long) ret_from_fork;
当系统进程调度到该子进程时,该子进程从ret_from_fork:开始执行