• 结合中断上下文切换和进程上下文切换分析Linux内核的一般执行过程


    实验内容:结合中断上下文切换和进程上下文切换分析Linux内核一般执行过程

    • 以fork和execve系统调用为例分析中断上下文的切换
    • 分析execve系统调用中断上下文的特殊之处
    • 分析fork子进程启动执行时进程上下文的特殊之处
    • 以系统调用作为特殊的中断,结合中断上下文切换和进程上下文切换分析Linux系统的一般执行过程

    一、fork系统调用分析

    fork()系统调用用于复制父进程从而创建子进程。fork()的特殊之处在于:一次调用,两次返回。如果fork()执行出现了问题则会返回一个负数。如果fork()系统调用正常执行,会给父进程返回子进程的pid,给子进程返回0。实际上出fork、vfork和clone这3个系统调⽤,以及do_fork和kernel_thread内核函数都可以实现相同的功能,他们最终都是通过调用_do_fork()函数来实现创建子进程的功能。下面我们来分析_do_fork()函数。

    _do_fork()函数主要关注两件事情:

    1. 通过copy_process()函数复制进程描述符
    2. 通过wake_up_new_task()函数将已经准备好进程上下文的子进程加入就绪队列

    copy_process()函数主要两件事情:

    1. 通过dup_task_struct()函数复制进程描述符,具体做法是将父进程的结构体task_struct变量的值复制给子进程
    2. 通过copy_thread()函数初始化⼦进程内核栈

    copy_thread()函数
    该函数对task_struct结构体中的thread_struct结构体进行了初始化。

    1. 将子进程的ax值设置为0,即fork()系统调用最终给子进程的返回值
    2. 设置子进程的sp值,即子进程的内核堆栈
    3. 将子进程的ip值设置为ret_from_fork,即子进程返回后开始执行的地方

    最后看一下fork系统调用的总体过程

    二、execve系统调用分析

    execve()用来加载可执行程序,linux系统提供了execl、execlp、execle、execv、execvp和execve等6个库函数,这些库函数统称为exec函数,exec函数都是通过execve系统调⽤进⼊内核,对应的系统调⽤内核处理函数为__x64_sys_execve,最终通过调⽤do_execve来具体执⾏加载可执⾏⽂件的⼯作。

    execve()系统调用的执行过程如下:

    1. 陷入内核
    2. 校验文件并加载新的可执行文件
    3. 新加载的文件根据ELF⽂件映射到进程的地址空间,覆盖原来的进程
    4. 设置EIP的值。如果可执行程序是静态链接的程序,或不需要动态链接库,则EIP设置为新的可执行文件的main函数地址,如果可执行程序需要其他的动态链接库,则入口地址是加载器ld的入口地址
    5. 返回用户态,程序从新的EIP开始继续执行

    三、Linux系统一般执行过程分析

    1. 每个进程有一个用户态堆栈和一个内核态堆栈,都属于进程上下文
    2. 进程在执行过程中有可能被中断,此时进程进入内核态并切换到中断上下文。系统调用属于异常,也是一种特殊的中断(软中断)
    3. 中断上下文并不是一个进程,只是占用了被中断进程的一部分内核堆栈空间
    4. 在中断结束,准备返回用户态的时候,内核会检查是否需要进行进程调度
    5. 如果不需要进行进程调度,那么直接返回用户态,如果需要进行进程调度,就需要调用schedule()函数切换进程上下文,然后返回新进程的用户态
  • 相关阅读:
    JS操作JSON总结
    jQuery对select操作
    MS SQL GUID
    QT延时方法
    MySQL 实践
    MySQL 入门教程
    asp.net获取URL和IP地址
    C#-foreach与yield
    C#—序列化(Serialize)和反序列化(NonSerialize)
    Newtonsoft.Json序列化和反序列
  • 原文地址:https://www.cnblogs.com/-zyq/p/13127356.html
Copyright © 2020-2023  润新知