20135327郭皓--Linux内核分析第六周 进程的描述和进程的创建

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了20135327郭皓--Linux内核分析第六周 进程的描述和进程的创建相关的知识,希望对你有一定的参考价值。

进程的描述和进程的创建

一、进程的描述

操作系统三大功能:

  • 进程管理
  • 内存管理
  • 文件系统

进程描述符task_struct数据结构

  • task _ struct:为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息。

  • 进程的状态:Linux进程的状态(就绪态、运行态、阻塞态)

  • 进程的标示pid:用来标示进程

技术分享

进程描述符task_struct数据结构(重要部分):

 1 struct task_struct {
 2 volatile long state;    /* 进程的运行状态-1 unrunnable, 0 runnable, >0 stopped */
 3 void *stack;    /*指定了进程的内核堆栈*/
 4 atomic_t usage;
 5 unsigned int flags; /* 每一个进程的标识符 */
 6 
 7 int on_rq;  /*运行队列*/
 8 
 9 pid_t pid; /*进程标识符*/
10 
11 struck list_head task;  /*进程链表*/
12 
13 /*父子进程*/
14 struct task_struct __rcu *real_parent; /* real parent process */
15 struct task_struct __rcu *parent; 
16 
17 struct list_head children;    /* list of my children */

 

二、进程的创建

start _ kernel代码中的rest _ init创建两个内核线程,kernel _ init和kthreadd。

kernel _ init将用户态进程init启动,是所有用户态进程的祖先。

kthreadd是所有内核线程的祖先。

0号进程是所有线程的祖先。(0号进程时手工写的)

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) 
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     }
28 }

这里特别说明一下:else if和if两个模块的代码都会被执行,子进程和父进程都会返回,子进程返回0,父进程返回子进程pid。

 

 

实验:

1. 删除menu,克隆新的menu。

 技术分享

2.查看help

技术分享

3.gdb调试

技术分享

4.设置断点

技术分享

5.单步追踪

技术分享

技术分享

技术分享

技术分享

 

总结:

新的进程从哪里开始?

1 *childregs = *current_pt_regs(); //复制内核堆栈
2 childregs->ax = 0; //为什么子进程的fork返回0,这里就是原因!
3  
4 p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶
5 p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址

Linux通过复制父进程来创建一个新进程:复制父进程PCB--task_struct来创建一个新进程,要给新进程分配一个新的内核堆栈。

修改复制过来的进程数据,比如pid、进程链表等等执行copy_process和copy_thread。

设置sp调度到子进程时的内核栈顶,ip转到子进程时的第一条指令地址

之后,当子进程获得CPU的控制权开始运行的时候,ret _ form _ fork可以将后面的堆栈出栈,从iret返回到用户态,从而切换到子进程的用户空间,完成新进程的创建。

以上是关于20135327郭皓--Linux内核分析第六周 进程的描述和进程的创建的主要内容,如果未能解决你的问题,请参考以下文章

20135327郭皓--Linux内核分析第三周 构造一个简单的Linux系统MenuOS

20135327郭皓——Linux内核分析第二周 操作系统是如何工作的

20135327郭皓--读书笔记一

《Linux内核分析》第六周学习笔记

《Linux内核与分析》第六周

linux内核分析第六周-分析Linux内核创建一个新进程的过程