• 20169212《Linux内核原理与分析》第八周作业


    理论

    1. task_struct的结构关系
      非常庞大的数据结构,400多行代码。包括对进程链表的管理,控制台,文件系统描述,文件描述符,内存管理描述,信号描述等。
    2. 创建一个新进程在内核中的执行过程
      fork、vfork和clone三个系统调用都可以创建一个新进程,而且都是通过调用do_fork来实现进程的创建;Linux通过复制父进程来创建一个新进程,那么这就给我们理解这一个过程提供一个想象的框架:
      复制一个PCB——task_struct
    err = arch_dup_task_struct(tsk, orig);
    

    要给新进程分配一个新的内核堆栈

    ti = alloc_thread_info_node(tsk, node);
    tsk->stack = ti;
    setup_thread_stack(tsk, orig);   //这里只是复制thread_info,而非复制内核堆栈
    

    要修改复制过来的进程数据,比如pid、进程链表等等都要改改吧,见copy_process内部。
    从用户态的代码看fork();函数返回了两次,即在父子进程中各返回一次,父进程从系统调用中返回比较容易理解,子进程从系统调用中返回,那它在系统调用处理过程中的哪里开始执行的呢?这就涉及子进程的内核堆栈数据状态和task_struct中thread记录的sp和ip的一致性问题,这是在哪里设定的?copy_thread in copy_process

    1 *childregs = *current_pt_regs();   //复制内核堆栈
    2 childregs->ax = 0;   //为什么子进程的fork返回0,这里就是原因!
    3  
    4 p->thread.sp = (unsigned long) childregs;   //调度到子进程时的内核栈顶
    5 p->thread.ip = (unsigned long) ret_from_fork;   //调度到子进程时的第一条指令地址
    

    实验(使用gdb跟踪创建新进程)

    fork、vfork和clone三个系统调用都可以创建一个新进程,而且都是通过调用do_fork来实现进程的创建,do_fork完成了创建中的大部分工作。

    具体分析过程如下:

    cd LinuxKernel
    ls
    cd menu
    vi test.c
    

    在这里与上次实验一样,仍然使用不了git clone这样的命令,于是自己进入menu目录下,对立面的test.c进行修改,修改如下:

    #include <unistd.h>  //添加头文件到文件中
    
    int Fork(int argc, char *argv[])  //添加一个新的函数Fork()
    {
    int pid;
    /* fork another process */
    pid = fork();                                     //fork之后变为两个进程
    if (pid<0) 
    { 
    /* error occurred */
    fprintf(stderr,"Fork Failed!");
    exit(-1);
    } 
    else if (pid==0)                                 //子进程中fork的返回值为0
    {
    /*	 child process 	*/
    printf("This is Child Process!
    ");
    } 
    else 
    { 	
    /* 	parent process	 */
    printf("This is Parent Process!
    ");            //父进程中fork的返回值为子进程的ID
    /* parent will wait for the child to complete*/
    wait(NULL);
    printf("Child Complete!
    ");
    }
    }
    通过这个小程序,可以在用户态创建一个子进程。
    //main函数中需要加入:
    MenuConfig("fork","Fork a new process",Fork);
    
    

    保存并退出。
    在menu目录下make rootfs便可编译,成功启动MenuOS系统,输入help可以看到如图所示的效果

    接下来要使用gdb来跟踪调试进程创建过程,所以需要设置断点。

    qemu -kernel linux-3.18.6/arch/x86/boot/bzImage initrd rootfs.img -s -S
    gdb
    file linux-3.18.6/vmlinux   //加载内核
    target remote:1234          //链接到menu os里
    

    分别在sys_clone,do_fork,dup_task_struct,copy_process,copy_thread,ret_from_fork这几处设置断点,如图

    当按c继续执行之后,后面的断点依次如图所示

    图4中出现了 copy_process

    再继续跟踪可以看到如下

    问题:

    新进程从哪里开始执行?
    回答:ret_from_fork决定了新进程的第一条指令地址:

    p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址
    

    总结:

    1. Linux通过复制父进程来创建一个子进程,通过调用fork来实现;
    2. Linux会为每个子进程动态的分配一个task_struct结构;
    3. Linux用双向循环链表的方式来组织系统中的所有进程(包括内核线程)
    4. fork()函数被调用一次,但返回两次

    书上内容

    1. 时钟中断的工作:跟新系统运行时间;跟新实际时间;在SMP系统中均衡调度各处理器的运行列队;检查当前进程是否耗尽时间片,若耗尽则进行重新调度;运行超时的动态定时器;更新资源消耗和处理器时间的统计值。提高HZ的优点:更高时钟中断解析度;提高时间驱动事件的准确性(平均误差5ms->0.5ms);内核定时器能够以更高的频度和更高准确度执行;依赖定时器的系统调用(如poll和select)能以更高精度运行;对资源消耗和系统运行时间的测量更准确;提供进程抢占的准确度。
    2. 定时器是管理内核流逝的时间的基础。使用很简单,执行一些初始化的工作,设置一个超时时间,指定超时发生后执行的函数,然后激活定时器就可以了。定时器与当前执行代码是异步的,因此就有可能存在潜在的竞争条件。
    3. 内核把物理页作为内存管理的基本单位;区:ZONE_DMA:包含的页用来执行DMA操作;ZONE_NORMAL:正常映射的页;ZONE_HIGHMEM:“高端内存”(并不能永久映射到内核地址空间);释放页:void __free_pages(struct page *page, unsigned int order); void free_pages(unsigned long addr, unsigned int order); void free_page(unsigned long addr)。gfp_mask该标志可以分为三类:(1)行为修饰符:描述内核如何分配所需内存。(2)区修饰符:从哪个区分配内存。(3)类型:组合了行为和区修饰符,提供了常用的标志。
    4. 使用每个cpu数据具有不少好处。首先是减少了数据锁定,第二是使用每个cpu数据可以大大减少缓存失效。目前并不要求必须使用每个cpu的新接口,新接口并不向后兼容之前的内核。
  • 相关阅读:
    曾经看到过一种理论:被爱的一方总是比爱的一方要晚一个季节,所以才会造就许多心酸。
    人生就像在雪地行走,向后看:自己一路走来的轨迹 ;向前看:白茫茫一片; 不要问该往哪里走,只要回答“想往哪里走” ,自己的双脚就是书写历史的工具 ;
    Google的创新九原则(转)
    电影《教父》中的老大哥都觉得:一个不花时间陪家人的男人算不得一个好男人。繁花似锦,岁月青葱,人生不过25亿秒,过一秒,少一秒,时间正滴答滴答地蚕食我们,我们唯一需要做的,就是让这些秒钟过得有意思:高效工作,不断的学习充实,陪陪家人联络亲友,爱惜身体养养花草。
    if you are not making someone else's life better, then you are wasting your time.– Will Smith如果你不能给别人的生活带来改善,那么你就是在浪费你的宝贵时间。 --威尔 史密斯(程序员,你做的东西...)
    要知道其实自己并没有那么出众,你若盛开,清风自来!(低要求,高行动)
    郎永淳妻子抗癌4年路:儿子弃读名校陪治病(转)
    Node.js、Express、Socket.io 入门
    Node.js Express 路由文件分类
    Node.js、express、mongodb 实现分页查询、条件搜索
  • 原文地址:https://www.cnblogs.com/Jarvan210/p/6060107.html
Copyright © 2020-2023  润新知