• Linux内核分析第八周——进程的切换和系统的一般执行过程


    Linux内核分析第八周——进程的切换和系统的一般执行过程

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

    一、知识要点:

    schedule目的:在运行队列中找到一个进程,把cpu分配给他。

    schedule()函数选择一个新的进程来运行,并调用context_switch进行上下文的切换,这个宏调用switch_to来进行关键上下文切换。

    next = pick_next_task(rq, prev);//进程调度算法都封装这个函数内部
    context_switch(rq, prev, next);//进程上下文切换
    

    switch_to利用了prev和next两个参数:prev指向当前进程,next指向被调度的进程

    打开schedule代码分析:

    打开switch_to代码,对其进行分析:

    ​​ #defineswitch_to(prev, next, last)

    32do {
    40unsignedlongebx, ecx, edx, esi, edi;
    42asmvolatile("pushfl
    	" //保存当前进程的flag
    43"pushl % ebp
    	"         //把当前进程的堆栈基址压栈
    44"movl %%esp,%[prev_sp]
    	"   //把当前栈顶保存起来,保存到thread.sp [prev_sp]是使用标号,类似以前的%1,这里使用字符串标记参数
    45"movl %[next_sp],%%esp
    	"   //把下一个进程的栈顶放到esp寄存器里面,从这开始,所有的压栈都是在next进程里面了
    46"movl $1f,%[prev_ip]
    	"         //保存当前进程的eip,在恢复prev当前进程的时候可以从这里开始恢复
    47"pushl %[next_ip]
    	"              //把next进程起点也就是IP的位置压栈,这里是压到next进程的堆栈,next进程的栈顶就是他的起点。
    48__switch_canary
    49"jmp __switch_to
    "                //不同于call调用函数
    用寄存器传递参数
    50"1:	"                                      //从这才开始执行next进程第一条语句,以上的语句是很模糊的,属于哪个进程还不好说,但从45行之后就已经在next进程中压栈了。
    51"popl % ebp
    	"
    52"popfl
    "
    55     : [prev_sp] "=m" (prev->thread.sp),//当前进程,因为中断内部在内核态,sp内核堆栈顶。                                                                             56       [prev_ip] "=m" (prev->thread.ip),//thread.ip当前进程的eip
    57"=a" (last),
    59
    60"=b" (ebx), "=c" (ecx), "=d" (edx),
    61"=S" (esi), "=D" (edi)    
    63__switch_canary_oparam
    66     : [next_sp]  "m" (next->thread.sp),//input:next->thread.sp下一个进程内核堆栈栈顶
    67       [next_ip]  "m" (next->thread.ip),//next->thread.ip下一个进程执行的起点
    70       [prev]     "a" (prev),
    71       [next]     "d" (next)
    73__switch_canary_iparam
    75     :
    76"memory");
    77} while (0)
    

    二、总结:

    ​Linux系统的一般执行过程分析总结:

    最一般的情况:正在运行的用户态进程X切换到运行用户态进程Y的过程

    • 正在运行的用户态进程X
    • 发生中断——save cs:eip/esp/eflags(current) to kernel stack(用户态进程x的内核堆栈),then load cs:eip(entry of a specific ISR当前对应的中断服务历程的起点) and ss:esp(point to kernel stack)(当前进程内核堆栈的信息)
    • SAVE_ALL //保存现场
    • 中断处理过程中或中断返回前调用了schedule(),其中的switch_to做了关键的进程上下文切换
    • 标号1之后开始运行用户态进程Y(这里Y曾经通过以上步骤被切换出去过因此可以从标号1继续执行)
    • restore_all //恢复现场
    • iret pop cs:eip/ss:esp/eflags from kernel stack(Y进程在发生中断时保存到堆栈里面的)
    • 继续运行用户态进程Y
  • 相关阅读:
    .net反编译原理
    科学使用Log4View2
    头条一面竟然问我Maven?
    SpringCloud Netflix(一) :微服务架构
    Linux环境安装Docker
    Quartz定时任务
    Jedis连接外部Redis
    宝塔phpmyadmin打不开的可能问题及解决方法
    文件上传 Window & Linux
    SpringBoot登录判断
  • 原文地址:https://www.cnblogs.com/lxq20135309/p/5401832.html
Copyright © 2020-2023  润新知