作业6:进程的描述和进程的创建 20135115臧文君

进程的描述和进程的创建

注:作者:臧文君,原创作品转载请注明出处,《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

一、进程的描述

操作系统的三大功能:进程管理,内存管理和文件系统。

1、进程描述符task_struct数据结构

(1)进程控制块PCB---task_struct

(2)进程描述符提供了内核所需了解的进程信息。

task_struct中包含:进程状态,进程打开的文件,进程优先级信息。

tty_struct控制台

fs_struct文件系统

files_struct打开的文件描述符

mm_struct内存管理

signal_struct通讯信号的描述

(3)struct task_struct的数据结构很庞大

(4)Linux进程的状态与操作系统原理中的描述的进程状态似乎有所不同,比如:就绪状态和运行状态都是TASK_RUNNING。

进程调用do_exit()终止执行,TASK_ZOMBIE(进程被终止)。

阻塞态:TASK_INTERRUPTIBLE or TASK_UNINTERRUPTIBLE(等待中)。

 

2、进程的标识pid

 

3、task_struct数据结构分析

 

(1)运行状态state:-1 unrunnable,0 runnable,>0 stopped。

进程的内核堆栈stack。

ifdef CONFIG SMP条件编译,多处理器时用到。

进程链表list_head tasks

 

4G的进程地址空间

(2)进程的父子关系

 

 

P0有三个儿子P1,P2,P3;P1有两个兄弟P2,P3;P3有一个儿子P4。

(3)CPU相关的状态:thread_struct

文件系统:fs_struct

二、进程的创建

1、进程的创建概览及fork一个进程的用户态代码

 

fork()是用户态用于创建一个子进程的系统调用。

 

fork()系统调用在父进程和子进程各返回一次,在子进程中,pid的返回值为0,执行else的代码,在父进程中,pid的返回值为子进程的ID,执行else if的代码。

2、系统调用再回顾

 

 

 

3、一个新创建的子进程从哪里开始执行?

创建新进程是通过复制当前进程来实现的。

 

系统调用内核处理函数sys_fork、sys_clone、sys_vfork

4、do fork中的copy process就是创建一个进程的主要代码。

dup task struct复制整个PCB。

拷贝内核堆栈数据和指定新进程的第一条指令地址:*childregs = *current_pt_regs();

 

5、创建的新进程是从哪里开始执行的?

p->thread.ip = (unsigned long) ret_from_fork;

 

当子进程获得CPU控制权时,它的return from fork可以把后面堆栈中的iret返回到用户态。

三、使用gdb跟踪创建新进程的过程

1、先删除menu,再克隆一个新的menu。

2、用test_fork.c覆盖test.c:

cd menu

mv test_fork.c test.c

make rootfs//编译

3、调试:

qemu-system-x86_64 -kernel bzImage -initrd /home/YL/menu/rootfs.img -s -S

gdb /usr/src/linux-source-4.4/vmlinux

set arch i386:x86-64

target remote:1234

 

4、设置断点:b sys_clone

b do_fork

b dup_task_struct

b copy_process

b copy_thread

b ret_from_fork

 

5、按c继续执行,但会报错显示超时,此时重启一遍gdb即可。

 

 

6、按n单步执行,按s进入某个函数中去单步执行。

 

 

当前进程的内核堆栈中压的寄存器复制到进程中:

 

设置子进程被调度的IP,是子进程的起点ret_from_fork:

 

总结:

     本次课程学习的是进程的结构分析以及进程的创建。Linux系统创建一个新进程主要依靠fork(),fork()是用户态用于创建一个子进程的系统调用,再由fork()调用do_fork来实现进程的创建。

     先复制一个PCB——task_struct,再给新进程分配一个新的内核堆栈,并且修改复制过来的进程数据,比如pid、进程链表等等。通过以上步骤,就可以创建一个新进程。

     新进程的起点是ret_from_fork,通过*childregs = *current_pt_regs()语句复制内核堆栈。

     在实验的过程中,会遇到gdb的问题,显示连接超时,此时需要重启gdb即可。另外,调试内核时还需要注意路径的问题。若没有给出路径,则是在当前目录下查找文件。

原文地址:https://www.cnblogs.com/CatherineZang/p/5343121.html