陈涛 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ”
一、实验
首先,进入实验楼环境,进入LinueKernel文件。
然后,删除menu,clone一份新的,再将test.c覆盖为fork.c,make rootfs。
进入menuOS,实现fork函数功能。
请来大小S,进行设置断点:sys_clone, do_fork, dup_task_struct, copy_process, copy_thread进行调试。
跟踪分析一个fork系统调用内核处理函数sys_clone,结束实验。
二、进程分析
一、task_struct数据结构
1.task_struct结构:
struct task_struct{
volatile long state; 进程状态
void stack; 堆栈*
pid_t pid; 进程标识符
unsigned int rt_priority; 实时优先级
unsigned int policy; 调度策略
struct files_struct files; 系统打开文件*
…
}
二、进程的创建
在Linux应用程序的开发中,可以通过fork、vfork和clone等API来创建一个子进程,它们在Linux内核中对应的系统调用分别为sys_fork、sys_vfork和sys_clone函数,而这些函数最终都会调用do_fork完成子进程的创建。do_fork主要是复制了父进程的task_struct,然后修改必要的信息,从而得到子进程的task_struct。主要修改了以下信息:
(1)pid,进程链表等
(2)系统调用内核处理函数:sys_fork、sys_clone、sys_vfork
(3)do_fork()中包含的copy process创建一个进程内容的主要代码
(4)arch dup_task_struct复制整个PCB(dst=src数据结构的值复制给dst)
(5)thread_info内核堆栈,创建一个页面,比较大(分配内核堆栈空间)
(6)p指向子进程的描述符
(7)copy_thread从子进程的pid找到了栈底的地址,把sp赋值过去,对父进程的栈底进行拷贝,包括栈顶数据,thread ip的内容。
三、子进程运行
ret_from_fork决定了新进程的第一条指令地址。p->thread.ip = (unsigned long) ret_from_fork;将子进程的ip设置为ret_from_fork的首地址。从用户态代码来看,fork()函数返回了两次,即在父子进程中各返回一次!但是子进程的返回值是0,从返回值我们就可以判断出返回后接下来要执行的代码是中父进程还是子进程中。