【益西拉姆 原创作品转载请注明出处 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000】

第六周 进程的描述和进程的创建

一、 进程的描述

  • 进程控制块PCB——task_struct

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

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

进程的创建

  • 进程的创建概览及fork一个进程的源代码
  • 回顾:
    • startkernel创建了cpuidle,也就是0号进程。而0号进程又创建了两个线程,一个是kernel_init,也就是1号进程,这个进程最终启动了用户态;
    • 另一个是kthreadd。这就是“道生一,一生二”。0号进程是固定的代码;
    • 1号进程是通过复制0号进程PCB之后在此基础上做修改得到的。
  • iret与int 0x80指令对应,一个是弹出寄存器值,一个是压入寄存器的值
  • 如果将系统调用类比于fork();那么就相当于系统调用创建了一个子进程,然后子进程返回之后将在内核态运行,而返回到父进程后仍然在用户态运行

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、vfork和clone三个系统调用都可以创建一个新进程,而且都是通过调用do_fork来实现进程的创建;
  2. Linux通过复制父进程来创建一个新进程,那么这就给我们理解这一个过程提供一个想象的框架:

    • 复制一个PCB——task_struct
    • err = arch_dup_task_struct(tsk, orig);
    • 要给新进程分配一个新的内核堆栈
    • `ti = allocthreadinfo_node(tsk, node);

      tsk->stack = ti;

      setupthreadstack(tsk, orig); //这里只是复制,而非复制内核堆`

  3. 要修改复制过来的进程数据,比如pid、进程链表等等都要改改吧,见copy_process内部。
  4. 从用户态的代码看fork();函数返回了两次,即在父子进程中各返回一次,父进程从系统调用中返回比较容易理解,子进程从系统调用中返回,那它在系统调用处理过程中的哪里开始执行的呢?这就涉及子进程的内核堆栈数据状态和taskstruct中thread记录的sp和ip的一致性问题,这是在哪里设定的?copythread in copy_process
  5. *childregs = *current_pt_regs(); //复制内核堆栈
  6. childregs->ax = 0; //为什么子进程的fork返回0,这里就是原因!
  7. p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶
  8. p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址

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

  • 更新menu内核,然后删除test_fork.c以及test.c(以减少对之后实验的影响
  • 编译内核,可以看到fork命令
  • 启动gdb调试,并对主要的函数设置断点
  • 在MenuOS中执行fork,就会发现fork函数停在了父进程中
  • 继续执行之后,停在了dofork的位置。然后n单步执行,依次进入copyprocess、duptaskstruct。按s进入该函数,可以看到dst = src(也就是复制父进程的struct)
  • 在copythread中,可以看到把taskpg_regs(p)也就是内核堆栈特定的地址找到并初始化
  • 到了159、160行的代码就是把压入的代码再放到子进程中:

     `*children = *current_pt_regs();
    
      childregs->ax = 0;`
  • 164行,是确定返回地址 p->thread.ip = (unsigned long) ret_from_fork;
  • 最后输入finish运行完毕。

总结

本周主要就是课本的进程一章的拓展,通过实践来更加的运用完整,很有趣。

20135239益西拉姆 Linux内核分析 进程的描述和进程的创建的更多相关文章

  1. 20135239 益西拉姆 linux内核分析 进程的切换和系统的一般执行过程

    week 8 进程的切换和系统的一般执行过程 [ 20135239 原文请转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course ...

  2. 20135239 益西拉姆 linux内核分析 可执行程序的装载

    益西拉姆 + 原创作品请勿转载 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ” week 7 可 ...

  3. 20135239益西拉姆 Linux内核分析 汇编一个简单的c程序并分析其指令过程

    益西拉姆+<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 第一周linux内核分析 学习笔记 一.计算机 ...

  4. 20135239益西拉姆 Linux内核分析 操作系统是怎样工作的?

    益西拉姆+ 原创作品+ <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 ” 堆栈 堆栈是C语言程序运行时 ...

  5. 20135239 益西拉姆 linux内核分析 跟踪分析Linux内核的启动过程

    回顾 1.中断上下文的切换——保存现场&恢复现场 本节主要课程内容 Linux内核源代码简介 1.打开内核源代码页面 arch/目录:支持不同CPU的源代码:其中的X86是重点 init/目录 ...

  6. 20135239 益西拉姆 linux内核分析 读书笔记之第四章

    chapter 4 进程调度 4.1 多任务 多任务操作系统就是能同时并发的交互执行多个进程的操作系统. 多任务系统可以划分为两类: - 非抢占式多任务: - 进程会一直执行直到自己主动停止运行(这一 ...

  7. 20135239 益西拉姆 linux内核分析 扒开系统调用的三层皮(下)

    一. 给MenuOS增加time-asm命令 代码解释 1.-rf:强制删除 2.clone :重新克隆 3.time-asm:显示系统时间的汇编形式 给MenuOS增加time和time-asm命令 ...

  8. 20135239 益西拉姆 linux内核分析 使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用

    https://drive.wps.cn/preview#l/759e32d65654419cb765da932cdf5cdc 本次直接在wps上写的,因为不能连同图片一起粘贴过来,一个一个粘比较费时 ...

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

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

随机推荐

  1. UVa 10055

    说一下犯错的地方: 1)没有注意数据范围,题目中是The input numbers are not greater than balabalabala. 而这个32位的int类型恰好装不下2^32, ...

  2. MySQL基础(一)

    首先需要安装MySOL,这里我是在windows环境下安装的,具体教程可以参考https://www.cnblogs.com/xsmile/p/7753984.html,不过要注意安装过程可能会不太顺 ...

  3. ossec代理

    代理端 OSSEC有两种代理端:可安装的代理端和哑代理端(免安装).可安装的代理端被安装在主机上,通过OSSEC的加密协议将主机的信息发送到OSSEC服务器.亚代理端则不需在远端主机进行安装.他作为O ...

  4. Java 内存模型_1

    title: Java 内存模型_1 date: 2017-01-15 17:11:02 tags: [JMM] categories: [Programming,Java] --- 概述 本文记录 ...

  5. Django缓存配置和使用

    - 缓存 - 配置 CACHES = { 'default': { 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache', 'LOCAT ...

  6. virtualbox命令行启动虚拟机和关闭虚拟机

    C:\Program Files\Oracle\VirtualBox\VBoxManage.exe startvm 虚拟机名字 --type headlessC:\Program Files\Orac ...

  7. Final发布中间产物

    目录 ❶版本控制 ❷软件功能说明书 ❸WBS ❹PSP 一.版本控制 ①Git地址:https://git.coding.net/tianjiping/Android-tianjiping.git ② ...

  8. 渡过OO的死劫,了解规格的意义——OO第三次博客总结

    当熬过了一次次黑暗,迎接我们的却是被扣的惨不忍睹的JSF ┭┮﹏┭┮ 一.总结调研 规格的历史 传统科学的特点是发现世界,而软件的特点是构造世界.软件的最底层就是0,1,两个离散的值.程序设计语言的三 ...

  9. 20lanmo162326 2017-2018-1 《程序设计与数据结构》第1周学习总结

    20162326 2017-2018-1 <程序设计与数据结构>第1周学习总结 教材学习内容总结 算法:在特定计算模型下,解决问题的指令序列 计算 = 信息处理 也就是用工具,遵规则,机械 ...

  10. 2018软工实践—Alpha冲刺(10)

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 测试整体软件 展示GitHub当 ...