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

    Linux 基础

    实验六

    作业所属课程 <2020-2021-1Linux内核原理与分析>
    作业要求 <2020-2021-1Linux内核原理与分析第一周作业>
    作业目标 分析Linux内核创建一个新进程的过程
    作业正文 2020-2021-1 20209308《Linux内核原理与分析》第七周作业

    一.实验过程

    1更新内核

    1.1下载新版本menu

    cd LinuxKernel/    //进入LinuxKernel文件夹
    rm -rf menu          //将menu目录删除
    git clone http://github.com/mengning/menu.git      //克隆下载更新了版本之后的menu目录
    cd menu
    mv test_fork.c test.c
    

    1.2进入menu文件夹,进入MenuOS

    cd menu/                  //进入menu文件夹
    make rootfs              //进入MenuOS
    MenuOS>>help       //并使用help命令查看现有的命令
    

    2.gdb调用

    cd LinuxKernel   //返回LinuxKernel目录
    qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S  //启动内核
    

    启动内核,建立连接后在sys_clone、do_fork、dup_task_struct、copy_process、copy_thread、ret_from_fork处各设置断点。

    (gdb)file linux-3.18.6/vmlinux
    (gdb)target remote:1234 //建立连接
    (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
    


    copy_process断点

    copy_thread断点


    二.分析进程的描述与创建

    2.1进程描述

    进程就是运行起来的程序,程序运行起来需要被加载到内存中。进程就是操作系统的描述,这个描述叫PCB(进程控制块),Linux下PCB有自己的名字叫task_struct.而操作系统就是

    使用task_struct结构体描述进程,使用双向链表来将这些结构体组织起来进行管理。

    -linux中主要三种状态
    - 就绪态
    - 运行态
    - 阻塞状态
    三种状态根据条件不断切换。 刚开始创建的进程叫做就绪态,叫做task_running 当被调用之后,开始运行叫做运行态,也叫做task_running 这两个状态都用了task_runing同一个标志,可理解为可运行状态,是否运行要看时间片等信息。 如果进程终止后进入僵尸状态,最终被回收。 如果等待某件事情将进入阻塞状态。如果被唤醒重新进入就绪态。

    2.2进程创建

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

    2.2.1do_fork

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

    2.2.2copy_process

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

    2.2.3copy_thread

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

    总结

    新的进程通过克隆旧的程序(当前进程)而建立。
    fork() 和 clone()(对于线程)系统调用可用来建立新的进程。
    这两个系统调用结束时,内核在系统的物理内存中为新的进程分配新的 task_struct 结构,同时为新进程要使用的堆栈分配物理页。

  • 相关阅读:
    自己写的一个ASP.NET服务器控件Repeater和GridView分页类
    c#Udp分包组包方法
    利用反射写的,可以插件的俄罗斯方块
    冰之随笔一(c#反射、特性)
    Socket的简单例子
    HTTP状态码
    C# WebService 基础实例
    Win7上IIS发布网站系统部署项目
    FileUpload 简单上传+小预览
    .net 验证码
  • 原文地址:https://www.cnblogs.com/ppswaggy/p/14019444.html
Copyright © 2011-2022 走看看