进程的描述和进程的创建

一、进程的描述

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

  操作系统的三大功能:进程管理(核心)、内存管理、文件系统。

  进程控制块PCB——task_struct(进程描述符):为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息。

  • struct task_struct数据结构很庞大,共有约400行代码

  • Linux进程的状态与操作系统原理中的描述的进程状态似乎有所不同,比如就绪状态和运行状态都是TASK_RUNNING,为什么呢?

    操作系统原理中有三个状态:就绪状态、运行状态。阻塞状态。

    调用fork创建一个新进程的时候实际上的状态是TASK_RUNNING(就绪但没有在运行),当调度器选择一个task时还是切换到TASK_RUNNING,(为什么呢?当进程是TASK_RUNNING状态时是可运行的,但是否运行还是看是否获得CPU的控制权(有没有在CPU上实际的执行))进程调用do_exit()中止执行,进入TASK_ZOMBIE(僵尸进程)

    一个正在运行的进程在等待特定的事件或者是资源的时候会进入阻塞态,当阻塞的条件没有了的时候,就进入就绪态。

  • 进程的标示pid

    pid及tpid用来标识进程的

  • 所有进程链表struct list_head tasks;
  • 内核的双向循环链表的实现方法 - 一个更简略的双向循环链表
  • 程序创建的进程具有父子关系,在编程时往往需要引用这样的父子关系。进程描述符中有几个域用来表示这样的关系
  • Linux为每个进程分配一个8KB大小的内存区域,用于存放该进程两个不同的数据结构:Thread_info和进程的内核堆栈
  • 进程处于内核态时使用,不同于用户态堆栈,即PCB中指定了内核栈,那为什么PCB中没有用户态堆栈?用户态堆栈是怎么设定的?
  • 内核控制路径所用的堆栈很少,因此对栈和Thread_info来说,8KB足够了
  • struct thread_struct thread; //CPU-specific state of this task
  • 文件系统和文件描述符
  • 内存管理——进程的地址空间

  2、进程描述符task_struct数据结构(二)

阅读理解task_struct数据结构

struct task_struct {
1236 volatile long state; /*state是运行状态*/
1237 void *stack;/*指定了进程的内核堆栈 */
1238atomic_tusage;
1239 unsigned int flags; /* 标识符*/
1240 unsigned int ptrace;
1241
1242#ifdef CONFIG_SMP/*条件编译多处理器用到*/
1243 struct llist_nodewake_entry;
1244 int on_cpu;
1245 struct task_struct *last_wakee;
1246 unsigned long wakee_flips;
1247 unsigned long wakee_flip_decay_ts;
1248
1249 int wake_cpu;
1250#endif
1251 int on_rq;/*运行队列和进程调度相关程序*/
1252
1253 int prio, static_prio, normal_prio;
1254 unsigned int rt_priority;
1255 const struct sched_class *sched_class;
1256 struct sched_entityse;
1257 struct sched_rt_entityrt;
1258#ifdef CONFIG_CGROUP_SCHED
1259 struct task_group *sched_task_group;
1260#endif
1295 struct list_head tasks;/*进程链表*/

/*双向链表*/
1296#ifdef CONFIG_SMP
1297 struct plist_nodepushable_tasks;
1298 struct rb_nodepushable_dl_tasks;
1299#endif
1300
1301 struct mm_struct *mm, *active_mm;/*进程管理进程的地址空间相关*/ 每个进程有独立的进程地址空间4G,32位x86。
1302#ifdef CONFIG_COMPAT_BRK
1303 unsigned brk_randomized:1;
1304#endif
1305 /* per-thread vma caching */
1306 u32 vmacache_seqnum;
1307 struct vm_area_struct *vmacache[VMACACHE_SIZE];
1308#if defined(SPLIT_RSS_COUNTING)
1309 struct task_rss_statrss_stat;
1310#endif
1330 pid_t pid;/*标识*/
1331pid_ttgid;
1337 /*
1338 * pointers to (original) parent process, youngest child, younger sibling,/*进程的父子关系*/
1339 * older sibling, respectively.  (p->father can be replaced with
1340 * p->real_parent->pid)
1341 */
1342 struct task_struct __rcu *real_parent; /* real parent process */
1343 struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
1344 /*
1345 * children/sibling forms the list of my natural children
1346 */
1347 struct list_head children; /* list of my children */
1348 struct list_head sibling; /* linkage in my parent's children list */
1349 struct task_struct *group_leader; /* threadgroup leader */

1411/*当前任务和CPU相关的状态,在进程上下文切换的过程中起着重要的作用 */
1412 struct thread_struct thread;
1413/* filesystem information */

1414 struct fs_struct *fs;/*文件系统相关的数据结构*/
1415/* open file information */
1416 struct files_struct *files;/*打开的文件描述符列表*/
1417/* namespaces */
1418 struct nsproxy *nsproxy;
1419/* signal handlers *//*与信号处理相关的工作*/

二、进程的创建

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

  进程描述符是整个系统管理中挈领性的东西。

  了解进程是如何创建的?进程之间如何调度切换的?

  

一号进程的创建:复制了0号进程的pcb,然后根据1号进程的需要修改,再加载一个init执行程序 。

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) /*与else共同执行*/
  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. }

  fork系统调用在子进程和父进程各返回一次。子进程中pid的返回值是:0。父进程中pid的返回值是:子进程的ID。

  fork之后两个进程。

  2、理解进程创建过程复杂代码的方法

  在进程调度的过程中,调度到一个未调度的新进程,执行的起点是我们设定的my process的ip。
  创建一个新进程就是复制当前进程的信息来实现的。
  一个父进程创建一个子进程,有一个地方复制子进程的pcb,修改复制出来的pcb.
  要给新进程分配一个新的内核堆栈.

  回顾:系统调用的进程创建过程

  

  Linux中创建进程一共有三个函数:

  • fork,创建子进程
  • vfork,与fork类似,但是父子进程共享地址空间,而且子进程先于父进程运行。
  • clone,主要用于创建线程

  这里值得注意的是,Linux中得线程是通过模拟进程实现的,较新的内核使用的线程库一般都是NPTL。

  3、浏览进程创建过程相关的关键代码

  

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

  fork,vfork,clone都可以创建新进程,他们都是通过调用do_fork来实现的。

ip指向ret_from_fork

fork()系统调用产生的子进程在系统调用处理过程中从ret_from_fork开始执行。

只复制了部分内核堆栈

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

为了减少对之后实验的影响,删除test_fork.c以及test.c,编译内核:

gdb调试,设断点:

执行fork,发现fork函数停在了父进程中。

特别关注新进程是从哪里开始执行的?为什么从哪里能顺利执行下去?即执行起点与内核堆栈如何保证一致。

  • ret_ from_ fork决定了新进程的第一条指令地址。
  • 子进程从ret_ from_ fork处开始执行。
  • 因为在ret_ from_ fork之前,也就是在copy_ thread()函数中* childregs = * current_ pt_ regs();该句将父进程的regs参数赋值到子进程的内核堆栈。
  • * childregs的类型为pt_ regs,里面存放了SAVE_ ALL中压入栈的参数,因此在之后的RESTORE ALL中能顺利执行下去。

三、总结

  fork()函数创建新进程是通过下列一系列函数实现的:fork() -> sys_clone() -> do_fork() -> dup_task_struct() -> copy_process() -> copy_thread() -> ret_from_fork()。操作系统的三大功能:进程管理(核心)、内存管理、文件系统。进程控制块PCB——task_struct(进程描述符):为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息。Linux通过复制父进程来创建一个新进程,fork系统调用在子进程和父进程各返回一次。子进程中pid的返回值是:0。父进程中pid的返回值是:子进程的ID。

《Linux内核分析》第六周笔记 进程的描述和进程的创建的更多相关文章

  1. Linux内核分析第六周学习笔记——分析Linux内核创建一个新进程的过程

    Linux内核分析第六周学习笔记--分析Linux内核创建一个新进程的过程 zl + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...

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

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

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

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

  4. linux内核分析第六周学习笔记

    LINUX内核分析第六周学习总结 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.c ...

  5. Linux内核分析——第六周学习笔记20135308

    第六周 进程的描述和进程的创建 一.进程描述符task_struct数据结构 1.操作系统三大功能 进程管理 内存管理 文件系统 2.进程控制块PCB——task_struct 也叫进程描述符,为了管 ...

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

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

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

    进程的描述和进程的创建 一.进程的描述 操作系统三大功能: 进程管理 内存管理 文件系统 进程描述符task_struct数据结构 task _ struct:为了管理进程,内核必须对每个进程进行清晰 ...

  8. Linux内核分析——第六周学习笔记

    进程的描述和进程的创建 前言:以下笔记除了一些讲解视频中的概念记录,图示.图示中的补充文字.总结.分析.小结部分均是个人理解.如有错误观点,请多指教! PS.实验操作会在提交到MOOC网站的博客中写.

  9. "Linux内核分析"第六周实验报告

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

  10. linux内核分析 第六周

    一.进程的描述 为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息. 1.进程控制块PCB--task_struct 进程状态 进程打开的文件 进程优先级信息 2. ...

随机推荐

  1. shell脚本之数组

    变量:存储单个元素的内存空间. 数组:存储多个元素的连续的内存空间. 数组名:整个数组只有一个名字: 数组索引:编号从0开始: 数组名[索引]: 引用数组中的某个元素:${ ARRAY_NAME [ ...

  2. vue 去除前后空格trim

    一.使用trim修饰符 <input v-model.trim = "massage" > 二.使用filter过去属性 html: <ul id="l ...

  3. http请求的全过程

    参考资料 http://blog.jobbole.com/106632/ https://www.cnblogs.com/engeng/articles/5959335.html https://ww ...

  4. 关于java中BufferedReader的read()及readLine()方法的使用心得

    BufferedReader的readLine()方法是阻塞式的, 如果到达流末尾, 就返回null, 但如果client的socket末经关闭就销毁, 则会产生IO异常. 正常的方法就是使用sock ...

  5. jmeter(三)SOAP/XML-RPC Request

    项目背景:公司的微信端H5界面新开发了会员注册功能,需要对其进行压力测试 项目目标:需要承受每分钟最少6000的压力 一.建立一个测试计划(test plan) 之前有说过,jmeter打开后会自动生 ...

  6. TerraExplorer Add-ons 和TEZ使用说明

    1.    概述 Skyline提供了丰富的API,用户可以根据不同实际需求,进行二次开发封装,实现各种功能的扩展和定制.当我们开发了各种功能页面或者应用程序后,如何将它们快速嵌入到TerraExpl ...

  7. 51单片机开发板(W25Q16学习)

    教程资料 链接:https://pan.baidu.com/s/142JRSPisQO2Cu6VZ2Y5YrQ 密码:eom0 今天测试开发板的W25Q16(16Mbit--Flash)写一篇文章备忘 ...

  8. MIUI7 系统应用精简(米5、红米note3)

    1.由于安装的部分应用在root后无法使用,所以自己一直不能使用MIUI的开发版本. 2.前段时间米5升级MIUI8,实在是用着不咋地,耗电,王者还掉帧,于是降级miui7 3.被逼走上了刷机路. 1 ...

  9. Luogu4249 WC2007 石头剪刀布 费用流

    传送门 考虑竞赛图三元环计数,设第\(i\)个点的入度为\(d_i\),根据容斥,答案为\(C_n^3 - \sum C_{d_i}^2\) 所以我们需要最小化\(\sum C_{d_i}^2\) 考 ...

  10. [Oracle]发生 ora-06502 RMAN 在对 catalog DB 同期时出错的调查方法

    Catalog DB resync error: 1, setting on the server that starts the RMAN client $ Export EVENT_10928 = ...