首页 技术 正文
技术 2022年11月14日
0 收藏 638 点赞 3,423 浏览 4704 个字

进程的描述和进程的创建

一、进程的描述

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

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

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

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

《Linux内核分析》第六周笔记 进程的描述和进程的创建

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

《Linux内核分析》第六周笔记 进程的描述和进程的创建

《Linux内核分析》第六周笔记 进程的描述和进程的创建

/*双向链表*/
1296#ifdef CONFIG_SMP
1297struct plist_nodepushable_tasks;
1298struct rb_nodepushable_dl_tasks;
1299#endif
1300
1301struct mm_struct *mm, *active_mm;/*进程管理进程的地址空间相关*/ 每个进程有独立的进程地址空间4G,32位x86。
1302#ifdef CONFIG_COMPAT_BRK
1303unsigned brk_randomized:1;
1304#endif
1305/* per-thread vma caching */
1306u32 vmacache_seqnum;
1307struct vm_area_struct *vmacache[VMACACHE_SIZE];
1308#if defined(SPLIT_RSS_COUNTING)
1309struct 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 */
1342struct task_struct __rcu *real_parent; /* real parent process */
1343struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
1344/*
1345 * children/sibling forms the list of my natural children
1346 */
1347struct list_head children;/* list of my children */
1348struct list_head sibling;/* linkage in my parent’s children list */
1349struct task_struct *group_leader;/* threadgroup leader */
《Linux内核分析》第六周笔记 进程的描述和进程的创建

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

《Linux内核分析》第六周笔记 进程的描述和进程的创建

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

二、进程的创建

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

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

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

  《Linux内核分析》第六周笔记 进程的描述和进程的创建

一号进程的创建:复制了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内核分析》第六周笔记 进程的描述和进程的创建

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

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

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

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

  《Linux内核分析》第六周笔记 进程的描述和进程的创建

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

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

《Linux内核分析》第六周笔记 进程的描述和进程的创建

ip指向ret_from_fork

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

只复制了部分内核堆栈

《Linux内核分析》第六周笔记 进程的描述和进程的创建

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

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

《Linux内核分析》第六周笔记 进程的描述和进程的创建

gdb调试,设断点:

《Linux内核分析》第六周笔记 进程的描述和进程的创建

《Linux内核分析》第六周笔记 进程的描述和进程的创建

执行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。

上一篇: ORACLE 重置SEQQUENCE
下一篇: HTML5 CANVAS 高级
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,484
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,899
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,732
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,485
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:8,125
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:5,286