分析Linux内核创建一个新进程的过程
2017-04-02 16:53
295 查看
章强 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
struct task_struct数据结构很庞大:可以看到state进程状态,stack内核堆栈,flag进程标识符,CONFIG_SMP条件编译(多处理器用到)
进程的内存地址空间:
下图是抽象图:task进程链表管理,tty控制台,fs文件系统,files打开的文件描述符,mm内存管理描述,signal进程间通信信号
linux的进程状态与操作系统不同,就绪状态和运行状态都是TASK_RUNNING,fork创建好新进程变成就绪态,调度器选择了进程后变成运行态。
进程在TASK_RUNNING状态下表示其是可运行的,根据cpu是否实际执行该任务来划分是就绪态还是运行态。
正在运行进程调用do exit会变成task_zombie僵尸进程由系统处理掉
正在运行进程等待资源会进入阻塞态,可用时被唤醒进入就绪态。
进程pid
双向链表
程序创建的进程具有父子关系,在编程时往往需要引用这样的父子关系。进程描述符中有几个域用来表示这样的关系(都是通过双向链表来连接起来的)
内核处理过程
(1) do_fork
调用
调用
(2) copy_process
创建进程描述符以及子进程所需要的其他所有数据结构,为子进程准备运行环境
调用
复制所有的进程信息
调用
(3) dup_ task_ struct
先调用
调用
最后为子进程分配了内核栈空间。
执行完
(4) copy_thread
获取子进程寄存器信息的存放位置
对子进程的thread.sp赋值,将来子进程运行,这就是子进程的esp寄存器的值。
如果是创建内核线程,那么它的运行位置是
将父进程的寄存器信息复制给子进程。
将子进程的eax寄存器值设置为0,所以fork调用在子进程中的返回值为0.
子进程从
(5) 运行新进程:从ret_from_fork处开始执行
将
do_fork主要是复制了父进程的task_struct,然后修改必要的信息,从而得到子进程的task_struct。
刚fork出来的子进程是从ret_from_fork开始执行的,然后跳转到syscall_exit,从系统调用中返回。
在新窗口打开gdb
设置断点
最后跳转到syscall_exit
1. dup_task_struct中为其分配了新的堆栈。
2. 调用了sched_fork,将其置为TASK_RUNNING。
3. copy_thread中将父进程的寄存器上下文复制给子进程,保证了父子进程的堆栈信息是一致的。
4. 将ret_from_fork的地址设置为eip寄存器的值。
最终子进程从ret_from_fork开始执行。
进程描述
进程控制块PCB——task_struct,也叫进程描述符,为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息。struct task_struct数据结构很庞大:可以看到state进程状态,stack内核堆栈,flag进程标识符,CONFIG_SMP条件编译(多处理器用到)
进程的内存地址空间:
下图是抽象图:task进程链表管理,tty控制台,fs文件系统,files打开的文件描述符,mm内存管理描述,signal进程间通信信号
linux的进程状态与操作系统不同,就绪状态和运行状态都是TASK_RUNNING,fork创建好新进程变成就绪态,调度器选择了进程后变成运行态。
进程在TASK_RUNNING状态下表示其是可运行的,根据cpu是否实际执行该任务来划分是就绪态还是运行态。
正在运行进程调用do exit会变成task_zombie僵尸进程由系统处理掉
正在运行进程等待资源会进入阻塞态,可用时被唤醒进入就绪态。
进程pid
双向链表
程序创建的进程具有父子关系,在编程时往往需要引用这样的父子关系。进程描述符中有几个域用来表示这样的关系(都是通过双向链表来连接起来的)
内核处理过程
(1) do_fork
调用
copy_process,将当前进程复制一份出来给子进程,并且为子进程设置相应地上下文信息。
调用
wake_up_new_task,将子进程放入调度器的队列中,此时的子进程就可以被调度进程选中运行。
(2) copy_process
创建进程描述符以及子进程所需要的其他所有数据结构,为子进程准备运行环境
调用
dup_task_struct复制一份
task_struct结构体,作为子进程的进程描述符。
复制所有的进程信息
调用
copy_thread,设置子进程的堆栈信息,为子进程分配一个pid。
(3) dup_ task_ struct
先调用
alloc_task_struct_node分配一个
task_struct结构体。
调用
alloc_thread_info_node,分配了一个union。这里分配了一个
thread_info结构体,还分配了一个stack数组。返回值为ti,实际上就是栈底。
tsk->stack = ti将栈底的地址赋给task的stack变量。
最后为子进程分配了内核栈空间。
执行完
dup_task_struct之后,子进程和父进程的task结构体,除了stack指针之外,完全相同。
(4) copy_thread
获取子进程寄存器信息的存放位置
对子进程的thread.sp赋值,将来子进程运行,这就是子进程的esp寄存器的值。
如果是创建内核线程,那么它的运行位置是
ret_from_kernel_thread, - 将这段代码的地址赋给thread.ip,之后准备其他寄存器信息,退出
将父进程的寄存器信息复制给子进程。
将子进程的eax寄存器值设置为0,所以fork调用在子进程中的返回值为0.
子进程从
ret_from_fork开始执行,所以它的地址赋给thread.ip,也就是将来的eip寄存器。
(5) 运行新进程:从ret_from_fork处开始执行
dup_task_struct中为其分配了新的堆栈
copy_process中调用了
sched_fork,将其置为TASK_RUNNING
copy_thread中将父进程的寄存器上下文复制给子进程,这是非常关键的一步,这里保证了父子进程的堆栈信息是一致的。
将
ret_from_fork的地址设置为eip寄存器的值,这是子进程的第一条指令。
进程创建
创建新进程是通过复制当前进程实现的,fork、vfork和clone三个系统调用都可以创建一个新进程,而且都是通过调用do_fork来实现进程的创建。do_fork主要是复制了父进程的task_struct,然后修改必要的信息,从而得到子进程的task_struct。
刚fork出来的子进程是从ret_from_fork开始执行的,然后跳转到syscall_exit,从系统调用中返回。
实验截图
cd LinuxKernel rm menu -rf cd .. cp -rf Code/shiyanlou_cs195/menu LinuxKernel cd LinuxKernel/menu mv test_fork.c test.c make rootfs
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
在新窗口打开gdb
$ gdb $ file linux-3.18.6/vmlinux $ target remote:1234
设置断点
b sys_clone b do_fork b dup_task_struct b copy_process b copy_thread b ret_from_fork
最后跳转到syscall_exit
总结
新进程的执行源于以下过程:1. dup_task_struct中为其分配了新的堆栈。
2. 调用了sched_fork,将其置为TASK_RUNNING。
3. copy_thread中将父进程的寄存器上下文复制给子进程,保证了父子进程的堆栈信息是一致的。
4. 将ret_from_fork的地址设置为eip寄存器的值。
最终子进程从ret_from_fork开始执行。
相关文章推荐
- 实验 六:分析linux内核创建一个新进程的过程
- 分析Linux内核创建一个新进程的过程
- 分析Linux内核创建一个新进程的过程
- [转载] 分析Linux内核创建一个新进程的过程
- Linux内核作业--分析Linux内核创建一个新进程的过程
- Linux内核设计第六周学习总结 分析Linux内核创建一个新进程的过程
- linux内核分析 第六周 分析Linux内核创建一个新进程的过程
- Linux内核作业--分析Linux内核创建一个新进程的过程
- 分析Linux内核创建一个新进程的过程
- 作业六:分析Linux内核创建一个新进程的过程
- linux内核分析第六周-分析Linux内核创建一个新进程的过程
- 《Linux内核--分析Linux内核创建一个新进程的过程 》 20135311傅冬菁
- 分析Linux内核创建一个新进程的过程
- 《Linux操作系统分析》之分析Linux内核创建一个新进程的过程
- Linux内核创建一个进程的过程分析
- 分析Linux内核创建一个新进程的过程
- Linux内核分析第六周学习笔记——分析Linux内核创建一个新进程的过程
- 分析Linux内核创建一个新进程的过程
- 20135202闫佳歆--week6 分析Linux内核创建一个新进程的过程——实验及总结
- 分析Linux内核创建一个新进程的过程