zoukankan      html  css  js  c++  java
  • 2019-2020-1 20199304《Linux内核原理与分析》第七周作业

    进程的描述和进程的创建

    1.进程描述

    1.1操作系统的三大管理功能以及对应的抽象概念:

    • 进程管理
    • 内存管理
    • 文件系统
      1.2Linux进程的状态:
      (1)Linux中进程的状态细分可以分为七种:
    • R运行状态(runing):并不意味着进程一定在运行中,也可以在运行队列里;
    • S睡眠状态(sleeping):进程在等待事件完成;(浅度睡眠,可以被唤醒)
    • D磁盘睡眠状态(Disk sleep):不可中断睡眠(深度睡眠,不可以被唤醒,通常在磁盘写入时发生)
    • T停止状态(stopped):可以通过发送SIGSTOP信号给进程来停止进程,可以发送SIGCONT信号让进程继续运行
    • X死亡状态(dead):该状态是返回状态,在任务列表中看不到;
    • Z僵尸状态(zombie):子进程退出,父进程还在运行,但是父进程没有读到子进程的退出状态,子进程进入僵尸状态;
    • t追踪停止状态(trancing stop)
      (2)在linux下,进程三种主要状态:
    • 就绪态
    • 运行态
    • 阻塞状态
      每种状态将会依据外部条件不断的切换。 刚开始创建的进程叫做就绪态,叫做task_running 当被调用之后,开始运行叫做运行态,也叫做task_running 这两个状态都用了task_runing同一个标志,可理解为可运行状态,是否运行要看时间片等信息。 如果进程终止后进入僵尸状态,最终被回收。 如果等待某件事情将进入阻塞状态。如果被唤醒重新进入就绪态。

    2.进程的创建

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

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

    注:Linux中所有的进程创建都是基于复制的方式,Linux通过复制父进程来创建一个新进程,通过调用do_ fork来实现。然后对子进程做一些特殊的处理。而Linux中的线程,又是一种特殊的进程。根据代码的分析,do_ fork中,copy_ process管子进程运行的准备,wake_ up_ new_ task作为子进程forking的完成。fork()函数最大的特点就是被调用一次,返回两次。

    2.2 do_fork处理内容:

    • 调用copy_process,将当期进程复制一份出来为子进程,并且为子进程设置相应地上下文信息。
    • 在vfork调用时,初始化vfork的完成处理信息
    • 调用wake_up_new_task,将子进程放入调度器的队列中,此时的子进程就可以被调度进程选中,得以运行。
    • 如果是vfork调用,需要阻塞父进程,直到子进程执行exec。

    2.3 copy_process的大体流程:

    • 检查各种标志位
    • 调用dup_task_struct复制一份task_struct结构体,作为子进程的进程描述符。
    • 检查进程的数量限制。
    • 初始化定时器、信号和自旋锁。
    • 初始化与调度有关的数据结构,调用了sched_fork,这里将子进程的state设置为TASK_RUNNING。
    • 复制所有的进程信息,包括fs、信号处理函数、信号、内存空间(包括写时复制)等。
    • 调用copy_thread,这又是关键的一步,这里设置了子进程的堆栈信息。
    • 为子进程分配一个pid
    • 设置子进程与其他进程的关系,以及pid、tgid等。这里主要是对线程做一些区分。
    • 在copy_process中,copy_thread函数为子进程准备了上下文堆栈信息

    2.4 copy_thread的流程如下:

    • 获取子进程寄存器信息的存放位置
    • 对子进程的thread.sp赋值,将来子进程运行,这就是子进程的esp寄存器的值。
    • 如果是创建内核线程,那么它的运行位置是ret_from_kernel_thread,将这段代码的地址赋给thread.ip,之后准备其他寄存器信息,退出
    • 将父进程的寄存器信息复制给子进程。
    • 将子进程的eax寄存器值设置为0,所以fork调用在子进程中的返回值为0.
    • 子进程从ret_from_fork开始执行,所以它的地址赋给thread.ip,也就是将来的eip寄存器。

    实验内容

    1.删除之前的menu,再通过git克隆一份新的,使用mv把test.c覆盖掉,然后执行 make roofts。

    cd LinuxKernel
    rm -rf menu
    git clone http://github.com/mengning/menu.git
    cd menu
    mv test_fork.c test.c
    

    2.执行make rootfs,使用help可以看到列表中增加了fork。

    make rootfs
    MenuOS>>help
    

    3.使用水平分割,开启新的shell窗口,启动gdb,把内核加载进来,连接到target remote 1234

    (gdb)file linux-3.18.6/vmlinux
    (gdb)target remote:1234
    

    4.使用b在sys_clone、do_fork、dup_task_struct、copy_process、copy_thread、ret_from_fork处各设置断点。

    (gdb)b sys_clone
    (gdb)b do_fork
    (gdb)b dup_task_struct
    (gdb)b copy_process
    (gdb)b copy_thread
    (gdb)b ret_from_fork
    

    5.使用c继续执行,停到了 do_fork 位置,然后使用命令n

    (gdb)c
    (gdb)n
    


    6.到 copy_process() 函数,继续执行。

    7.使用c继续执行,到断点copy_thread

    总结

    通过对本周的课程的学习,我的理解如下:
    新的进程通过克隆旧的程序(当前进程)而建立。
    fork() 和 clone()(对于线程)系统调用可用来建立新的进程。
    这两个系统调用结束时,内核在系统的物理内存中为新的进程分配新的 task_struct 结构,同时为新进程要使用的堆栈分配物理页。
    Linux 还会为新的进程分配新的进程标识符。
    然后,新 task_struct 结构的地址保存在链表中,而旧进程的 task_struct 结构内容被复制到新进程的 task_struct 结构中。

  • 相关阅读:
    VS2008 环境中完美搭建 Qt 4.7.4 静态编译的调试与发布 Inchroy's Blog 博客频道 CSDN.NET
    编写可丢弃的代码
    c++ using namespace std; 海明威 博客园
    解决MySQL server has gone away
    nginx upstream 调度策略
    (2006, 'MySQL server has gone away') 错误解决 dba007的空间 51CTO技术博客
    Linux IO模型漫谈(2) 轩脉刃 博客园
    redis源码笔记 initServer 刘浩de技术博客 博客园
    MySQLdb批量插入数据
    词库的扩充百度百科的抓取你知道这些热词吗? rabbit9898 ITeye技术网站
  • 原文地址:https://www.cnblogs.com/20199304lbs/p/11785212.html
Copyright © 2011-2022 走看看