LINUX内核分析第六周学习总结:进程的描述和进程的创建
一、进程的描述
- 进程控制块PCB——task_struct
• 操作系统的三大管理功能
• - 进程管理
• - 内存管理
- 文件系统
• PCB task_struct中包含
• - 进程状态
• - 进程打开的文件 - 进程优先级信息
• struct task_struct数据结构很庞大
- Linux进程的状态
不同于操作系统(就绪、运行、阻塞)
,
- TASK_RUNNING具体是就绪还是执行,要看系统当前的资源分配情况;
- TASK_ZOMBIE也叫僵尸进程
为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息。
二,进程的创建
1.进程的创建概览及fork一个进程的源代码
- 回顾:start_kernel创建了cpu_idle,也就是0号进程。而0号进程又创建了两个线程,一个是kernel_init,也就是1号进程,这个进程最终启动了用户态;另一个是kthreadd。这就是“道生一,一生二”。0号进程是固定的代码;1号进程是通过复制0号进程PCB之后在此基础上做修改得到的。
- 回顾:系统调用的进程创建过程
fork代码
1.#include <stdio.h>
2.#include <stdlib.h>
3.#include <unistd.h>
4.int main(int argc, char * argv[])
5.{
6.int pid;
7./* fork another process /
8.pid = fork();
9.if (pid < 0)
10.{
11./ error occurred /
12.fprintf(stderr,"Fork Failed!");
13.exit(-1);
14.}
15.else if (pid == 0) //pid == 0和下面的else都会被执行到(一个是在父进程中即pid ==0的情况,一个是在子进程中,即pid不等于0)
16.{
17./ child process /
18.printf("This is Child Process!\n");
19.}
20.else
21.{
22./ parent process /
23.printf("This is Parent Process!\n");
24./ parent will wait for the child to complete*/
25.wait(NULL);
26.printf("Child Complete!\n");
27.}
}
创建新进程的框架
fork,vfork,clone都可以创建新进程,他们都是通过调用do_fork来实现的。
• dup_thread复制父进程的PCB
•
• copy_process修改复制的PCB以适应子进程的特点,也就是子进程的初始化
•
• 分配一个新的内核堆栈(用于存放子进程数据)
• 内核堆栈的一部分也要从父进程中拷贝
•
• 根据拷贝的内核堆栈情况设置eip,esp寄存器的值
2. 一个新创建的子进程,(当它获得CPU之后)是从哪一行代码进程执行的?
• 与之前写过的my_kernel相比较,kernel中是可以指定新进程开始的位置(也就是通过eip寄存器指定代码行)。fork中也有相似的机制
• 这就涉及子进程的内核堆栈数据状态和task_struct中thread记录的sp和ip的一致性问题,这是在哪里设定的?copy_thread in copy_process
• 1.*childregs = *current_pt_regs(); //复制内核堆栈,并不是全部,只是regs结构体(内核堆栈栈底的程序)
• 2.childregs->ax = 0; //为什么子进程的fork返回0,这里就是原因!
• 3.
• 4.p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶
5.p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址,也就是说返回的就是子进程的空间了
三,使用gdb调试
四,总结
通过本次的实践我了解到了关于进程的一些原理明白进程在内核的中创建的过程。