进程的描述和进程的创建

一、 进程的描述

(一)进程控制块PCB——task_struct

1、操作系统的三大管理功能包括:

  (1)进程管理

  (2)内存管理

  (3)文件系统

2、PCB task_struct中包含:

  (1)进程状态

  (2)进程打开的文件

  (3)进程优先级信息

3、通过唯一的进程标识PID来区别每个进程。

4、进程控制块PCB——task_struct

5、进程状态

  (1)创建新进程后实际的状态是TASK_RUNNING,就绪但是没有运行,调度器选择一个task之后进入运行态,也叫TASK_RUNNING。

  (2)当进程是TASK_RUNNING时,代表这个进程是可运行的,至于它有没有真的在运行,取决于它有没有获得cpu的控制权,即有没有在cpu上实际的运行。

  (3)一个正在进行的进程调用do_exit(),进入TASK_ZOMBIE,进程被终止,“僵尸进程”。

  (4)等待特定时间或者资源的时候,进入阻塞态,如果条件满足就进入就绪态,被选择后进入运行态。

6、理解task_struct数据结构

  (1)进程的标示pid

  (2)为了对给定类型的进程进行有效的搜索,内核维护了几个进程链表。

  (3)所有进程链表struct list_head tasks

7、CPU相关的状态

二、 进程的创建

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

1、fork一个子进程的代码:

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

int main(int argc, char * argv[])

{

int pid;

/* fork another process */

pid = fork();

if (pid < 0)

{

/* error occurred */

fprintf(stderr,"Fork Failed!");

exit(-1);

}

else if (pid == 0)

{

/* child process */

printf("This is Child Process!\n");

}

else

{

/* parent process  */

printf("This is Parent Process!\n");

/* parent will wait for the child to complete*/

wait(NULL);

printf("Child Complete!\n");

}

}

  (1)fork()系统调用从内核返回两次:一次回到父进程,另一次回到新产生的子进程。

  (2)fork()实际上是由clone()系统调用实现的。

(二)理解进程创建过程复杂代码的方法

1、调用fork的过程:

(三)创建一个新进程在内核中的执行过程

  • fork、vfork和clone三个系统调用都可以创建一个新进程,而且都是通过调用do_fork来实现进程的创建;
  • Linux通过复制父进程来创建一个新进程,那么这就给我们理解这一个过程提供一个想象的框架:
  • 复制一个PCB——task_struct
    1. err = arch_dup_task_struct(tsk, orig);
  • 要给新进程分配一个新的内核堆栈
    1. ti = alloc_thread_info_node(tsk, node);
    2. tsk->stack = ti;
    3. setup_thread_stack(tsk, orig); //这里只是复制thread_info,而非复制内核堆栈
    • 要修改复制过来的进程数据,比如pid、进程链表等等都要改改吧,见copy_process内部。
  • 从用户态的代码看fork();函数返回了两次,即在父子进程中各返回一次,父进程从系统调用中返回比较容易理解,子进程从系统调用中返回,那它在系统调用处理过程中的哪里开始执行的呢?这就涉及子进程的内核堆栈数据状态和task_struct中thread记录的sp和ip的一致性问题,这是在哪里设定的?copy_thread in copy_process
    1. *childregs = *current_pt_regs(); //复制内核堆栈
    2. childregs->ax = 0; //为什么子进程的fork返回0,这里就是原因!
    3. p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶
    4. p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址

新进程执行起点:return_from_fork,只复制了内核堆栈一部分,int指令和save_all压到内核栈的内容,参数、系统调用号等都进行压栈。

(四)使用gdb跟踪创建新进程的过程

1、准备工作:

  rm menu -rf

  git clone http://github.com/mengning/menu.git   //更新Menu

  cd menu

  mv test_fork.c test.c   //把test.c覆盖掉

  make rootfs

2、进行gdb调试:

  qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

  gdb

  file linux-3.18.6/vmlinux

  target remote:1234

  // 设置断点

  b sys_clone  //因为fork实际上是执行的clone

  b do_fork

  b dup_task_struct

  b copy_process

  b copy_thread

  b ret_from_fork

  c

  n

  tsk->stack = ti;    //把内核堆栈的地址赋给它

  sturct pt_regs *childregs = task_pg_regs(p);  //把内核堆栈压栈的空间地址找到,初始化。

  *childregs = *current_pt_regs();

  childregs->ax = 0;  //把当前进程的内核堆栈的压的寄存器赋值到子进程中来。

  p->thread.ip = (unsigned long) ret_from_fork; //设置子进程被调度的ip,即子进程的起点

  jmp syscall_exit;   //这之后就跟踪不到了。

三、总结

  进程就是处于执行期的程序;进程就是正在执行的程序代码的实时结果;进程是处于执行期的程序以及相关的资源的总称。

进程在创建它的时刻开始存活。在Linux系统中,这通常是调用fork()系统的结果。fork()系统调用从内核返回两次:一次回到父进程,另一次回到新产生的子进程。它实际上是由clone()系统调用实现的。

Linux内核分析——进程的描述和进程的创建的更多相关文章

  1. 《Linux内核分析》 第六节 进程的描述和进程的创建

    <Linux内核分析> 第六节 进程的描述和进程的创建 20135307 张嘉琪 原创作品转载请注明出处 +<Linux内核分析>MOOC课程http://mooc.study ...

  2. 《Linux内核分析》第六周 进程的描述与创建

    [刘蔚然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK SIX(3 ...

  3. 《Linux内核分析》第八周 进程的切换和系统的一般执行过程

    [刘蔚然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK EIGHT ...

  4. Linux内核分析期中总结

    目录: “Linux内核分析”实验一报告 “Linux内核分析”实验二报告 “Linux内核分析”实验三报告 Linux实验四报告 “Linux内核分析”第五周报告 "Linux内核分析&q ...

  5. 《Linux内核分析》课程第三周学习总结

    姓名:何伟钦 学号:20135223 ( *原创作品转载请注明出处*) ( 学习课程:<Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...

  6. Linux内核分析第六周学习总结:进程的描述和进程的创建

    韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.进程的描述 ...

  7. LINUX内核分析第六周学习总结——进程的描述与创建

    LINUX内核分析第六周学习总结--进程的描述与创建 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc ...

  8. LINUX内核分析第六周学习总结——进程的描述和进程的创建

    LINUX内核分析第六周学习总结——进程的描述和进程的创建 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...

  9. 20135239益西拉姆 Linux内核分析 进程的描述和进程的创建

    [益西拉姆 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] 第六周 进程的描述 ...

  10. Linux内核分析——进程描述与创建

    20135125陈智威 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 实验内容 ...

随机推荐

  1. JDK10源码阅读--String

    jdk源码里对String的介绍: String 是不可变的,一旦被创建其值不能被改变. String buffers 支持可变String. 因为String是不可变的, 所以它们可以被共享. 例如 ...

  2. <20190104>关掉一些鸡肋的Win10功能

    讨厌鬼001 # - windows defender -    本身没什么卵用, 却一直占着位置, 而且不断提示更新. 必须关闭它 . 在"运行" 中,  输入 "gp ...

  3. mysqldump与innobackupex备份过程你知多少

    mysqldump与innobackupex备份过程你知多少 测试库表创建(这里在同一个库下创建两个表,一个表为innodb引擎,一个为myisam引擎) root@localhost : (none ...

  4. 前端性能优化成神之路—资源合并与压缩减少HTTP请求

    资源合并与压缩减少HTTP请求的概要 资源合并与压缩减少HTTP请求主要的两个优化点是减少HTTP请求的数量和减少请求资源的大小 http协议是无状态的应用层协议,意味着每次http请求都需要建立通信 ...

  5. 协程与concurent.furtrue实现线程池与进程池

    1concurent.furtrue实现线程池与进程池 2协程 1concurent.furtrue实现线程池与进程池 实现进程池 #进程池 from concurrent.futures impor ...

  6. NOIP 2000 进制转换

    题目描述 我们可以用这样的方式来表示一个十进制数: 将每个阿拉伯数字乘以一个以该数字所处位置的(值减1)为指数,以10为底数的幂之和的形式.例如:123可表示为 1\times 10^2+2\time ...

  7. .NET Core、Xamarin、.NET Standard和.NET Framework四者之间的区别

    前段时日微软(Microsoft)正式发布了.NET Core 2.0,在很多开发社区中反响不错.但还是有一些开发者发出了疑问,.NET Core.Xamarin..NET Standard和.NET ...

  8. ethereum/EIPs-1077 Executable Signed Messages

    https://github.com/alexvandesande/EIPs/blob/ee2347027e94b93708939f2e448447d030ca2d76/EIPS/eip-1077.m ...

  9. day12 Python数字,字符串,列表,元祖,字典总结

    一.数字 int() 二.字符串 replace/find/join/strip/startswith/split/upper/lower/format tempalte = "i am { ...

  10. kubectl常用命令

    command kubectl kubectl 输出格式 显示Pod的更多信息 kubectl get pod <pod-name> -o wide 以yaml格式显示Pod的详细信息 k ...