进程的描述和进程的创建
进程的描述和进程的创建
20135109 高艺桐
《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
一、进程的描述
1、1进程描述符task_struck数据结构(一)
(1)操作系统的三大功能:进程管理、内存管理、文件系统。
(2)
进程控制块PCB——task_struck
tty_struck控制台
fs_struck文件系统的描述
files_struck打开的文件描述符
mm_struck内存的描述
signal_struck信号的描述
(3)操作系统原理中的状态:就绪态、运行态、阻塞态
(4)
内核管理中的进程状态:
TASK_TUNNING(可运行)获得cpu控制权正在运行,被调度出去就是就绪态。
TASK_ZOMBIE(进程被终止)
TASK_interruotibie(阻塞态)
TASK_uninterruotibie(阻塞态)
(5)进程的标示符:pid(用来标识进程)
1、2进程描述符task_struck数据结构(二)
(1)state运行状态(指定进程状态)
(2)SMP条件编译(多处理器时会用到)
(3)
struct list_head tasks进程的链表,双向循环链表连接,链表可独立进行操作
(4)每个进程有自己独立的地址空间,32位x86有4G进程地址空间。
(5)pid_t pid标识一个进程
(6)
进程的父子关系:兄弟父子之间的关系通过双向链表连接起来。
(7)CPU相关的状态:thread_struct(sp、ip)进程上下文切换时期关键作用
(8)struct files_struct*files打开文件列表
(9)struck signal_struct *signal信号处理相关工作
二、进程的创建过程
2、1进程的创建概览及fork一个进程的用户态代码
(1)(文件系统、信号、内存)进程描述符中有相应的指针指向其内容,进行研究。
(2)
进程是怎么创建的:复制一份进程描述符,0号进程用代码写死,1号进程复制0号进程pcb,根据1号进程需要修改pid,最后加一个init可执行程序。
(3)
子进程从哪里开始执行:shell命令行怎么创建子进程的?
fork()用户态进行创建子进程
fork系统调用在父进程和子进程各返回一次
(4)fork在子进程中返回值是父进程的ID
2、2理解进程创建过程复杂代码的方法
(1)系统调用再回顾:
Int0x80是中断指令,把用户态堆栈转化到内核态堆栈,把CPU最关键的现场eip、esp保存到内核堆栈中去。
(2)
子进程从哪里开始执行:fork()出的子进程在内核中开始返回。创建一个进程的框架:复制一份进程描述符,0号进程用代码写死,1号进程复制0号进程pcb,根据1号进程需要修改pid,最后加一个init可执行程序。
(3)创建进程过程中要做哪些事情:修改pcb,建立链表,修改分配内核堆栈,保存进程执行到哪个位置,保存sp、ip(避免发生混乱),需要有thread设定eip和esp位置。
2、3浏览进程的创建过程相关的关键方法
(1)
创建新进程在内核中执行的过程:
复制一个PCB——task_struct
给新进程分配一个新的内核堆栈
更改复制过来的进程数据,比如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的内容。
2、4创建的新进程是从哪里开始执行的
(1)子进程从哪里开始执行的:ret_from_fork
(2)
Int指令和SAVE_ALL压到内核栈的内容。
(3)ret_from_fork 中的syscall_exit内核堆栈可正常返回到用户态(子进程的进程空间)。
2、5使用gdb跟踪创建新进程的过程
自己实验截图:
(1)把menu删除,克隆一份新的,把test_fork.c覆盖掉,编译内核,可以看到fork命令
(2)设置断点sys_clone,设置断点do_fork,设置断点dup_task_struck,设置断点copy_process,设置断点copy_thread,设置断点ret_from_fork
(3)在MenuOS中执行fork,就会发现fork函数停在了父进程中
(4)继续执行之后,停在了do_fork的位置
(5)按s进入该函数,可以看到dst = src(也就是复制父进程的struct)
(6)按n继续追踪
(7)在copy_thread中,可以看到把task_pg_regs(p)也就是内核堆栈特定的地址找到并初始化
三、实验总结
通过本周的学习,我了解到了Linux通过clone()系统调用实现fork(),fork(),vfork(),和clone()库函数都是根据各自需要的参数标志去调用clone(),然后由clone()调用do_fork,其中do_fork函数调用了copy_process()函数,然后让进程执行 Linux通过复制父进程创建新进程,fork、vfork、clone都是通过do_exit实现进程的创建。
创建新进程的过程为:复制一个PCB——task_struct,给新进程分配一个新的内核堆栈,更改复制过来的进程数据,比如pid,进程链表等。子进程从ret_from_fork开始执行。