zoukankan      html  css  js  c++  java
  • 20135316Linux内核学习笔记第六周

    20135316王剑桥《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC 1000029000
    一、进程控制块PCB——task_struct又称进程描述符,是操作系统用于管理控制进程的一个专门的数据结构,记录进程的各种属性,描述进程的动态变化过程,而PCB是系统感知进程存在的唯一标志
    为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息。
    struct task_struct数据结构很庞大

    Linux进程的状态与操作系统原理中的描述的进程状态似乎有所不同,比如就绪状态和运行状态都是TASK_RUNNING,为什么呢?
    我们调用fork创建好一个新进程的时候,它的状态是TASK_RUNNING(就绪,但是没有在运行),当调度器选择我们新fork的这个进程的时候,它就切换到TASK_RUNNING(正在运行)
    当进程是TASK_RUNNING这种状态的时候,也就是说它是可运行的,但它有没有在运行呢?这个取决于它有没有获得CPU的控制权,也就是说这个进程有没有在CPU上实际地执行,如果在CPU上实际地执行,那就是“正在运行”,如果被调度出去了,在等待,那就是“就绪,但是没有在运行”,这是和操作系统原理中描述的进程状态不同的地方
    进程的标示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(在用户态创建一个子进程,在子进程和父进程中各返回一次)、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
    *childregs = *current_pt_regs(); //复制内核堆栈
    childregs->ax = 0; //为什么子进程的fork返回0,这里就是原因!
    p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶
    p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址(子进程从这里开始执行)
    五、道生一(start-kernel。。。cpu-idle),一生二(kernel-init和kthreadd),二生三(即前面的0,1,2号三个进程),三生万物(一号进程是所有用户态进程的祖先,二号进程是所有内核态进程的祖先)
    六、系统调用回顾


    七、实验截图

    1.首先删除原有menu,并下载新的menu


    2.查看fork系统调用


    3.gdb调试


  • 相关阅读:
    EF的连表查询Lambda表达式和linq语句
    C#.NET里面抽象类,接口,虚方法
    ASP.Net WebAPI的返回值
    IHttpActionResult不识别解决办法
    web api 开发之 filter
    SQL语句大全教程
    ASP.NET Web API 跨域访问(CORS)要注意的地方
    铁乐学python_shelve模块详解
    铁乐学python_day25_序列化模块
    铁乐学python_day24_面向对象进阶1_内置方法
  • 原文地址:https://www.cnblogs.com/20135316wjq/p/5339169.html
Copyright © 2011-2022 走看看