Linux分析第六周——进程的描述和进程的创建

李雪琦+原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000

一、知识要点:

task_struct

task_struct结构的分配使用的是alloc_task_struct宏,该宏就是简单地调用kmem_cache_alloc()task_struct_cachep缓存中分配。接着会使用alloc_thread_info宏分配thread_info结构。thread_info结构保存了特定于体系结构的汇编语言代码需要访问的那部分进程数据,包括执行域、可抢占标志和当前的CPU等信息。在分配thread_info结构的时,实际调用的是__get_free_pages(),64位下分配的是2个物理页(返回的是虚拟地址)。但是很显然thread_info结构是用不了2页的,剩余的内存其实是用作子进程的内核栈(不是stack_start参数指定的用户栈),可以通过end_of_stack()来计算栈顶位置。在分配完必要的结构后,会调用arch_dup_task_struct()拷贝父进程的task_struct结构到子进程的task_struct结构,如果父进程使用FPU或其他的CPU扩展寄存器,则要将这些寄存器的信息(在prepare_to_copy()中保存的)拷贝到子进程的task_struct结构中。
 

fork函数对应的内核处理过程sys_clone:

fork()系统调用对应的内核实现为sys_fork()sys_fork()是对do_fork()的简单封装,sys_fork()的任务是从处理器寄存器中提取由用户空间提供的信息,do_fork()负责进程的复制。fork()和clone()系统调用的入口点sys_vfork()sys_clone()也是调用的do_fork()

而其中关系着进程创建的主要是copy_processcopy_thread.copy_process()函数有7个参数,其中我们需要关心的有clone_flagsstack_startregscone_flags是一个标志集合,分为两部分:最低的字节指定了在子进程终止时发送给父进程的信号,其余的高位字节保存了各种真正的复制标志,如CLONE_FSCLONE_THREAD等。在用户层调用fork()时不能指定标志,所以默认的CLONE_FLAGS的值为SIGCHLD。
 

dup_task_struct: 

     

  • task_struct开辟内存tsk = alloc_task_struct_node(node);

  • thread_info开辟内存ti = alloc_thread_info_node(tsk, node);

  • 复制父进程的task_struct信息到新的task_structerr = arch_dup_task_struct(tsk, orig);
     

    int arch_dup_task_struct(struct task_struct dst, struct task_struct src)
    {
       dst = src;
       if (src->thread.xstate) {
          dst->thread.xstate = kmem_cache_alloc(task_xstate_cachep,
                             GFP_KERNEL);
         if (!dst->thread.xstate)
             return -ENOMEM;
            memcpy(dst->thread.xstate, src->thread.xstate, xstate_size);
       }
        return 0;
    }

4)setup_thread_stack 设置线程栈

    
子进程的初始化:进程的用户栈的起始地址存储在task_struct结构的stack_start成员中,在初始化的时候使用的是父进程的用户栈地址,所以在子进程创建时会和父进程使用相同的用户栈,如果有任何一方修改栈的话,会重新拷贝一份,这是基于COW技术,以避免无用的复制。创建子进程为调度器类提供了调度进程的一个切入点,内核会调用sched_fork()函数,以便使调度器有机会对新进程进行设置。sched_fork()会初始化一些和调度相关的成员,并将进程设置为TASK_RUNNING状态。不过此时新的进程还没有放到CPU的执行队列中,所以新的进程不会被调度到。
 

新进程是从ret_from_fork处开始执行的。对于fork执行处理过程来说,父子进程共享同一段代码空间,”一次调用,两次返回“,其实对于调用fork的父进程来说,如果fork出来的子进程没有得到 调度,那么父进程从fork系统调用返回,同时分析sys_fork知道,fork返回的是子进程的id。再看fork出来的子进程,由 copy_process函数可以看出,子进程的返回地址为ret_from_fork(和父进程在同一个代码点上返回),返回值直接置为0。所以当子进 程得到调度的时候,也从fork返回,返回值为0。ret_from_fork()调用schedule_tail()函数,用存放在栈中的值再装入所有寄存器,并强迫CPU返回到用户态。这样,eax寄存器就装过两个值,一个是子进程的值0,一个是父进程的值——子进程的PID。然后在fork()、vfork()或clone()返回时,新进程将开始执行。在不同的进程中返回不同的值。

执行过程图:

二、实验过程:

1.配置环境,登录实验楼网站。

按照上次实验的基本步骤,结合老师视频所讲,完成相关实验。

cd LinuxKernel

删除menu

然后从github上克隆相应的mengning/menu.git
 

2.测试menuOS,测试fork直接执行结果。

3.配置调试系统,进入gdb调试,利用file linux-3.18.6/vmlinux和target remote:1234来配置加载初始调试环境.

4.在linux内核进程创建可能用到的点设置断点分别为sys_clone,do_fork,dup_task_struct,copy_thread,copy_process和ret_from_fork.


三、总结:

Linux中,fork、vfork和clone三个系统调用都是通过调用do_fork来实现进程的创建,而fork()系统调用产生的子进程在系统调用处理过程中从ret_from_fork处开始执行。fork会产生父子进程,在父进程中,返回值是子进程的进程号;在子进程中,返回值为0。因此可通过返回值来判断当前进程是父进程还是子进程。使用fork函数得到的子进程是父进程的一个复制品,它从父进程处复制了整个进程的地址空间,包括进程上下文,进程堆栈,内存信息,打开的文件描述符,信号控制设定,进程优先级,进程组号,当前工作目录,根目录,资源限制,控制终端等。而子进程所独有的只是它的进程号,资源使用和计时器等。可以看出,使用fork函数的代价是很大的,它复制了父进程中的代码段,数据段和堆栈段里的大部分内容,使得fork函数的执行速度并不快。

Linux分析第六周——进程的描述和进程的创建的更多相关文章

  1. LINUX内核分析第六周学习总结——进程的描述与创建

    LINUX内核分析第六周学习总结--进程的描述与创建 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc ...

  2. LINUX内核分析第六周学习总结——进程的描述和进程的创建

    LINUX内核分析第六周学习总结——进程的描述和进程的创建 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...

  3. 《Linux内核分析》第六周笔记 进程的描述和进程的创建

    进程的描述和进程的创建 一.进程的描述 1.进程描述符task_struct数据结构(一) 操作系统的三大功能:进程管理(核心).内存管理.文件系统. 进程控制块PCB——task_struct(进程 ...

  4. 20135327郭皓--Linux内核分析第六周 进程的描述和进程的创建

    进程的描述和进程的创建 一.进程的描述 操作系统三大功能: 进程管理 内存管理 文件系统 进程描述符task_struct数据结构 task _ struct:为了管理进程,内核必须对每个进程进行清晰 ...

  5. 20135337朱荟潼 Linux第六周学习总结——进程的描述和进程的创建

    朱荟潼 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课http://mooc.study.163.com/course/USTC 1000029000 第六周 进程的描述 ...

  6. Linux内核分析第六周学习笔记——分析Linux内核创建一个新进程的过程

    Linux内核分析第六周学习笔记--分析Linux内核创建一个新进程的过程 zl + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...

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

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

  8. linux内核分析第六周学习笔记

    LINUX内核分析第六周学习总结 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.c ...

  9. 20135239益西拉姆 Linux内核分析 进程的描述和进程的创建

    [益西拉姆 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] 第六周 进程的描述 ...

随机推荐

  1. JavaFX学习笔记——ControlsFX控件集学习——ToggleSwitch和BreadCrumbBar例子

    ToggleSwitch ToggleSwitch ts = new ToggleSwitch("开"); 效果 BreadCrumbBar BreadCrumbBar<St ...

  2. 获取一个数组里面第K大的元素

    如何在O(n)内获取一个数组比如{9, 1, 2, 8, 7, 3, 6, 4, 3, 5, 0, 9, 19, 39, 25, 34, 17, 24, 23, 34, 20}里面第K大的元素呢? 我 ...

  3. MongoDB 极简实践入门

    原作者StevenSLXie; 原链接(https://github.com/StevenSLXie/Tutorials-for-Web-Developers/blob/master/MongoDB% ...

  4. Java飞机大战MVC版

    PlaneWar Java飞机大战MVC版 //无聊时偷的雷霆战机素材写了一个飞机大战,本意是练习mvc,但写得还是不清晰 github下载:https://github.com/dejavudwh/ ...

  5. 修改Linux系统下的最大文件描述符限制

    通常我们通过终端连接到linux系统后执行ulimit -n 命令可以看到本次登录的session其文件描述符的限制,如下: $ulimit -n1024 当然可以通过ulimit -SHn 1024 ...

  6. Gradle初使用

    我以前一直使用Maven来构建工程,这两天突然发现gradle也非常好用,记录一下自己使用gradle的过程. Gradle的下载与配置 本次选择下载的是gradle3.5版本,没选最新的gradle ...

  7. java之接口开发-初级篇-socket通信

    socket通信实现util包类实现 public class SocketThread extends Thread { public void run() { while (true) { // ...

  8. 算法笔记(c++)--使用一个辅助栈排列另一个栈

    算法笔记(c++)--使用一个辅助栈排列另一个栈 仅仅使用一个辅助栈,不使用其他数据结构来排列一个栈,要求,上大下小. 分析下.肯定是先吧主栈中的数据都放到辅助栈中,在辅助栈中上小下大. 1.首先循环 ...

  9. 微信小程序---scroll-view在苹果手机上触底或触顶页面闪动问题

    在项目开发中遇到一个关于scroll-view的的问题,具体如下: 项目要求是横向滚动,由于直接在scroll-view组件设置display:flex不生效,因此考虑直接在scroll-view下增 ...

  10. Django 使用 Celery 实现异步任务

    对于网站来说,给用户一个较好的体验是很重要的事情,其中最重要的指标就是网站的浏览速度.因此服务端要从各个方面对网站性能进行优化,比如可采用CDN加载一些公共静态文件,如js和css:合并css或者js ...